diff --git a/packages/components/src/api/jobs/JobsBySession.ts b/packages/components/src/api/jobs/JobsBySession.ts new file mode 100644 index 0000000000..9d8ef49369 --- /dev/null +++ b/packages/components/src/api/jobs/JobsBySession.ts @@ -0,0 +1,20 @@ +import MakeRequest from "../MakeRequest"; +import { InferenceJob } from "@storyteller/components/src/jobs/InferenceJob"; +import { ModelInferenceJobStatus } from "@storyteller/components/src/api/model_inference/GetModelInferenceJobStatus"; + +export interface JobsBySessionRequest {} + +export interface JobsBySessionResponse { + success: boolean; + jobs?: ModelInferenceJobStatus[]; +} + +export const JobsBySession = MakeRequest< + string, + JobsBySessionRequest, + JobsBySessionResponse, + {} +>({ + method: "GET", + routingFunction: (jobToken: string) => `/v1/jobs/session`, +}); diff --git a/packages/fakeyou.com/src/hooks/useInferenceJobsPolling.tsx b/packages/fakeyou.com/src/hooks/useInferenceJobsPolling.tsx new file mode 100644 index 0000000000..6d5dba58d0 --- /dev/null +++ b/packages/fakeyou.com/src/hooks/useInferenceJobsPolling.tsx @@ -0,0 +1,112 @@ +import { useState } from "react"; +import { + JobsBySession, + JobsBySessionResponse, +} from "@storyteller/components/src/api/jobs/JobsBySession"; +import { + FrontendInferenceJobType, + InferenceJob, +} from "@storyteller/components/src/jobs/InferenceJob"; +import { jobStateCanChange } from "@storyteller/components/src/jobs/JobStates"; +import { useInterval } from "hooks"; + +const JobCategoryToType = (jobCategory: string) => { + console.log("⚙️", jobCategory); + switch (jobCategory) { + case "lipsync_animation": + return FrontendInferenceJobType.FaceAnimation; + case "text_to_speech": + return FrontendInferenceJobType.TextToSpeech; + case "voice_conversion": + return FrontendInferenceJobType.VoiceConversion; + case "image_generation": + return FrontendInferenceJobType.ImageGeneration; + case "mocap": + return FrontendInferenceJobType.VideoMotionCapture; + case "workflow": + return FrontendInferenceJobType.VideoWorkflow; + case "format_conversion": + return FrontendInferenceJobType.ConvertFbxtoGltf; + case "convert_bvh_to_workflow": + return FrontendInferenceJobType.EngineComposition; + default: + return FrontendInferenceJobType.TextToSpeech; + } +}; + +export interface JobsPollingProps { + debug?: boolean; +} + +const newJobCategoryMap = (): Map => { + let inferenceJobsByCategory = new Map(); + Object.keys(FrontendInferenceJobType) + .filter(key => !isNaN(Number(key))) + .forEach(key => inferenceJobsByCategory.set(Number(key), [])); + + return inferenceJobsByCategory; +}; + +export default function useInferenceJobsPolling({ debug }: JobsPollingProps) { + const [inferenceJobs, inferenceJobsSet] = useState(); + const [byCategory, byCategorySet] = useState(newJobCategoryMap()); + // const [initialized, initializedSet] = useState(false); + const [keepAlive, keepAliveSet] = useState(true); + + const interval = 2500; + + if (debug) console.log("☠️ keepAlive", keepAlive, inferenceJobs, byCategory); + + const onTick = ({ + eventProps: { inferenceJobs: currentQueue }, + }: { + eventProps: { inferenceJobs: JobsBySessionResponse }; + }) => { + JobsBySession("", {}).then((res: JobsBySessionResponse) => { + if (res && res.jobs) { + let newMap = new Map(newJobCategoryMap()); + const updatedJobs = res.jobs.map((job, i) => { + const frontendJobType = JobCategoryToType( + job.request.inference_category + ); + + const remappedJob = InferenceJob.fromResponse(job, frontendJobType); + + newMap.set(frontendJobType, [ + ...(newMap.get(frontendJobType) || []), + remappedJob, + ]); + + return remappedJob; + }); + + inferenceJobsSet(updatedJobs); + byCategorySet(newMap); + if (!updatedJobs.some(job => jobStateCanChange(job.jobState))) { + keepAliveSet(false); + } + } + }); + }; + + const enqueueInferenceJob = ( + jobToken: string, + frontendJobType: FrontendInferenceJobType + ) => { + keepAliveSet(true); + }; + + useInterval({ + eventProps: { inferenceJobs }, + interval, + onTick, + locked: !keepAlive, + }); + + return { + byCategory, + inferenceJobsByCategory: byCategory, + enqueueInferenceJob, + inferenceJobs, + }; +} diff --git a/packages/fakeyou.com/src/v2/view/pages/media/VideoMediaPage.tsx b/packages/fakeyou.com/src/v2/view/pages/media/VideoMediaPage.tsx index 422d5bc067..85bf87b88a 100644 --- a/packages/fakeyou.com/src/v2/view/pages/media/VideoMediaPage.tsx +++ b/packages/fakeyou.com/src/v2/view/pages/media/VideoMediaPage.tsx @@ -26,6 +26,7 @@ import { faArrowRightArrowLeft, faCheck, faPen, + faStars, faTrash, faX, } from "@fortawesome/pro-solid-svg-icons"; @@ -59,6 +60,8 @@ export default function DevMediaPage({ basicTransition({ ...events }) ); + console.log("😎", mediaFile); + const saveTitle = () => { editingTitleSet(EditingTitleState.saving); RenameMedia(urlToken, { @@ -215,9 +218,22 @@ export default function DevMediaPage({ icon: faArrowRightArrowLeft, label: "Style Transfer", to: `/style-video/${mediaFile?.token || ""}`, + variant: "secondary", }} /> )} + {canAccessStudio() && + mediaFile?.maybe_scene_source_media_file_token && ( +