VideoChain-API / src /index.mts
jbilcke-hf's picture
jbilcke-hf HF Staff
work in progress to create the video service
a65e95e
raw
history blame
3.54 kB
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}`) })