diff --git a/src/app/api/generate/providers/__tests__/newapiwg.test.ts b/src/app/api/generate/providers/__tests__/newapiwg.test.ts index c50148de..f82eb650 100644 --- a/src/app/api/generate/providers/__tests__/newapiwg.test.ts +++ b/src/app/api/generate/providers/__tests__/newapiwg.test.ts @@ -509,6 +509,31 @@ describe("NewApiWG generation payloads", () => { expect(capturedBody!.image).toBeUndefined(); }); + it("keeps Vidu reference videos on the schema field expected by the gateway", async () => { + const result = await generateWithNewApiWG("test-key", "https://newapi.example/v1", makeInput({ + model: { + id: "viduq3-turbo", + name: "viduq3-turbo", + description: null, + provider: "newapiwg", + capabilities: ["text-to-video", "image-to-video"], + }, + dynamicInputs: { + reference_video_urls: ["data:video/mp4;base64,reference"], + video_urls: "data:video/mp4;base64,connected", + }, + })); + + expect(result.success).toBe(true); + expect(capturedBody).not.toBeNull(); + expect(capturedBody!.reference_video_urls).toEqual([ + "data:video/mp4;base64,reference", + "data:video/mp4;base64,connected", + ]); + expect(capturedBody!.videos).toBeUndefined(); + expect(capturedBody!.video_urls).toBeUndefined(); + }); + it("resolves temporary local media inputs before NewApiWG video generation", async () => { const imageId = storeImage("data:image/png;base64,dmlkZW8tcmVm"); try { diff --git a/src/app/api/generate/providers/newapiwg.ts b/src/app/api/generate/providers/newapiwg.ts index 1d87cb92..125e60e8 100644 --- a/src/app/api/generate/providers/newapiwg.ts +++ b/src/app/api/generate/providers/newapiwg.ts @@ -848,6 +848,22 @@ function uniqueStrings(values: string[]): string[] { return [...new Set(values)]; } +function isViduVideoModel(modelId: string): boolean { + return /vidu/i.test(modelId); +} + +function appendDynamicInputArray( + inputs: Record, + key: string, + values: string[] +): void { + const merged = uniqueStrings([ + ...asStringArray(inputs[key]), + ...values, + ]); + if (merged.length > 0) inputs[key] = merged; +} + function normalizeNewApiWGVideoInputs( input: GenerationInput, dynamicInputs: Record @@ -859,12 +875,18 @@ function normalizeNewApiWGVideoInputs( const images = [...(input.images || [])]; const videos: string[] = []; const audios: string[] = []; + const shouldUseViduReferenceVideoField = isViduVideoModel(input.model.id); for (const [key, value] of Object.entries(dynamicInputs)) { if (NEWAPIWG_VIDEO_IMAGE_INPUTS.has(key)) { images.push(...asStringArray(value)); } else if (NEWAPIWG_VIDEO_INPUTS.has(key)) { - videos.push(...asStringArray(value)); + const videoValues = asStringArray(value); + if (shouldUseViduReferenceVideoField) { + appendDynamicInputArray(normalizedDynamicInputs, "reference_video_urls", videoValues); + } else { + videos.push(...videoValues); + } } else if (NEWAPIWG_VIDEO_AUDIO_INPUTS.has(key)) { audios.push(...asStringArray(value)); } else { diff --git a/src/components/__tests__/PromptNode.test.tsx b/src/components/__tests__/PromptNode.test.tsx index 6a5a1ea8..9cca4c2b 100644 --- a/src/components/__tests__/PromptNode.test.tsx +++ b/src/components/__tests__/PromptNode.test.tsx @@ -85,6 +85,29 @@ describe("PromptNode", () => { expect(screen.getByText("Initial prompt text")).toBeInTheDocument(); }); + it("should keep long prompt previews bounded inside the node", () => { + const longPrompt = "水电费".repeat(120); + const propsWithPrompt = { + ...defaultProps, + data: { prompt: longPrompt }, + }; + + render( + + + + ); + + const preview = screen.getByRole("button", { name: "Double-click to edit" }); + expect(preview).toHaveClass("overflow-hidden"); + expect(preview).toHaveClass("items-start"); + + const text = screen.getByText(longPrompt); + expect(text).toHaveClass("max-h-full"); + expect(text).toHaveClass("overflow-y-auto"); + expect(text).toHaveClass("break-words"); + }); + it("should call updateNodeData when typing in textarea and blurring", () => { render( diff --git a/src/components/nodes/PromptNode.tsx b/src/components/nodes/PromptNode.tsx index f07fef72..feadaaa9 100644 --- a/src/components/nodes/PromptNode.tsx +++ b/src/components/nodes/PromptNode.tsx @@ -235,14 +235,14 @@ export function PromptNode({ id, data, selected }: NodeProps) { setIsEditing(true); } }} - className={`nodrag nopan nowheel flex h-full w-full cursor-text rounded-lg bg-neutral-800 p-8 outline-none ${ + className={`nodrag nopan nowheel flex h-full w-full cursor-text rounded-lg bg-neutral-800 p-8 text-center outline-none ${ promptText - ? "items-start justify-start overflow-auto text-left select-text" - : "items-center justify-center text-center" + ? "items-start justify-start overflow-hidden" + : "items-center justify-center" }`} > {promptText ? ( -
+
{localPrompt}
) : (