Browse Source

fix: WaveSpeed video generation saves as .mp4 instead of .bin

Derive provider capabilities from mediaType instead of hardcoding
text-to-image, so isVideoModel is correct for video generations.
Treat application/octet-stream as unhelpful content-type and fall back
to video/mp4 or image/png based on model type. Add safety net in
save-generation to override .bin extension when media type is known.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 5 months ago
parent
commit
ebc98018ff
  1. 14
      src/app/api/generate/route.ts
  2. 10
      src/app/api/save-generation/route.ts

14
src/app/api/generate/route.ts

@ -2199,9 +2199,11 @@ async function generateWithWaveSpeed(
const outputArrayBuffer = await outputResponse.arrayBuffer(); const outputArrayBuffer = await outputResponse.arrayBuffer();
const outputSizeMB = outputArrayBuffer.byteLength / (1024 * 1024); const outputSizeMB = outputArrayBuffer.byteLength / (1024 * 1024);
const rawContentType = outputResponse.headers.get("content-type");
const contentType = const contentType =
outputResponse.headers.get("content-type") || (rawContentType && rawContentType !== "application/octet-stream")
(isVideoModel ? "video/mp4" : "image/png"); ? rawContentType
: (isVideoModel ? "video/mp4" : "image/png");
console.log(`[API:${requestId}] Output: ${contentType}, ${outputSizeMB.toFixed(2)}MB`); console.log(`[API:${requestId}] Output: ${contentType}, ${outputSizeMB.toFixed(2)}MB`);
@ -2323,7 +2325,7 @@ export async function POST(request: NextRequest) {
id: selectedModel!.modelId, id: selectedModel!.modelId,
name: selectedModel!.displayName, name: selectedModel!.displayName,
provider: "replicate", provider: "replicate",
capabilities: ["text-to-image"], capabilities: mediaType === "video" ? ["text-to-video"] : ["text-to-image"],
description: null, description: null,
}, },
prompt: prompt || "", prompt: prompt || "",
@ -2411,7 +2413,7 @@ export async function POST(request: NextRequest) {
id: selectedModel!.modelId, id: selectedModel!.modelId,
name: selectedModel!.displayName, name: selectedModel!.displayName,
provider: "fal", provider: "fal",
capabilities: ["text-to-image"], capabilities: mediaType === "video" ? ["text-to-video"] : ["text-to-image"],
description: null, description: null,
}, },
prompt: prompt || "", prompt: prompt || "",
@ -2502,7 +2504,7 @@ export async function POST(request: NextRequest) {
id: selectedModel!.modelId, id: selectedModel!.modelId,
name: selectedModel!.displayName, name: selectedModel!.displayName,
provider: "kie", provider: "kie",
capabilities: ["text-to-image"], capabilities: mediaType === "video" ? ["text-to-video"] : ["text-to-image"],
description: null, description: null,
}, },
prompt: prompt || "", prompt: prompt || "",
@ -2593,7 +2595,7 @@ export async function POST(request: NextRequest) {
id: selectedModel!.modelId, id: selectedModel!.modelId,
name: selectedModel!.displayName, name: selectedModel!.displayName,
provider: "wavespeed", provider: "wavespeed",
capabilities: ["text-to-image"], capabilities: mediaType === "video" ? ["text-to-video"] : ["text-to-image"],
description: null, description: null,
}, },
prompt: prompt || "", prompt: prompt || "",

10
src/app/api/save-generation/route.ts

@ -165,7 +165,10 @@ export async function POST(request: NextRequest) {
} }
} }
const contentType = response.headers.get("content-type") || (isVideo ? "video/mp4" : "image/png"); const rawSaveContentType = response.headers.get("content-type");
const contentType = (rawSaveContentType && rawSaveContentType !== "application/octet-stream")
? rawSaveContentType
: (isVideo ? "video/mp4" : "image/png");
extension = getExtensionFromMime(contentType); extension = getExtensionFromMime(contentType);
const arrayBuffer = await response.arrayBuffer(); const arrayBuffer = await response.arrayBuffer();
@ -198,6 +201,11 @@ export async function POST(request: NextRequest) {
} }
} }
// Safety net: if extension resolved to "bin" but we know the media type, use correct extension
if (extension === "bin") {
extension = isVideo ? "mp4" : "png";
}
// Compute content hash for deduplication // Compute content hash for deduplication
const contentHash = computeContentHash(buffer); const contentHash = computeContentHash(buffer);

Loading…
Cancel
Save