import { promises as fs } from "fs" import express from "express" import { generateSeed } from "./services/generateSeed.mts" import { Job, ShotQuery } from "./types.mts" import { generateShot } from "./services/generateShot.mts" const app = express() const port = 7860 app.use(express.json()) const queue: Job[] = [] app.post("/shot", async (req, res) => { const query = req.body as ShotQuery const token = `${query.token || ""}` if (token !== process.env.VS_SECRET_ACCESS_TOKEN) { console.log("couldn't find access token in the query") res.write(JSON.stringify({ error: true, message: "access denied" })) res.end() return } const shotPrompt = `${query.shotPrompt || ""}` if (shotPrompt.length < 5) { res.write(JSON.stringify({ error: true, message: "prompt too short (must be at least 5 in length)" })) res.end() return } // optional video URL // const inputVideo = `${req.query.inputVideo || ""}` // optional background audio prompt const backgroundAudioPrompt = `${query.backgroundAudioPrompt || ""}` // optional foreground audio prompt const foregroundAudioPrompt = `${query.foregroundAudioPrompt || ""}` // optional seed const defaultSeed = generateSeed() const seedStr = Number(`${query.seed || defaultSeed}`) const maybeSeed = Number(seedStr) const seed = isNaN(maybeSeed) || ! isFinite(maybeSeed) ? defaultSeed : maybeSeed // in production we want those ON by default const upscale = `${query.upscale || "true"}` === "true" const interpolate = `${query.upscale || "true"}` === "true" const noise = `${query.noise || "true"}` === "true" const defaultDuration = 3 const maxDuration = 5 const durationStr = Number(`${query.duration || defaultDuration}`) const maybeDuration = Number(durationStr) const duration = Math.min(maxDuration, Math.max(1, isNaN(maybeDuration) || !isFinite(maybeDuration) ? defaultDuration : maybeDuration)) const defaultSteps = 35 const stepsStr = Number(`${query.steps || defaultSteps}`) const maybeSteps = Number(stepsStr) const nbSteps = Math.min(60, Math.max(1, isNaN(maybeSteps) || !isFinite(maybeSteps) ? defaultSteps : maybeSteps)) // const frames per second const defaultFps = 24 const fpsStr = Number(`${query.fps || defaultFps}`) const maybeFps = Number(fpsStr) const nbFrames = Math.min(60, Math.max(8, isNaN(maybeFps) || !isFinite(maybeFps) ? defaultFps : maybeFps)) const defaultResolution = 576 const resolutionStr = Number(`${query.resolution || defaultResolution}`) const maybeResolution = Number(resolutionStr) const resolution = Math.min(1080, Math.max(256, isNaN(maybeResolution) || !isFinite(maybeResolution) ? defaultResolution : maybeResolution)) const actorPrompt = `${query.actorPrompt || ""}` const actorVoicePrompt = `${query.actorVoicePrompt || ""}` const actorDialoguePrompt = `${query.actorDialoguePrompt || ""}` const { filePath } = await generateShot({ seed, actorPrompt, shotPrompt, backgroundAudioPrompt, foregroundAudioPrompt, actorDialoguePrompt, actorVoicePrompt, duration, nbFrames, resolution, nbSteps, upscale, interpolate, noise, }) console.log(`generated video in ${filePath}`) console.log("returning result to user..") const buffer = await fs.readFile(filePath) res.setHeader("Content-Type", "media/mp4") res.setHeader("Content-Length", buffer.length) res.end(buffer) }) app.listen(port, () => { console.log(`Open http://localhost:${port}`) })