From fa32ac5edc8d5313a5d9849a769ce18af4fe62f8 Mon Sep 17 00:00:00 2001 From: dev Date: Thu, 18 Jan 2024 18:22:10 -0500 Subject: [PATCH] better UI and flow for uploading video and triggering generate MoCap --- packages/components/src/api/ApiConfig.ts | 5 + .../video_mocap/EnqueueVideoMotionCapture.ts | 42 ++++++ .../components/src/api/video_mocap/index.ts | 7 + packages/components/src/jobs/InferenceJob.ts | 1 + .../fakeyou.com/src/v2/view/PageContainer.tsx | 8 +- .../v2/view/pages/video_mocap/VideoMocap.tsx | 88 ++++++++----- .../components/pageInferenceStatuses.tsx | 47 +++++++ .../components/pageVideoProvision.tsx | 39 ++++++ .../components/tabContentLibrary.tsx | 3 +- .../components/tabContentUpload.tsx | 124 +++++++++++++----- 10 files changed, 296 insertions(+), 68 deletions(-) create mode 100644 packages/components/src/api/video_mocap/EnqueueVideoMotionCapture.ts create mode 100644 packages/components/src/api/video_mocap/index.ts create mode 100644 packages/fakeyou.com/src/v2/view/pages/video_mocap/components/pageInferenceStatuses.tsx create mode 100644 packages/fakeyou.com/src/v2/view/pages/video_mocap/components/pageVideoProvision.tsx diff --git a/packages/components/src/api/ApiConfig.ts b/packages/components/src/api/ApiConfig.ts index 7d9b4e8135..6d915810d8 100644 --- a/packages/components/src/api/ApiConfig.ts +++ b/packages/components/src/api/ApiConfig.ts @@ -471,6 +471,11 @@ class ApiConfig { return `${this.getApiOrigin()}/v1/animation/face_animation/create`; } + // =============== Motion Capture / mocap =============== + enqueueVideoMotionCapture(): string{ + return `${this.getApiOrigin()}/v1/mocap/mocapnet/create` + } + // =============== Generic Model Downloads =============== enqueueRemoteDownloadJob(): string { diff --git a/packages/components/src/api/video_mocap/EnqueueVideoMotionCapture.ts b/packages/components/src/api/video_mocap/EnqueueVideoMotionCapture.ts new file mode 100644 index 0000000000..5652109927 --- /dev/null +++ b/packages/components/src/api/video_mocap/EnqueueVideoMotionCapture.ts @@ -0,0 +1,42 @@ +import { ApiConfig } from "@storyteller/components"; + +export interface EnqueueVideoMotionCaptureRequest { + uuid_idempotency_token: string, + video_source: string, +} + +export interface EnqueueVideoMotionCaptureResponse { + success: boolean, + inference_job_token?: string, +} + +export async function EnqueueVideoMotionCapture(request: EnqueueVideoMotionCaptureRequest) : Promise +{ + const endpoint = new ApiConfig().enqueueVideoMotionCapture(); + + return await fetch(endpoint, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify(request), + }) + .then(res => res.json()) + .then(res => { + if (!res) { + return { success : false }; + } + + if (res && 'success' in res) { + return res; + } else { + return { success : false }; + } + }) + .catch(e => { + return { success : false }; + }); +} + diff --git a/packages/components/src/api/video_mocap/index.ts b/packages/components/src/api/video_mocap/index.ts new file mode 100644 index 0000000000..45a1c2b9c1 --- /dev/null +++ b/packages/components/src/api/video_mocap/index.ts @@ -0,0 +1,7 @@ +export type { + EnqueueVideoMotionCaptureRequest, EnqueueVideoMotionCaptureResponse, +} from './EnqueueVideoMotionCapture'; + +export { + EnqueueVideoMotionCapture +} from './EnqueueVideoMotionCapture'; \ No newline at end of file diff --git a/packages/components/src/jobs/InferenceJob.ts b/packages/components/src/jobs/InferenceJob.ts index 93dca97161..1b529482d7 100644 --- a/packages/components/src/jobs/InferenceJob.ts +++ b/packages/components/src/jobs/InferenceJob.ts @@ -8,6 +8,7 @@ export enum FrontendInferenceJobType { VoiceConversion, VoiceDesignerCreateVoice, VoiceDesignerTts, + VideoMotionCapture } // NB: Many of these fields are optional despite the response payload containing them diff --git a/packages/fakeyou.com/src/v2/view/PageContainer.tsx b/packages/fakeyou.com/src/v2/view/PageContainer.tsx index cf5460547f..8019b9c764 100644 --- a/packages/fakeyou.com/src/v2/view/PageContainer.tsx +++ b/packages/fakeyou.com/src/v2/view/PageContainer.tsx @@ -659,7 +659,13 @@ class PageContainer extends React.Component< diff --git a/packages/fakeyou.com/src/v2/view/pages/video_mocap/VideoMocap.tsx b/packages/fakeyou.com/src/v2/view/pages/video_mocap/VideoMocap.tsx index 9c8e89f123..0c9ac95a45 100644 --- a/packages/fakeyou.com/src/v2/view/pages/video_mocap/VideoMocap.tsx +++ b/packages/fakeyou.com/src/v2/view/pages/video_mocap/VideoMocap.tsx @@ -1,13 +1,46 @@ -import React from "react"; -import { useLocalize } from "hooks"; +import React, { useState, useEffect } from "react"; -import TabContentUpload from "./components/tabContentUpload"; -import TabContentLibrary from "./components/tabContentLibrary"; +import { useLocalize } from "hooks"; +import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper"; +import { FrontendInferenceJobType, InferenceJob } from "@storyteller/components/src/jobs/InferenceJob"; + +import { PageVideoProvision } from "./components/pageVideoProvision"; +import { PageInferenceStatuses } from "./components/pageInferenceStatuses"; import { BasicVideo } from "components/common"; -export default function VideoMotionCapture(){ +export default function VideoMotionCapture(props: { + sessionSubscriptionsWrapper: SessionSubscriptionsWrapper, + enqueueInferenceJob: ( + jobToken: string, + frontendInferenceJobType: FrontendInferenceJobType + ) => void, + inferenceJobs: Array, + inferenceJobsByCategory: Map>, +}){ + + const { enqueueInferenceJob } = props; const { t } = useLocalize("VideoMotionCapture"); + enum pageStates { VIDEO_PROVISION, SHOW_JOB_STATUS } + const { VIDEO_PROVISION, SHOW_JOB_STATUS} = pageStates; + const [pageState, setPageState] = useState<{ + index:number, + inputMediaToken: string, + jobToken: string, + resultMediaToken: string + }>({ index: VIDEO_PROVISION, inputMediaToken: "", jobToken: "", resultMediaToken: ""}); + const handlePageState = ( + {tokenType, token }:{tokenType:string, token:string | undefined} + ) => { + if(token && tokenType == "jobToken"){ + setPageState({ + ...pageState, + index: SHOW_JOB_STATUS, + jobToken: token + }) + } + } + return (
@@ -21,34 +54,25 @@ export default function VideoMotionCapture(){
- {/*Video Chooser Tabs*/} + {/*Video Provision Tabs & Job Statuses*/}
-
    -
  • - -
  • -
  • - -
  • -
-
- - -
+ { pageState.index === VIDEO_PROVISION && + + } + { pageState.index === SHOW_JOB_STATUS && + + }
{/*ENDS Video Chooser Tabs*/} diff --git a/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/pageInferenceStatuses.tsx b/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/pageInferenceStatuses.tsx new file mode 100644 index 0000000000..a5ea888460 --- /dev/null +++ b/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/pageInferenceStatuses.tsx @@ -0,0 +1,47 @@ +import React, { useEffect } from 'react' + +import { Analytics } from "common/Analytics"; +import InferenceJobsList from "components/layout/InferenceJobsList"; +import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob"; + +export function PageInferenceStatuses (props:{ + t: Function, + pageStates: Object, + pageState: { + index:number, + inputMediaToken: string, + jobToken: string, + resultMediaToken: string + }, + enqueueInferenceJob: ( + jobToken: string, + frontendInferenceJobType: FrontendInferenceJobType + ) => void, + pageStateCallback: (data:{tokenType:string, token:string | undefined}) => void +}){ + const { enqueueInferenceJob } = props; + useEffect(()=>{ + console.log("ENQUEUE INFERENCE JOB>>") + enqueueInferenceJob( + props.pageState.jobToken, + FrontendInferenceJobType.VideoMotionCapture + ); + }, []) + + const failures = (fail = "") => { + switch (fail) { + case "sample case": + return "Sample Case, this should not have been shown"; + default: + return "Uknown failure"; + } + }; + + return( + Analytics.voiceConversionClickDownload(), + jobType: FrontendInferenceJobType.VideoMotionCapture, + }}/> + ) +} \ No newline at end of file diff --git a/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/pageVideoProvision.tsx b/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/pageVideoProvision.tsx new file mode 100644 index 0000000000..65bb821b75 --- /dev/null +++ b/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/pageVideoProvision.tsx @@ -0,0 +1,39 @@ +import React from "react"; +import TabContentUpload from "./tabContentUpload"; +import TabContentLibrary from "./tabContentLibrary"; + +export function PageVideoProvision (props:{ + t: Function + pageStateCallback: (data:{tokenType:string, token:string | undefined}) => void +}){ + const {t} = props; + return(<> +
    +
  • + +
  • +
  • + +
  • +
+
+ + +
+ ); +} \ No newline at end of file diff --git a/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/tabContentLibrary.tsx b/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/tabContentLibrary.tsx index 926d22611d..af5368fb9f 100644 --- a/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/tabContentLibrary.tsx +++ b/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/tabContentLibrary.tsx @@ -1,7 +1,8 @@ import React from "react"; export default function TabContentLibrary(props: { - t: Function + t: Function, + pageStateCallback: Function }){ const { t } = props return( diff --git a/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/tabContentUpload.tsx b/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/tabContentUpload.tsx index ad294938a5..51927725cf 100644 --- a/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/tabContentUpload.tsx +++ b/packages/fakeyou.com/src/v2/view/pages/video_mocap/components/tabContentUpload.tsx @@ -2,20 +2,25 @@ import React, {useState, useEffect} from "react"; import { v4 as uuidv4 } from "uuid"; import { UploadVideo } from '@storyteller/components/src/api/upload/UploadVideo' +import { + EnqueueVideoMotionCapture +} from "@storyteller/components/src/api/video_mocap"; import { useFile } from "hooks"; import VideoInput from "v2/view/pages/video_mocap/components/VideoInput"; export default function TabContentUpload(props:{ t: Function + pageStateCallback: (data:{tokenType:string, token:string | undefined}) => void }){ - const { t } = props + const { t, pageStateCallback } = props const videoProps = useFile({}) - const NO_FILE = 0 - const FILE_STAGED = 1 - const FILE_UPLOADING = 2 - const FILE_UPLOADED = 3 - const [videoState, setVideoState] = useState(NO_FILE); + enum tabStates { + NO_FILE, FILE_STAGED, FILE_UPLOADING, FILE_UPLOADED + } + const { NO_FILE, FILE_STAGED, FILE_UPLOADING, FILE_UPLOADED } = tabStates; + const [tabState, setTabState] = useState(NO_FILE); + const [token, setToken] = useState(""); const makeRequest = () => ({ uuid_idempotency_token: uuidv4(), @@ -25,39 +30,90 @@ export default function TabContentUpload(props:{ }); const handleUploadVideo = ()=>{ - setVideoState(FILE_UPLOADING) + setTabState(FILE_UPLOADING) UploadVideo(makeRequest()).then((res=>{ - console.log("RESPONSE >>>") - console.log(res) - setVideoState(FILE_UPLOADED) + if(res.success && "upload_token" in res){ + setToken(res.upload_token) + } })); } - // contains upload inout state and controls, see docs - return( -
-
-
- setVideoState(videoProps.file ? FILE_STAGED : NO_FILE), - }}/> -
-
+ useEffect(()=>{ + if (token!=="") setTabState(FILE_UPLOADED) + }, [token]) -
-
-
- - + const handleEnqueueMocapNet = ()=>{ + const request = { + video_source: token, + uuid_idempotency_token: uuidv4() + } + EnqueueVideoMotionCapture(request) + .then(res=>{ + pageStateCallback({ + tokenType: "jobToken", + token: res.inference_job_token + }) + }); + } + // contains upload inout state and controls, see docs + if (tabState === NO_FILE || tabState === FILE_STAGED){ + return( +
+
+
+ setTabState(videoProps.file ? FILE_STAGED : NO_FILE), + }}/>
+ +
+
+
+ +
+
+
+
+ ) + } else if (tabState === FILE_UPLOADING){ + return( +
+
+
+

{t("tab.message.fileUploading")}

+
+
+
+ ) + }else if (tabState === FILE_UPLOADED){ + return( +
+
+
+

{t("tab.message.fileUploaded")}

+
+
+ +
+
+
+ ) + }else { + return( +
+
+
+

{t("tab.message.error")}

+
-
- ) +
+ ) + } } \ No newline at end of file