Spaces:
Build error
Build error
"use client" | |
import { ClapProject, ClapSegment } from "@aitube/clap" | |
import { PromiseResponseType, waitPromisesUntil } from "@/lib/utils/waitPromisesUntil" | |
import { generateVideo } from "./generateVideo" | |
import { BasicVideo } from "./basic-video" | |
import { useStore } from "@/app/state/useStore" | |
export async function resolve(segment: ClapSegment, clap: ClapProject): Promise<JSX.Element> { | |
const { prompt } = segment | |
// this is were the magic happen, and we create our buffer of N videos | |
// we need to adopt a conservative approach, ideally no more than 3 videos in parallel per user | |
const numberOfParallelRequests = 3 | |
// the playback speed is the second trick: | |
// it allows us to get more "value" per video (a run time of 2 sec instead of 1) | |
// at the expense of a more sluggish appearance (10 fps -> 5 fps, if you pick a speed of 0.5) | |
const playbackSpeed = 0.5 | |
// running multiple requests in parallel increase the risk that a server is down | |
// we also cannot afford to wait for all videos for too long as this increase latency, | |
// so we should keep a tight execution window | |
// with current resolution and step settings, | |
// we achieve 3463.125 rendering time on a A10 Large | |
const maxRenderingTimeForAllVideos = 5000 | |
// this is how long we wait after we received our first video | |
// this represents the variability between rendering time | |
// | |
// this parameters helps us "squeeze" the timeout, | |
// if the hardware settings changed for instance | |
// this is a way to say "how, this is faster than I expected, other videos should be fast too then" | |
// | |
// I've noticed it is between 0.5s and 1s with current settings | |
// so let's a a slightly larger value | |
const maxWaitTimeAfterFirstVideo = 1500 | |
let playlist: string[] = [] | |
try { | |
// console.log(`resolveVideo: generating video for: ${prompt}`) | |
const promises: Array<Promise<string>> = [] | |
for (let i = 0; i < numberOfParallelRequests; i++) { | |
// TODO use the Clap segments instead to bufferize the next scenes, | |
// otherwise we just clone the current segment, which is not very interesting | |
promises.push(generateVideo({ | |
prompt, | |
width: clap.meta.width, | |
height: clap.meta.height, | |
token: useStore.getState().jwtToken, | |
mode: "object-uri" // it's better for videos withing Chrome, apparently | |
})) | |
} | |
const results = await waitPromisesUntil(promises, maxWaitTimeAfterFirstVideo, maxRenderingTimeForAllVideos) | |
playlist = results | |
.filter(result => result?.status === PromiseResponseType.Resolved && typeof result?.value === "string") | |
.map(result => result?.value || "") | |
// console.log(`resolveVideo: generated ${assetUrl}`) | |
} catch (err) { | |
console.error(`resolveVideo failed: ${err}`) | |
return <></> | |
} | |
// note: the latent-video class is not used for styling, but to grab the component | |
// from JS when we need to segment etc | |
return ( | |
<BasicVideo | |
className="latent-video object-cover h-full" | |
playbackSpeed={playbackSpeed} | |
src={playlist[0]} | |
playsInline | |
muted | |
autoPlay | |
loop | |
/> | |
) | |
} |