mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-10 03:51:25 +00:00
copy pasting page
This commit is contained in:
1 parent
ec5ef41fed
commit
f0acf491a9
13 files changed
+501
-1
No files matched your search
@@ -13,6 +13,7 @@ export enum FrontendInferenceJobType {
|
||||
ConvertFbxtoGltf,
|
||||
EngineComposition,
|
||||
VideoWorkflow,
|
||||
VideoStyleTransfer,
|
||||
}
|
||||
|
||||
// NB: Many of these fields are optional despite the response payload containing them
|
||||
|
||||
@@ -212,6 +212,8 @@ function initInferenceJobsByCategoryMap(): Map<
|
||||
inferenceJobsByCategory.set(FrontendInferenceJobType.ConvertFbxtoGltf, []);
|
||||
inferenceJobsByCategory.set(FrontendInferenceJobType.VideoWorkflow, [])
|
||||
return inferenceJobsByCategory;
|
||||
inferenceJobsByCategory.set(FrontendInferenceJobType.VideoStyleTransfer, [])
|
||||
return inferenceJobsByCategory;
|
||||
}
|
||||
|
||||
function isMacOs() {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ModerationIpBanListFc } from "./pages/moderation/moderation_ip_ban_list
|
||||
import { ModerationViewIpBanFc } from "./pages/moderation/moderation_view_ip_ban/ModerationViewIpBanFc";
|
||||
import FaceAnimator from "./pages/face_animator";
|
||||
import VideoMocap from "./pages/video_mocap";
|
||||
import VideoStyleTransfer from "./pages/video_styletransfer";
|
||||
import { ProfileEditFc } from "./pages/profile/profile_edit/ProfileEditFc";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
@@ -866,6 +867,20 @@ class PageContainer extends React.Component<
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/video-styletransfer">
|
||||
<VideoStyleTransfer
|
||||
{...{
|
||||
enqueueInferenceJob: this.props.enqueueInferenceJob,
|
||||
sessionSubscriptionsWrapper:
|
||||
this.props.sessionSubscriptionsWrapper,
|
||||
inferenceJobs: this.props.inferenceJobs,
|
||||
inferenceJobsByCategory:
|
||||
this.props.inferenceJobsByCategory,
|
||||
sessionWrapper: this.props.sessionWrapper,
|
||||
}}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/text-to-image">
|
||||
<TextToImagePage
|
||||
sessionSubscriptionsWrapper={
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import React, {useReducer, useEffect} from 'react';
|
||||
|
||||
import { SessionWrapper } from '@storyteller/components/src/session/SessionWrapper';
|
||||
import { StudioNotAvailable } from 'v2/view/_common/StudioNotAvailable';
|
||||
import { useInferenceJobs, useLocalize } from "hooks";
|
||||
import { FrontendInferenceJobType, InferenceJob } from '@storyteller/components/src/jobs/InferenceJob';
|
||||
|
||||
import { Container } from "components/common";
|
||||
import PageHeader from "components/layout/PageHeader";
|
||||
|
||||
import { states, reducer } from "./reducer";
|
||||
import SubRoutes from "./routes";
|
||||
|
||||
export default function VideoStyleTransfer(props:{
|
||||
enqueueInferenceJob: (
|
||||
jobToken: string,
|
||||
frontendInferenceJobType: FrontendInferenceJobType
|
||||
) => void;
|
||||
inferenceJobs: Array<InferenceJob>;
|
||||
inferenceJobsByCategory: Map<FrontendInferenceJobType, Array<InferenceJob>>;
|
||||
sessionWrapper: SessionWrapper;
|
||||
}){
|
||||
const debug = false;
|
||||
const {t} = useLocalize("VideoStyleTransfer");
|
||||
const { NO_FILE } = states;
|
||||
const [pageState, dispatchPageState] = useReducer(reducer, {
|
||||
status: NO_FILE,
|
||||
});
|
||||
|
||||
const { enqueueInferenceJob } = props;
|
||||
useInferenceJobs(
|
||||
FrontendInferenceJobType.VideoWorkflow
|
||||
);
|
||||
useEffect(() => {
|
||||
if (
|
||||
pageState.status === states.WORKFLOW_ENQUEUED &&
|
||||
pageState.inferenceJobToken
|
||||
) {
|
||||
enqueueInferenceJob(
|
||||
pageState.inferenceJobToken,
|
||||
FrontendInferenceJobType.VideoWorkflow
|
||||
);
|
||||
dispatchPageState({
|
||||
type: "enqueueFilterSuccess",
|
||||
payload: { inferenceJobToken: undefined },
|
||||
});
|
||||
}
|
||||
}, [pageState, enqueueInferenceJob]);
|
||||
|
||||
if (!props.sessionWrapper.canAccessStudio()) {
|
||||
return <StudioNotAvailable />
|
||||
}
|
||||
|
||||
return(
|
||||
<Container type="panel" className="mb-5">
|
||||
{debug && <p>{`Status:${pageState.status} MediaToken:${pageState.mediaFileToken}`}</p>}
|
||||
<PageHeader
|
||||
title={t("headings.title")}
|
||||
subText={t("headings.subtitle")}
|
||||
/>
|
||||
|
||||
<SubRoutes {...{debug, t, pageState, dispatchPageState}}/>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import { Analytics } from "common/Analytics";
|
||||
import InferenceJobsList from "components/layout/InferenceJobsList";
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
|
||||
export default function CompVideoStyleTransferJobList({
|
||||
showNoJobs = false
|
||||
}:{
|
||||
showNoJobs?:boolean
|
||||
}){
|
||||
const failures = (fail = "") => {
|
||||
switch (fail) {
|
||||
case "sample case":
|
||||
return "Sample Case, this should not have been shown";
|
||||
default:
|
||||
return "Unknown failure";
|
||||
}
|
||||
};
|
||||
return (
|
||||
<InferenceJobsList {...{
|
||||
showNoJobs,
|
||||
failures,
|
||||
onSelect: () => Analytics.voiceConversionClickDownload(),
|
||||
jobType: FrontendInferenceJobType.VideoStyleTransfer,
|
||||
}}/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import React, { memo } from 'react'
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { states, Action, State } from "../reducer";
|
||||
import { Button, Spinner } from 'components/common';
|
||||
|
||||
import CompJoblist from './compJoblist';
|
||||
|
||||
export default memo (function PageWorkflowJoblist({
|
||||
t, pageState, dispatchPageState, parentPath
|
||||
}: {
|
||||
debug?: boolean;
|
||||
t: Function;
|
||||
pageState: State;
|
||||
parentPath: string
|
||||
dispatchPageState: (action: Action) => void;
|
||||
}) {
|
||||
|
||||
return(
|
||||
<>
|
||||
<div className="row mb-3">
|
||||
<NavLink to={`${parentPath}`}>
|
||||
<Button
|
||||
label={t("button.generateNewWorkflow")}
|
||||
variant="primary"
|
||||
/>
|
||||
</NavLink>
|
||||
</div>
|
||||
{pageState.status === states.WORKFLOW_ENQUEUEING &&
|
||||
<div>
|
||||
<h2> Requesting Filter Job</h2>
|
||||
<Spinner />
|
||||
</div>
|
||||
}
|
||||
<CompJoblist showNoJobs />
|
||||
</>
|
||||
);
|
||||
});
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import React from "react";
|
||||
|
||||
import { Panel, Tabs } from "components/common";
|
||||
|
||||
import { State, Action } from "../reducer";
|
||||
import TabContentUpload from "./tabContentUpload";
|
||||
import TabContentLibrary from "./tabContentLibrary";
|
||||
import CompJoblist from "./compJoblist";
|
||||
|
||||
export default function PageVideoProvision({
|
||||
debug=false, parentPath, t, pageState, dispatchPageState
|
||||
}: {
|
||||
debug?: boolean;
|
||||
parentPath: string;
|
||||
t: Function;
|
||||
pageState: State;
|
||||
dispatchPageState: (action: Action) => void;
|
||||
}) {
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
label: t("tabTitle.upload"),
|
||||
content: <TabContentUpload {...{
|
||||
debug, t, pageState, dispatchPageState
|
||||
}} />,
|
||||
to: `${parentPath}/upload`,
|
||||
padding: true,
|
||||
},
|
||||
{
|
||||
label: t("tabTitle.library"),
|
||||
content: <TabContentLibrary {...{
|
||||
debug, t, pageState, dispatchPageState
|
||||
}} />,
|
||||
to: `${parentPath}/select-media`,
|
||||
padding: true,
|
||||
},
|
||||
];
|
||||
|
||||
return(
|
||||
<>
|
||||
<Panel className="mb-4">
|
||||
<div className="row g-0">
|
||||
<div className="col-12 col-md-6">
|
||||
<Tabs tabs={tabs} />
|
||||
</div>
|
||||
<div className="col-12 col-md-6 p-5 mt-3">
|
||||
<p>{t("video.instruction")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
<CompJoblist />
|
||||
</>
|
||||
);
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
import React from "react";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import { states, Action, State } from "../reducer";
|
||||
import { Button } from "components/common";
|
||||
import SelectModal, { SelectModalData } from "components/common/SelectModal/SelectModal";
|
||||
import VideoFakeyou from "components/common/VideoFakeyou";
|
||||
|
||||
export default function TabContentLibrary({
|
||||
t, pageState, dispatchPageState
|
||||
}: {
|
||||
t: Function;
|
||||
pageState: State;
|
||||
dispatchPageState: (action: Action) => void;
|
||||
}){
|
||||
const handleProceed = ()=>{
|
||||
dispatchPageState({type: "loadFile"})
|
||||
}
|
||||
const handleOnSelect = (data:SelectModalData)=>{
|
||||
if (data.token !== ""){
|
||||
dispatchPageState({
|
||||
type: "selectedFile",
|
||||
payload: {mediaFileToken: data.token}
|
||||
});
|
||||
}else{
|
||||
dispatchPageState({type: "clearedFile"});
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="row g-3">
|
||||
<div className="col-12">
|
||||
<SelectModal
|
||||
modalTitle="Select a Video"
|
||||
label="Select a Video"
|
||||
onSelect={handleOnSelect}
|
||||
tabs={[
|
||||
{
|
||||
label: "All Videos",
|
||||
tabKey: "allVideos",
|
||||
typeFilter: "video",
|
||||
searcher: false,
|
||||
type: "media",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{pageState.mediaFileToken &&
|
||||
<VideoFakeyou mediaToken={pageState.mediaFileToken} />
|
||||
}
|
||||
</div>
|
||||
{pageState.status === states.FILE_SELECTED &&
|
||||
<div className="col-12 d-flex justify-content-center mt-5">
|
||||
<NavLink to={`load/${pageState.mediaFileToken}`}>
|
||||
<Button
|
||||
label={t("button.proceed")}
|
||||
onClick={handleProceed}
|
||||
/>
|
||||
</NavLink>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
import React from "react";
|
||||
import { Redirect } from "react-router-dom";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { UploadMedia } from "@storyteller/components/src/api/media_files/UploadMedia";
|
||||
import { useFile } from "hooks";
|
||||
import { ErrorMessage, VideoInput, Spinner } from "components/common";
|
||||
import { states, Action, State } from "../reducer";
|
||||
|
||||
export default function TabContentUpload({
|
||||
debug=false, t, pageState, dispatchPageState
|
||||
}: {
|
||||
debug?: boolean;
|
||||
t: Function;
|
||||
pageState: State;
|
||||
dispatchPageState: (action: Action) => void;
|
||||
}) {
|
||||
const videoProps = useFile({});
|
||||
const {NO_FILE, FILE_STAGED, FILE_SELECTED, FILE_UPLOADING, FILE_UPLOADED} = states;
|
||||
|
||||
const makeVideoUploadRequest = () => ({
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
file: videoProps.file,
|
||||
source: "file",
|
||||
type: "video",
|
||||
});
|
||||
|
||||
const handleUploadVideo = () => {
|
||||
dispatchPageState({type: 'uploadFile'});
|
||||
UploadMedia(makeVideoUploadRequest()).then(res => {
|
||||
if (res.success && res.media_file_token) {
|
||||
dispatchPageState({
|
||||
type: 'uploadFileSuccess',
|
||||
payload:{
|
||||
mediaFileToken :res.media_file_token
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// contains upload inout state and controls, see docs
|
||||
if (pageState.status === NO_FILE
|
||||
|| pageState.status === FILE_STAGED
|
||||
|| pageState.status === FILE_SELECTED
|
||||
) {
|
||||
return (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<VideoInput
|
||||
{...{
|
||||
t,
|
||||
...videoProps,
|
||||
onStateChange: () =>{
|
||||
if (pageState.status === NO_FILE && videoProps.file)
|
||||
dispatchPageState({type: "stagedFile"})
|
||||
else if (pageState.status === FILE_STAGED && !videoProps.file)
|
||||
dispatchPageState({type: "clearedFile"})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row py-3">
|
||||
<div className="col-12">
|
||||
<div className="d-flex justify-content-end gap-3">
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
disabled={pageState.status !== FILE_STAGED}
|
||||
onClick={handleUploadVideo}
|
||||
>
|
||||
{t("button.upload")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}else if (pageState.status === FILE_UPLOADING){
|
||||
return(
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<h1>{t("message.fileUploading")}</h1>
|
||||
</div>
|
||||
<div className="col-12">
|
||||
<Spinner />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}else if (pageState.status === FILE_UPLOADED){
|
||||
return(
|
||||
<Redirect to={`load/${pageState.mediaFileToken}`}/>
|
||||
)
|
||||
}
|
||||
return <ErrorMessage />;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
export {default} from "./VideoStyleTransfer";
|
||||
@@ -0,0 +1,87 @@
|
||||
import { MediaFile } from "@storyteller/components/src/api/media_files/GetMediaFile";
|
||||
|
||||
export enum states{
|
||||
NO_FILE,
|
||||
FILE_STAGED,
|
||||
FILE_SELECTED,
|
||||
FILE_UPLOADING,
|
||||
FILE_UPLOADED,
|
||||
FILE_LOADING,
|
||||
FILE_LOADED,
|
||||
WORKFLOW_ENQUEUEING,
|
||||
WORKFLOW_ENQUEUED
|
||||
}
|
||||
|
||||
export type State = {
|
||||
status: number;
|
||||
mediaFileToken?: string;
|
||||
mediaFile?: MediaFile;
|
||||
inferenceJobToken?: string;
|
||||
}
|
||||
|
||||
export type Action =
|
||||
| {type: 'reset'}
|
||||
| {type: 'stagedFile'}
|
||||
| {type: 'clearedFile'}
|
||||
| {type: 'selectedFile', payload: { mediaFileToken: string}}
|
||||
| {type: 'uploadFile'}
|
||||
| {type: 'uploadFileSuccess', payload:{ mediaFileToken: string}}
|
||||
| {type: 'loadFile'}
|
||||
| {type: 'loadFileSuccess', payload:{
|
||||
mediaFileToken: string, mediaFile: MediaFile
|
||||
}}
|
||||
| {type: 'enqueueFilter'}
|
||||
| {type: 'enqueueFilterSuccess', payload: {inferenceJobToken: string|undefined}}
|
||||
|
||||
|
||||
export function reducer (state: State, action: Action): State {
|
||||
|
||||
switch(action.type){
|
||||
case 'stagedFile':
|
||||
return {...state, status: states.FILE_STAGED}
|
||||
case 'clearedFile':
|
||||
return {...state,
|
||||
status: states.NO_FILE,
|
||||
mediaFileToken: ""
|
||||
}
|
||||
case 'selectedFile':
|
||||
return {
|
||||
...state,
|
||||
status: states.FILE_SELECTED,
|
||||
mediaFileToken: action.payload.mediaFileToken
|
||||
}
|
||||
case 'uploadFile':
|
||||
return {...state,status: states.FILE_UPLOADING};
|
||||
case 'uploadFileSuccess':
|
||||
return {
|
||||
...state,
|
||||
status: states.FILE_UPLOADED,
|
||||
mediaFileToken: action.payload.mediaFileToken
|
||||
}
|
||||
case 'loadFile':
|
||||
return {...state, status: states.FILE_LOADING}
|
||||
case 'loadFileSuccess':
|
||||
console.log("LOAD FILE SUCCESS");
|
||||
return {
|
||||
...state,
|
||||
status: states.FILE_LOADED,
|
||||
mediaFile: action.payload.mediaFile,
|
||||
mediaFileToken : action.payload.mediaFileToken,
|
||||
}
|
||||
case 'enqueueFilter':
|
||||
return {
|
||||
...state,
|
||||
status: states.WORKFLOW_ENQUEUEING
|
||||
}
|
||||
case 'enqueueFilterSuccess':
|
||||
return {
|
||||
...state,
|
||||
status: states.WORKFLOW_ENQUEUED,
|
||||
inferenceJobToken: action.payload.inferenceJobToken
|
||||
}
|
||||
case 'reset':
|
||||
default:
|
||||
return {status: states.NO_FILE};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from "react";
|
||||
import {Switch, Route, useRouteMatch, Redirect, useHistory} from "react-router-dom";
|
||||
// import PageWorkflowControls from "./components/pageWorkflowControls";
|
||||
import PageVideoProvision from "./components/pageVideoProvision";
|
||||
import PageJoblist from "./components/pageJoblist";
|
||||
import {states,State,Action} from "./reducer";
|
||||
|
||||
export default function SubRoutes ({
|
||||
debug, t, pageState, dispatchPageState
|
||||
}:{
|
||||
debug?:boolean,
|
||||
t:Function,
|
||||
pageState:State,
|
||||
dispatchPageState: (action: Action) => void
|
||||
}){
|
||||
const { path } = useRouteMatch();
|
||||
const history = useHistory();
|
||||
history.listen(({pathname}, action) => {
|
||||
if ((pathname === path || pathname.match(/upload|select-media/g)) && pageState.status >= states.FILE_LOADING){
|
||||
//reset page if landed on page "Freshly"
|
||||
dispatchPageState({type: 'reset'})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const commonPageProps = {
|
||||
debug, parentPath: path, t, pageState, dispatchPageState
|
||||
};
|
||||
|
||||
return(
|
||||
<Switch>
|
||||
{/* <Route exact path={`${path}/load/:mediaToken`} >
|
||||
<PageWorkflowControls {...commonPageProps}/>
|
||||
</Route> */}
|
||||
<Route exact path={`${path}/upload`}>
|
||||
<PageVideoProvision {...commonPageProps}/>
|
||||
</Route>
|
||||
<Route exact path={`${path}/select-media`}>
|
||||
<PageVideoProvision {...commonPageProps}/>
|
||||
</Route>
|
||||
<Route exact path={`${path}/jobs`}>
|
||||
<PageJoblist {...commonPageProps}/>
|
||||
</Route>
|
||||
<Route path={`${path}`}>
|
||||
<Redirect to={`${path}/upload`} />
|
||||
</Route>
|
||||
</Switch>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import SubRoutes from "./videoWorkflowRoutes";
|
||||
import { SessionWrapper } from '@storyteller/components/src/session/SessionWrapper';
|
||||
import { StudioNotAvailable } from 'v2/view/_common/StudioNotAvailable';
|
||||
|
||||
export default function StorytellerFilter(props:{
|
||||
export default function VideoWorkflow(props:{
|
||||
enqueueInferenceJob: (
|
||||
jobToken: string,
|
||||
frontendInferenceJobType: FrontendInferenceJobType
|
||||
|
||||
Reference in new issue
Block a user