"use client" import { ClapProject, ClapSegment } from "@aitube/clap" import { PromiseResponseType, waitPromisesUntil } from "@/lib/utils/waitPromisesUntil" import { VideoLoop } from "./video-loop" import { generateVideo } from "./generateVideo" import { useStore } from "@/app/state/useStore" export async function resolve(segment: ClapSegment, clap: ClapProject): Promise { 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> = [] 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 ( ) }