feat: add Seedance 2 video generation via PiAPI provider#186
feat: add Seedance 2 video generation via PiAPI provider#186SecurityQQ merged 2 commits intomainfrom
Conversation
Add PiAPI as a new provider for Seedance 2 video generation (ByteDance). Three integration layers: - Classic provider (src/providers/piapi.ts) extending BaseProvider - Model definitions (src/definitions/models/seedance.ts) for both variants - AI SDK v3 provider (src/ai-sdk/providers/piapi.ts) with VideoModelV3 Models: - seedance-2-preview: high quality, auto watermark removal - seedance-2-fast-preview: fast, no watermark removal Supports all Seedance modes: T2V, I2V, video edit, extend, watermark removal.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 Walkthroughwalkthroughadds a piapi-backed seedance video provider, new seedance model defs, and provider registration; implements async task submission, polling, optional watermark removal, and video download across ai-sdk and providers layers. changes
sequence diagramssequenceDiagram
participant client as Client
participant model as VideoModel
participant provider as PiAPIProvider
participant piapi as PiAPI
participant seedance as Seedance
client->>model: request generateVideo(prompt, options)
model->>provider: submit task(payload)
provider->>piapi: POST /api/v1/task {model: "seedance", input: ...}
piapi-->>provider: {task_id, status: pending}
loop poll
provider->>piapi: GET /api/v1/task/{task_id}
alt processing
piapi-->>provider: {status: processing}
else completed
piapi-->>provider: {status: completed, output: {video: {url}}}
else failed
piapi-->>provider: {status: failed, error}
end
end
alt preview model
provider->>piapi: POST remove-watermark task
piapi->>seedance: process removal
seedance-->>piapi: cleaned video url
piapi-->>provider: completed output
end
provider->>piapi: GET video bytes (download)
piapi-->>provider: binary bytes
provider-->>model: return video bytes + warnings
model-->>client: deliver generated video
estimated code review effort🎯 4 (complex) | ⏱️ ~60 minutes poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
src/ai-sdk/providers/piapi.ts (3)
310-310: consider validating modelIdunlike the together provider which validates against known models, this accepts any string and only fails at the api level. could add validation against known seedance models.
♻️ potential validation
+const SEEDANCE_MODELS = ["seedance-2-preview", "seedance-2-fast-preview"]; + export function createPiAPI( settings: PiAPIProviderSettings = {}, ): PiAPIProvider { const { apiKey, baseUrl } = resolveConfig(settings); return { specificationVersion: "v3", - videoModel: (modelId) => new PiAPIVideoModel(modelId, baseUrl, apiKey), + videoModel: (modelId) => { + if (!SEEDANCE_MODELS.includes(modelId)) { + throw new NoSuchModelError({ + modelId, + modelType: "videoModel", + message: `Unknown video model: ${modelId}. Available: ${SEEDANCE_MODELS.join(", ")}`, + }); + } + return new PiAPIVideoModel(modelId, baseUrl, apiKey); + },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/ai-sdk/providers/piapi.ts` at line 310, The videoModel factory currently constructs new PiAPIVideoModel(modelId, baseUrl, apiKey) without checking modelId; add validation of modelId against the known Seedance model whitelist before instantiating (e.g., inside the videoModel factory or within the PiAPIVideoModel constructor). If modelId is not in the allowed list, return or throw a clear validation error (rather than letting the API call fail) and include the invalid modelId in the message; keep using baseUrl and apiKey when creating the PiAPIVideoModel for valid IDs.
323-324: minor naming nit
piapi_provideruses snake_case but guidelines prefer camelcase. the export aliaspiapiis fine tho.🧹 if you feel like it
-const piapi_provider = createPiAPI(); -export { piapi_provider as piapi }; +const piapiProvider = createPiAPI(); +export { piapiProvider as piapi };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/ai-sdk/providers/piapi.ts` around lines 323 - 324, Rename the snake_case variable piapi_provider to camelCase piapiProvider where it's declared from createPiAPI(), and update any internal references to use piapiProvider; keep the export alias unchanged (export { piapiProvider as piapi }) so external imports remain the same and ensure createPiAPI() usage and any other occurrences are updated to the new identifier.
211-230: extension detection edge caseurls without extensions (like cdn urls with query params or signed urls) will default to image. might want to handle content-type detection or document this limitation.
// example edge case: // https://cdn.example.com/video/abc123?signature=xyz // -> no extension detected, treated as imagenot blocking since the fallback is reasonable, just something to be aware of.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/ai-sdk/providers/piapi.ts` around lines 211 - 230, The current extension-based media detection in the block handling options.files (the loop that pushes into videoUrls or imageUrls and emits warnings for inline files) misclassifies URLs that lack extensions (e.g., signed CDN URLs); update the logic to perform a lightweight HEAD (or fetch with method HEAD) to inspect the Content-Type when ext is missing or unrecognized and classify as video if Content-Type starts with "video/", otherwise image; keep the existing extension check first for performance, fall back to the HEAD request only when ext is absent, and ensure failures/timeouts fall back to the current image default and emit a warning via the same warnings array so callers are informed.src/providers/piapi.ts (1)
200-243: consider reusing submit()the fetch logic here duplicates what's in
submit(). could potentially callsubmit("remove-watermark", { task_type: "remove-watermark", video_url: videoUrl })and reuse that code path. not blocking tho, just a thought.♻️ potential refactor
async removeWatermark(videoUrl: string): Promise<string> { console.log("[piapi] submitting watermark removal..."); - const response = await fetch(`${PIAPI_BASE_URL}/api/v1/task`, { - method: "POST", - headers: { - "X-API-Key": this.apiKey, - "Content-Type": "application/json", - Accept: "application/json", - }, - body: JSON.stringify({ - model: "seedance", - task_type: "remove-watermark", - input: { video_url: videoUrl }, - }), - }); - - if (!response.ok) { - const errorText = await response.text(); - throw new Error( - `piapi watermark removal submit failed (${response.status}): ${errorText}`, - ); - } - - const data = (await response.json()) as PiAPIResponse; - const taskId = data.data?.task_id; - if (!taskId) { - throw new Error("no task_id in piapi watermark removal response"); - } + // note: would need to adjust submit() to accept raw input or add a new method + const taskId = await this.submitRaw({ + model: "seedance", + task_type: "remove-watermark", + input: { video_url: videoUrl }, + }); console.log(`[piapi] watermark removal task: ${taskId}`);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/providers/piapi.ts` around lines 200 - 243, The removeWatermark method duplicates HTTP submit logic; refactor it to call the existing submit helper instead of duplicating fetch code: replace the fetch/response parsing and extraction of task_id inside removeWatermark by invoking submit("remove-watermark", { video_url: videoUrl }) (or the appropriate submit signature) to obtain the task id, then pass that id into this.waitForCompletion and keep the existing result handling; update any call-sites in removeWatermark that expect taskId or response shape accordingly and remove the duplicated fetch block to centralize API request/response/error handling in submit().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/definitions/models/seedance.ts`:
- Line 11: Remove the unused import of aspectRatioSchema from the top of the
file: locate the import statement importing aspectRatioSchema and delete it,
keeping the local seedanceAspectRatioSchema that is actually used in this module
(check references to seedanceAspectRatioSchema, SeedanceModel, or related schema
definitions to confirm no other usage of aspectRatioSchema remains).
---
Nitpick comments:
In `@src/ai-sdk/providers/piapi.ts`:
- Line 310: The videoModel factory currently constructs new
PiAPIVideoModel(modelId, baseUrl, apiKey) without checking modelId; add
validation of modelId against the known Seedance model whitelist before
instantiating (e.g., inside the videoModel factory or within the PiAPIVideoModel
constructor). If modelId is not in the allowed list, return or throw a clear
validation error (rather than letting the API call fail) and include the invalid
modelId in the message; keep using baseUrl and apiKey when creating the
PiAPIVideoModel for valid IDs.
- Around line 323-324: Rename the snake_case variable piapi_provider to
camelCase piapiProvider where it's declared from createPiAPI(), and update any
internal references to use piapiProvider; keep the export alias unchanged
(export { piapiProvider as piapi }) so external imports remain the same and
ensure createPiAPI() usage and any other occurrences are updated to the new
identifier.
- Around line 211-230: The current extension-based media detection in the block
handling options.files (the loop that pushes into videoUrls or imageUrls and
emits warnings for inline files) misclassifies URLs that lack extensions (e.g.,
signed CDN URLs); update the logic to perform a lightweight HEAD (or fetch with
method HEAD) to inspect the Content-Type when ext is missing or unrecognized and
classify as video if Content-Type starts with "video/", otherwise image; keep
the existing extension check first for performance, fall back to the HEAD
request only when ext is absent, and ensure failures/timeouts fall back to the
current image default and emit a warning via the same warnings array so callers
are informed.
In `@src/providers/piapi.ts`:
- Around line 200-243: The removeWatermark method duplicates HTTP submit logic;
refactor it to call the existing submit helper instead of duplicating fetch
code: replace the fetch/response parsing and extraction of task_id inside
removeWatermark by invoking submit("remove-watermark", { video_url: videoUrl })
(or the appropriate submit signature) to obtain the task id, then pass that id
into this.waitForCompletion and keep the existing result handling; update any
call-sites in removeWatermark that expect taskId or response shape accordingly
and remove the duplicated fetch block to centralize API request/response/error
handling in submit().
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f793065b-67a9-4d7d-b717-bacf6143b1e5
📒 Files selected for processing (5)
src/ai-sdk/providers/piapi.tssrc/definitions/models/index.tssrc/definitions/models/seedance.tssrc/providers/index.tssrc/providers/piapi.ts
| */ | ||
|
|
||
| import { z } from "zod"; | ||
| import { aspectRatioSchema } from "../../core/schema/shared"; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# verify aspectRatioSchema is not used in this file
rg -n 'aspectRatioSchema' src/definitions/models/seedance.tsRepository: vargHQ/sdk
Length of output: 118
remove unused import
aspectRatioSchema is imported on line 11 but never used in the file—you're using a local seedanceAspectRatioSchema instead. safe to delete. meow 🐱
fix
-import { aspectRatioSchema } from "../../core/schema/shared";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { aspectRatioSchema } from "../../core/schema/shared"; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/definitions/models/seedance.ts` at line 11, Remove the unused import of
aspectRatioSchema from the top of the file: locate the import statement
importing aspectRatioSchema and delete it, keeping the local
seedanceAspectRatioSchema that is actually used in this module (check references
to seedanceAspectRatioSchema, SeedanceModel, or related schema definitions to
confirm no other usage of aspectRatioSchema remains).
Follow fal provider pattern: textToVideo, imageToVideo, editVideo, extendVideo, removeWatermark — each with typed args instead of leaking PiAPI's internal taskType concept.
Summary
Add PiAPI as a new provider for Seedance 2 video generation (ByteDance) across all three SDK integration layers.
Integration Layers
1. Classic Provider (
src/providers/piapi.ts)BaseProviderwithsubmit,getStatus,getResulttextToVideo()— text prompt to videoimageToVideo()— image(s) + prompt to videoeditVideo()— edit existing video based on promptextendVideo()— extend a previously generated videoremoveWatermark()— remove watermark from videoseedance-2-preview2. Model Definitions (
src/definitions/models/seedance.ts)seedance-2-preview— high quality, auto watermark removalseedance-2-fast-preview— fast, no watermark removal3. AI SDK v3 Provider (
src/ai-sdk/providers/piapi.ts)VideoModelV3implementationfiles[]toimage_urls/video_urlsby extensionparent_task_idviaproviderOptions.piapiseedance-2-previewSupported Modes
promptonlyprompt+image_urls(max 9,@imageNrefs)prompt+video_urlsprompt+video_urls+image_urlsparent_task_idseedance-2-previewUsage
Companion PR