diff --git a/CHANGELOG.md b/CHANGELOG.md index e4ec563a..d94d89eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +## [1.6.0] - 2026-04-21 + +### Added + +- **Seedance 2 I2V: richer media inputs** — The ByteDance Seedance 2.0 and 2.0 Fast image-to-video nodes now expose Last Frame, Reference Images (up to 9), Reference Videos (up to 3), and Reference Audio (up to 3) handles alongside First Frame. Handle descriptions document the First/Last Frame vs Reference Images mutual-exclusivity rule. + +### Fixed + +- **Seedance 2 I2V: reference-only runs no longer rejected** — When connecting images only to Reference Images, the request no longer duplicates them into `first_frame_url`, which Kie was rejecting as a mutually-exclusive combination. + ## [1.5.0] - 2026-04-20 ### Added diff --git a/package.json b/package.json index 9b0d43b7..04d97e52 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-banana", - "version": "1.5.0", + "version": "1.6.0", "private": true, "scripts": { "dev": "node server.js", diff --git a/src/app/api/generate/providers/kie.ts b/src/app/api/generate/providers/kie.ts index f85e13c0..87fe2191 100644 --- a/src/app/api/generate/providers/kie.ts +++ b/src/app/api/generate/providers/kie.ts @@ -624,9 +624,12 @@ export async function submitKieTask( } } - // Handle image inputs (fallback - only if dynamicInputs didn't already set the image key) + // Handle image inputs (fallback - only if dynamicInputs didn't already handle any image key). + // If the schema-driven dynamic inputs already placed images into specific fields + // (e.g. reference_image_urls), don't also populate the default key — some models + // treat these fields as mutually exclusive and reject the request. const imageKey = getKieImageInputKey(modelId); - if (input.images && input.images.length > 0 && !handledImageKeys.has(imageKey)) { + if (input.images && input.images.length > 0 && handledImageKeys.size === 0) { const imageUrls: string[] = []; for (const image of input.images) { if (image.startsWith("http")) { diff --git a/src/app/api/models/[modelId]/route.ts b/src/app/api/models/[modelId]/route.ts index c0fa0dd6..d4d7d83c 100644 --- a/src/app/api/models/[modelId]/route.ts +++ b/src/app/api/models/[modelId]/route.ts @@ -881,7 +881,11 @@ function getKieSchema(modelId: string): ExtractedSchema { ], inputs: [ { name: "prompt", type: "text", required: false, label: "Prompt" }, - { name: "first_frame_url", type: "image", required: true, label: "Image" }, + { name: "first_frame_url", type: "image", required: false, label: "First Frame", description: "Starting frame. Mutually exclusive with Reference Images." }, + { name: "last_frame_url", type: "image", required: false, label: "Last Frame", description: "Optional end frame — interpolates from First to Last. Mutually exclusive with Reference Images." }, + { name: "reference_image_urls", type: "image", required: false, isArray: true, label: "Reference Images", description: "Up to 9 reference images for style/subject guidance. Mutually exclusive with First/Last Frame." }, + { name: "reference_video_urls", type: "image", required: false, isArray: true, label: "Reference Videos", description: "Up to 3 reference videos (accepts video data URLs over the image handle)." }, + { name: "reference_audio_urls", type: "audio", required: false, isArray: true, label: "Reference Audio", description: "Up to 3 reference audio clips." }, ], }, "bytedance/seedance-2-fast/text-to-video": { @@ -906,7 +910,11 @@ function getKieSchema(modelId: string): ExtractedSchema { ], inputs: [ { name: "prompt", type: "text", required: false, label: "Prompt" }, - { name: "first_frame_url", type: "image", required: true, label: "Image" }, + { name: "first_frame_url", type: "image", required: false, label: "First Frame", description: "Starting frame. Mutually exclusive with Reference Images." }, + { name: "last_frame_url", type: "image", required: false, label: "Last Frame", description: "Optional end frame — interpolates from First to Last. Mutually exclusive with Reference Images." }, + { name: "reference_image_urls", type: "image", required: false, isArray: true, label: "Reference Images", description: "Up to 9 reference images for style/subject guidance. Mutually exclusive with First/Last Frame." }, + { name: "reference_video_urls", type: "image", required: false, isArray: true, label: "Reference Videos", description: "Up to 3 reference videos (accepts video data URLs over the image handle)." }, + { name: "reference_audio_urls", type: "audio", required: false, isArray: true, label: "Reference Audio", description: "Up to 3 reference audio clips." }, ], }, "grok-imagine/text-to-video": {