← GPT-AI-VIDEO
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 };
}