CODE · 2.2 KB
server/generation.js
Workspace snapshot · 09/04 14:52
import { findVideoProvider, providerSupportsDuration } from "../src/providers.js";
const allowedRatios = new Set(["9:16", "16:9"]);
export function validateGenerationInput(input = {}) {
const provider = findVideoProvider(input.provider);
const prompt = String(input.prompt || "").trim();
const aspectRatio = allowedRatios.has(input.aspectRatio) ? input.aspectRatio : "9:16";
const durationSeconds = Number(input.durationSeconds || 8);
const outputGcsUri = String(input.outputGcsUri || "").trim();
if (!prompt || prompt.length > 6000) throw new Error("prompt must contain 1-6000 characters");
if (!provider.executable || !provider.model) throw new Error(`provider ${provider.id} is not executable`);
if (!Number.isInteger(durationSeconds) || !providerSupportsDuration(provider, durationSeconds)) {
throw new Error(`durationSeconds is not supported by provider ${provider.id}`);
}
if (provider.engine === "vertex" && !outputGcsUri.startsWith("gs://")) {
throw new Error("outputGcsUri must be a gs:// URI for Vertex AI");
}
return {
provider,
prompt,
aspectRatio,
durationSeconds,
outputGcsUri,
estimatedCostYen: Math.ceil(provider.yenPerSecond * durationSeconds)
};
}
export function buildVertexRequest(input) {
const validated = validateGenerationInput(input);
return {
model: validated.provider.model,
prompt: validated.prompt,
config: {
aspectRatio: validated.aspectRatio,
durationSeconds: validated.durationSeconds,
outputGcsUri: validated.outputGcsUri,
numberOfVideos: 1
}
};
}
export async function runVertexGeneration(input, { client, onProgress = () => {} }) {
const request = buildVertexRequest(input);
let operation = await client.models.generateVideos(request);
onProgress({ state: "RUNNING", operationName: operation.name || null });
while (!operation.done) {
await new Promise((resolve) => setTimeout(resolve, 15000));
operation = await client.operations.get({ operation });
}
const video = operation.response?.generatedVideos?.[0]?.video;
if (!video?.uri && !video?.videoBytes) throw new Error("Vertex AI completed without a video output");
return { uri: video.uri || null, videoBytes: video.videoBytes || null, model: request.model };
}