jbilcke-hf's picture
jbilcke-hf HF staff
let's use @aitube/clap inside AiTube
0d218b1
raw
history blame
No virus
3.15 kB
"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
/>
)
}