mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 09:28:11 +00:00
Merge pull request #620 from storytold/unused-file-cleanup
Unused file cleanup, header text wrap fix
This commit is contained in:
35 files changed
+19
-2980
No files matched your search
@@ -448,7 +448,7 @@ export default function SideNav({
|
||||
|
||||
<li>
|
||||
<NavLink
|
||||
to="/video-styletransfer"
|
||||
to="/style-video"
|
||||
activeClassName="active-link"
|
||||
onClick={handleNavLinkClick}
|
||||
>
|
||||
|
||||
@@ -449,7 +449,7 @@ export default function TopNav({
|
||||
</Link>
|
||||
|
||||
{domain.titlePart === "FakeYou" && (
|
||||
<div className="d-none d-lg-block">
|
||||
<div className="d-none d-lg-block no-wrap">
|
||||
<NavItem
|
||||
icon={faScrewdriverWrench}
|
||||
label="Creator Tools"
|
||||
@@ -462,13 +462,13 @@ export default function TopNav({
|
||||
icon={faCompass}
|
||||
label="Explore"
|
||||
link="/explore"
|
||||
className="d-none d-lg-block"
|
||||
className="d-none d-lg-block no-wrap"
|
||||
/>
|
||||
<NavItem
|
||||
icon={faStar}
|
||||
label="Pricing"
|
||||
link="/pricing"
|
||||
className="me-3 d-none d-lg-block"
|
||||
className="me-3 d-none d-lg-block no-wrap"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,6 @@ 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";
|
||||
@@ -816,14 +815,6 @@ class PageContainer extends React.Component<
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/video-styletransfer">
|
||||
<VideoStyleTransfer
|
||||
{...{
|
||||
sessionWrapper: this.props.sessionWrapper,
|
||||
}}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/text-to-image">
|
||||
<TextToImagePage
|
||||
sessionSubscriptionsWrapper={
|
||||
|
||||
+6
-6
@@ -10,22 +10,22 @@ const columns = [
|
||||
{
|
||||
title: "Original Video",
|
||||
videoSrc: "/videos/landing/vst/1-original.mp4",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
{
|
||||
title: "2D Flat Anime",
|
||||
videoSrc: "/videos/landing/vst/1-2d_flat_anime.mp4",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
{
|
||||
title: "Ink B&W",
|
||||
videoSrc: "/videos/landing/vst/1-ink_bw.mp4",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
{
|
||||
title: "Origami",
|
||||
videoSrc: "/videos/landing/vst/1-origami.mp4",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -70,7 +70,7 @@ export default function VstSectionV1(props: VstSectionV1Props) {
|
||||
small={true}
|
||||
icon={faArrowRight}
|
||||
iconFlip={true}
|
||||
to="/video-styletransfer"
|
||||
to="/style-video"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -88,7 +88,7 @@ export default function VstSectionV1(props: VstSectionV1Props) {
|
||||
<Badge label={column.title} color="gray" />
|
||||
</div>
|
||||
{/* <div className="vst-sbs-video-overlay-cta">
|
||||
<Link to={column.ctaLink || "/video-styletransfer"}>
|
||||
<Link to={column.ctaLink || "/style-video"}>
|
||||
<Badge label="Try this style" />
|
||||
</Link>
|
||||
</div> */}
|
||||
|
||||
+9
-9
@@ -61,22 +61,22 @@ export default function VstSectionV2(props: VstSectionV2Props) {
|
||||
{
|
||||
src: "/videos/landing/vst/1-2d_flat_anime.mp4",
|
||||
label: "2D Flat Anime",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
{
|
||||
src: "/videos/landing/vst/1-3d_cartoon.mp4",
|
||||
label: "3D Cartoon",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
{
|
||||
src: "/videos/landing/vst/1-ink_bw.mp4",
|
||||
label: "Ink B&W",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
{
|
||||
src: "/videos/landing/vst/1-origami.mp4",
|
||||
label: "Origami",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -87,22 +87,22 @@ export default function VstSectionV2(props: VstSectionV2Props) {
|
||||
{
|
||||
src: "/videos/landing/vst/2-2d_flat_anime.mp4",
|
||||
label: "2D Flat Anime",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
{
|
||||
src: "/videos/landing/vst/2-pop_art.mp4",
|
||||
label: "Pop Art",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
{
|
||||
src: "/videos/landing/vst/2-ink_splash.mp4",
|
||||
label: "Ink Splash",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
{
|
||||
src: "/videos/landing/vst/2-origami.mp4",
|
||||
label: "Origami",
|
||||
ctaLink: "/video-styletransfer",
|
||||
ctaLink: "/style-video",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -240,7 +240,7 @@ export default function VstSectionV2(props: VstSectionV2Props) {
|
||||
<Badge label={styledVideo.label} color="gray" />
|
||||
</div>
|
||||
{/* <div className="vst-styled-videos-panel-overlay-cta">
|
||||
<Link to={styledVideo.ctaLink || "/video-styletransfer"}>
|
||||
<Link to={styledVideo.ctaLink || "/style-video"}>
|
||||
<Badge label="Try this style" />
|
||||
</Link>
|
||||
</div> */}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
.studio-intro-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100vh - 66px);
|
||||
|
||||
.studio-intro-exporter {
|
||||
background: rgba(#000, .5);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: .5rem;
|
||||
right: 1rem;
|
||||
bottom: 1rem;
|
||||
padding: .5rem;
|
||||
position: absolute;
|
||||
|
||||
|
||||
.exporter-title {
|
||||
width: 100%;
|
||||
|
||||
span {
|
||||
opacity: .66;
|
||||
font-size: .875rem;
|
||||
height: 1em;
|
||||
line-height: 1em;
|
||||
display: block;
|
||||
margin-bottom: .25rem;
|
||||
}
|
||||
}
|
||||
.exporter-controls {
|
||||
display: flex;
|
||||
gap: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.result-video-wrapper {
|
||||
max-width: 1100px;
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { StudioNotAvailable } from "v2/view/_common/StudioNotAvailable";
|
||||
import { Button } from "components/common";
|
||||
import { usePrefixedDocumentTitle } from "common/UsePrefixedDocumentTitle";
|
||||
import { useParams, useHistory } from "react-router-dom";
|
||||
import { useInferenceJobs } from "hooks";
|
||||
import { EnqueueEngineCompositing } from "@storyteller/components/src/api/engine_compositor/EnqueueEngineCompositing";
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import "./StudioIntro.scss";
|
||||
import Scene3D from "components/common/Scene3D/Scene3D";
|
||||
import { EngineMode } from "components/common/Scene3D/EngineMode";
|
||||
import { SplitFirstPeriod } from "utils/SplitFirstPeriod";
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper;
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
}
|
||||
|
||||
const PAGE_TITLE = "Storyteller Studio";
|
||||
|
||||
function StudioIntroPage(props: Props) {
|
||||
// NB: The URL parameter might be a raw media token (for .scn.ron files), or it might
|
||||
// have an appended suffix to assist the engine in loading the correct scene format.
|
||||
// For example, this is a valid "mediaTokenSpec": `m_zk0qkm1tgsdbh6e3c9kedy34vaympd.glb`
|
||||
const { mediaToken: mediaTokenSpec } = useParams<{ mediaToken: string }>();
|
||||
|
||||
const { base: mediaToken, maybeRemainder: maybeExtension } =
|
||||
SplitFirstPeriod(mediaTokenSpec);
|
||||
|
||||
const history = useHistory();
|
||||
|
||||
const inferenceJobs = useInferenceJobs();
|
||||
|
||||
// If the user saves the scene in the engine, we'll need to use the new token
|
||||
// for subsequent steps of this flow.
|
||||
const [savedMediaToken, setSavedMediaToken] = useState(mediaToken);
|
||||
|
||||
// We don't show the "next step" buttons until the engine loads.
|
||||
// Unfortunately the engine sometimes fires this twice, with one instance
|
||||
// being called before the scene loads. Until this is fixed, we'll count the
|
||||
// number of event fires and assume we must have two calls.
|
||||
const [sceneIsLoadedCount, sceneIsLoadedCountSet] = useState(0);
|
||||
|
||||
// If the scene is saved, we know the user must have interacted.
|
||||
// This can serve as a second optional gate for enabling the next steps.
|
||||
const [sceneIsSaved, sceneIsSavedSet] = useState(false);
|
||||
|
||||
usePrefixedDocumentTitle(PAGE_TITLE);
|
||||
|
||||
const onSaveCallback = useCallback(
|
||||
(sceneMediaToken: string) => {
|
||||
console.log(`Saved scene, new media token: ${sceneMediaToken}`);
|
||||
|
||||
setSavedMediaToken(sceneMediaToken);
|
||||
sceneIsSavedSet(true); // Just in case we missed the "scene loaded" event.
|
||||
|
||||
// Replace the history state without causing a React re-render
|
||||
window.history.replaceState(
|
||||
null,
|
||||
PAGE_TITLE,
|
||||
`/studio-intro/${sceneMediaToken}`
|
||||
);
|
||||
},
|
||||
[setSavedMediaToken, sceneIsSavedSet]
|
||||
);
|
||||
|
||||
const onSceneReadyCallback = useCallback(() => {
|
||||
sceneIsLoadedCountSet(sceneIsLoadedCount + 1);
|
||||
}, [sceneIsLoadedCount, sceneIsLoadedCountSet]);
|
||||
|
||||
if (!props.sessionWrapper.canAccessStudio()) {
|
||||
return <StudioNotAvailable />;
|
||||
}
|
||||
|
||||
let assetDescriptor;
|
||||
|
||||
// We should prefer to start the onboarding flow with an existing scene, but if
|
||||
// one is unavailable, we should show the sample room.
|
||||
if (maybeExtension !== undefined) {
|
||||
assetDescriptor = {
|
||||
sceneImportToken: mediaToken,
|
||||
extension: maybeExtension,
|
||||
};
|
||||
} else if (mediaToken) {
|
||||
assetDescriptor = {
|
||||
storytellerSceneMediaFileToken: mediaToken,
|
||||
};
|
||||
} else {
|
||||
assetDescriptor = {
|
||||
objectId: "sample-room.gltf",
|
||||
};
|
||||
}
|
||||
|
||||
const onClick = () => {
|
||||
// This opens the job modal. Needs to be disabled.
|
||||
EnqueueEngineCompositing("", {
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
media_file_token: savedMediaToken,
|
||||
skybox: "meadow_4k",
|
||||
}).then((res: any) => {
|
||||
if (res && res.success) {
|
||||
inferenceJobs.enqueue(
|
||||
res.inference_job_token,
|
||||
FrontendInferenceJobType.EngineComposition
|
||||
);
|
||||
history.push(`/studio-intro/style/${res.inference_job_token}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const sceneIsLoaded = sceneIsLoadedCount > 1 || sceneIsSaved;
|
||||
|
||||
let progressButtons = <></>;
|
||||
|
||||
if (sceneIsLoaded) {
|
||||
progressButtons = (
|
||||
<div {...{ className: "p-3 d-flex justify-content-center" }}>
|
||||
<Button label="Create Movie from 3D Scene" onClick={onClick} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="studio-intro-page">
|
||||
<Scene3D
|
||||
fullScreen={true}
|
||||
mode={EngineMode.Studio}
|
||||
asset={assetDescriptor}
|
||||
className="flex-grow-1"
|
||||
onSceneReadyCallback={onSceneReadyCallback}
|
||||
onSceneSavedCallback={onSaveCallback}
|
||||
/>
|
||||
|
||||
{progressButtons}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { StudioIntroPage };
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { Button, Container, Panel } from "components/common";
|
||||
import { usePrefixedDocumentTitle } from "common/UsePrefixedDocumentTitle";
|
||||
import { useHistory, useParams } from "react-router-dom";
|
||||
import "./StudioIntro.scss";
|
||||
import LoadingSpinner from "components/common/LoadingSpinner";
|
||||
import { useMedia, useInferenceJobs } from "hooks";
|
||||
import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
|
||||
import { MediaFileType } from "@storyteller/components/src/api/media_files";
|
||||
import { JobState } from "@storyteller/components/src/jobs/JobStates";
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper;
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
}
|
||||
|
||||
// This page just needs to poll the job and show the video when it's done.
|
||||
|
||||
function StudioIntroResultPage(props: Props) {
|
||||
const [rething,rethingSet] = useState(false);
|
||||
const { jobToken } = useParams<{ jobToken: string }>();
|
||||
const history = useHistory();
|
||||
const { enqueue, inferenceJobs } = useInferenceJobs();
|
||||
const job = inferenceJobs.find((item: any) => item.jobToken === jobToken);
|
||||
|
||||
useEffect(() => {
|
||||
if (!job && !rething) {
|
||||
rethingSet(true);
|
||||
enqueue(jobToken);
|
||||
}
|
||||
},[enqueue,job,jobToken,rething]);
|
||||
|
||||
|
||||
// const [mediaToken, setMediaToken] = useState(
|
||||
// "m_f5kp3hm74qeq16eq7536jb73jkbvkh"
|
||||
// ); // Set the media token after polling success
|
||||
// const [jobExists, setJobExists] = useState<boolean | null>(null);
|
||||
|
||||
// const job = useJobStatus({ jobToken });
|
||||
|
||||
const [mediaFile, setMediaFile] = useState<MediaFileType>();
|
||||
|
||||
const mediaToken = job?.maybeResultToken|| "";
|
||||
|
||||
useMedia({
|
||||
mediaToken,
|
||||
onSuccess: (res: any) => {
|
||||
setMediaFile(res);
|
||||
},
|
||||
});
|
||||
|
||||
const mediaLink =
|
||||
mediaFile && new BucketConfig().getGcsUrl(mediaFile.public_bucket_path);
|
||||
|
||||
usePrefixedDocumentTitle("Storyteller Studio");
|
||||
|
||||
if (!jobToken) {
|
||||
history.push("/");
|
||||
}
|
||||
|
||||
const contentSwitch = () => {
|
||||
switch (job?.jobState) {
|
||||
case JobState.UNKNOWN:
|
||||
case JobState.PENDING:
|
||||
case JobState.STARTED: return <LoadingSpinner label="Generating your movie..." />;
|
||||
case JobState.ATTEMPT_FAILED: return <div {...{ className: "d-flex justify-content-center align-items-center" }}>
|
||||
<h3>{`Attempt failed, retrying (attempt ${ job.attemptCount } )`}</h3>
|
||||
</div>;
|
||||
case JobState.COMPLETE_SUCCESS: return <video src={mediaLink} controls />;
|
||||
case JobState.DEAD: return <h3>Job dead</h3>;
|
||||
case JobState.CANCELED_BY_USER: return <h3>Job canceled by user</h3>;
|
||||
default: return;
|
||||
};
|
||||
}
|
||||
|
||||
// Should also check if job actually exists or not
|
||||
//
|
||||
// if (!jobExists) {
|
||||
// history.push("/");
|
||||
// }
|
||||
|
||||
return (
|
||||
<Container
|
||||
type="full"
|
||||
className="mt-4 d-flex flex-column align-items-center"
|
||||
>
|
||||
<Panel clear={true}>
|
||||
<h2 className="fw-bold mb-0 mb-4 text-center">Generation Result</h2>
|
||||
</Panel>
|
||||
<Panel className="overflow-hidden rounded result-video-wrapper">
|
||||
<div className="ratio ratio-16x9">
|
||||
{
|
||||
contentSwitch()
|
||||
}
|
||||
</div>
|
||||
</Panel>
|
||||
{mediaToken ? (
|
||||
<div className="d-flex justify-content-center p-4">
|
||||
<Button label="Sign up to use your own scene" />
|
||||
</div>
|
||||
) : null}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export { StudioIntroResultPage };
|
||||
-190
@@ -1,190 +0,0 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { NavLink, useParams, useHistory } from "react-router-dom";
|
||||
import { Button, Container, Panel, Select, TextArea } from "components/common";
|
||||
|
||||
// import { VideoPlayer } from "components/common/VideoPlayer";
|
||||
import { useJobStatus, useInferenceJobs, useMedia } from "hooks";
|
||||
import {
|
||||
EnqueueVST,
|
||||
EnqueueVSTResponse,
|
||||
} from "@storyteller/components/src/api/workflows/EnqueueVST";
|
||||
import { initialValues } from "./defaultValues";
|
||||
import { VSTType } from "./helpers";
|
||||
import LoadingSpinner from "components/common/LoadingSpinner";
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { STYLE_OPTIONS, StyleOption } from "common/StyleOptions";
|
||||
import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
|
||||
|
||||
export default function PageVSTApp() {
|
||||
const { jobToken } = useParams<{ jobToken: string }>();
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const history = useHistory();
|
||||
|
||||
const job = useJobStatus({ jobToken });
|
||||
|
||||
const { enqueue } = useInferenceJobs();
|
||||
|
||||
const [vstValues, setVstValues] = useState<VSTType>({
|
||||
...initialValues,
|
||||
// fileToken: job?.maybe_result?.entity_token || "",
|
||||
});
|
||||
|
||||
// console.log(job);
|
||||
// console.log(job?.maybe_result);
|
||||
// console.log(job?.maybe_result?.entity_token);
|
||||
|
||||
const handleOnChange = (val: {
|
||||
[key: string]: number | string | boolean | undefined;
|
||||
}) => {
|
||||
setVstValues(curr => ({ ...curr, ...val }));
|
||||
};
|
||||
|
||||
const handleGenerate = () => {
|
||||
EnqueueVST("", {
|
||||
creator_set_visibility: vstValues.visibility,
|
||||
enable_lipsync: false,
|
||||
input_file: job?.maybe_result?.entity_token || "",
|
||||
negative_prompt: vstValues.negPrompt,
|
||||
prompt: vstValues.posPrompt,
|
||||
style: vstValues.sdModelToken,
|
||||
trim_end_millis: 3000,
|
||||
trim_start_millis: 0,
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
}).then((res: EnqueueVSTResponse) => {
|
||||
if (res.success && res.inference_job_token) {
|
||||
enqueue(
|
||||
res.inference_job_token,
|
||||
FrontendInferenceJobType.VideoStyleTransfer
|
||||
);
|
||||
// console.log("Job enqueued successfully", res.inference_job_token);
|
||||
history.push(`/studio-intro/result/${res.inference_job_token}`);
|
||||
} else {
|
||||
console.log("Failed to enqueue job", res);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (videoRef?.current) {
|
||||
const ve = videoRef.current;
|
||||
ve.onloadedmetadata = () => {
|
||||
const newValues: {
|
||||
width?: number;
|
||||
height?: number;
|
||||
maxDuration?: number;
|
||||
} = {};
|
||||
if (ve.duration) {
|
||||
newValues.maxDuration = ve.duration;
|
||||
}
|
||||
setVstValues(curr => ({
|
||||
...curr,
|
||||
...newValues,
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
const handleStyleSelection = (selectedOption: StyleOption) => {
|
||||
console.log("option", selectedOption);
|
||||
const selectedSdModelToken = selectedOption ? selectedOption.value : null;
|
||||
if (selectedSdModelToken) {
|
||||
setVstValues(curr => ({ ...curr, sdModelToken: selectedSdModelToken }));
|
||||
}
|
||||
};
|
||||
|
||||
if (!jobToken) {
|
||||
history.push("/");
|
||||
}
|
||||
|
||||
// const contentSwitch = () => {
|
||||
// switch (job.jobState) {
|
||||
// case JobState.UNKNOWN:
|
||||
// case JobState.PENDING:
|
||||
// case JobState.STARTED: return <LoadingSpinner label="Loading Video" />;
|
||||
// case JobState.ATTEMPT_FAILED: return <div {...{ className: "d-flex justify-content-center align-items-center" }}>
|
||||
// { `Video compositor attempt failed, retrying (attempt ${ job.attemptCount } )` }
|
||||
// </div>;
|
||||
// case JobState.COMPLETE_SUCCESS: return <VideoFakeyou mediaToken={job.maybe_result.entity_token}/>;
|
||||
// case JobState.DEAD: return <div>Job dead</div>;
|
||||
// case JobState.CANCELED_BY_USER: return <div>Job canceled by user</div>;
|
||||
// };
|
||||
// }
|
||||
|
||||
// Should also check if job actually exists or not
|
||||
//
|
||||
// if (!jobExists) {
|
||||
// history.push("/");
|
||||
// }
|
||||
|
||||
const { media } = useMedia({
|
||||
mediaToken: job?.maybe_result?.entity_token,
|
||||
});
|
||||
|
||||
const mediaLink =
|
||||
media?.public_bucket_path &&
|
||||
new BucketConfig().getGcsUrl(media?.public_bucket_path || "");
|
||||
|
||||
return (
|
||||
<Container type="panel" className="mt-5">
|
||||
<Panel clear={true}>
|
||||
<h2 className="fw-bold mb-0 mb-5 text-center">Style Your Scene</h2>
|
||||
</Panel>
|
||||
<Panel padding={true}>
|
||||
<div className="row g-5">
|
||||
<div className="col-12 col-md-6">
|
||||
{job.isSuccessful && job.maybe_result ? (
|
||||
<div className="ratio ratio-4x3 panel-inner rounded">
|
||||
<video src={mediaLink} controls />
|
||||
</div>
|
||||
) : (
|
||||
<div className="ratio ratio-4x3 panel-inner rounded">
|
||||
<LoadingSpinner label="Loading Video" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-12 col-md-6 d-flex flex-column gap-3 justify-content-center">
|
||||
<div>
|
||||
<label className="sub-title">Select a Style</label>
|
||||
<Select
|
||||
label="Label"
|
||||
options={STYLE_OPTIONS}
|
||||
onChange={handleStyleSelection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TextArea
|
||||
label="Describe Your Scene"
|
||||
placeholder="Enter your description..."
|
||||
onChange={e => handleOnChange({ posPrompt: e.target.value })}
|
||||
value={vstValues.posPrompt}
|
||||
required={false}
|
||||
rows={5}
|
||||
resize={false}
|
||||
/>
|
||||
{/* <TextArea
|
||||
label="Negative Prompt"
|
||||
placeholder="Enter your negative prompt"
|
||||
onChange={e => handleOnChange({ negPrompt: e.target.value })}
|
||||
value={vstValues.negPrompt}
|
||||
required={false}
|
||||
/> */}
|
||||
{/* <SectionAdvanceOptions
|
||||
onChange={handleOnChange}
|
||||
vstValues={vstValues}
|
||||
/> */}
|
||||
<div className="d-flex gap-2 justify-content-end mt-3">
|
||||
<NavLink to="/">
|
||||
<Button label="Cancel" variant="secondary" />
|
||||
</NavLink>
|
||||
<Button
|
||||
label="Generate Your Movie"
|
||||
onClick={handleGenerate}
|
||||
variant="primary"
|
||||
disabled={!job.isSuccessful}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
type CNPreset =
|
||||
'custom'|
|
||||
'closeup'|
|
||||
'default' |
|
||||
'halfbody'|
|
||||
'fullbody'|
|
||||
'landscape'|
|
||||
'typog';
|
||||
|
||||
const defaultPreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 1,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0,
|
||||
cnSoftEdge: 1,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
const closeupPreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 0,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0.7,
|
||||
cnSoftEdge: 0.7,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
const halfbodyPreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 0.7,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0,
|
||||
cnSoftEdge: 1,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
const fullbodyPreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 1,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0,
|
||||
cnSoftEdge: 1,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
const landscapePreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0.4,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 0,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0,
|
||||
cnSoftEdge: 0,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
const typogPreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 0,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0,
|
||||
cnSoftEdge: 0.7,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
export type {
|
||||
CNPreset
|
||||
}
|
||||
export {
|
||||
defaultPreset,
|
||||
closeupPreset,
|
||||
halfbodyPreset,
|
||||
fullbodyPreset,
|
||||
landscapePreset,
|
||||
typogPreset,
|
||||
};
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
import { defaultPreset as defaultCN } from "./cnPresets";
|
||||
|
||||
export { initialValues, hiddenValues };
|
||||
const initialValues = {
|
||||
//files Settings
|
||||
fileToken: "",
|
||||
outputPath: "vid2vid/SparseUpscaleInterp_00001.mp4",
|
||||
|
||||
//video Settings
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
maxDuration: 0,
|
||||
trimStart: 0,
|
||||
trimEnd: 3,
|
||||
|
||||
//Presents
|
||||
workflowConfig: "weight_0a04e66y14t4e2bwxjfyg1mb2", //weight_99tz2nzbp5x9v55gqn5ekj1sd
|
||||
sdModelToken: "weight_yqexh77ntqyawzgh9fzash798",
|
||||
loraModelToken: "",
|
||||
loraModelStrength: 0,
|
||||
|
||||
//basics
|
||||
inputFps: 24,
|
||||
posPrompt: "",
|
||||
negPrompt: "",
|
||||
visibility: "private",
|
||||
|
||||
//Control Net
|
||||
...defaultCN,
|
||||
};
|
||||
|
||||
const hiddenValues = {
|
||||
posPrompt: "",
|
||||
negPrompt:
|
||||
"flare, lens flare, glare,naked, nsfw, text, logo, watermark:1.3, letterboxed,embedding:easynegative, embedding:badhandv4,(worst quality, low quality:1.4), lowres, blurry, monochrome, ",
|
||||
};
|
||||
@@ -1,91 +0,0 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { hiddenValues } from "./defaultValues";
|
||||
|
||||
export type VSTType = {
|
||||
// File Settings
|
||||
fileToken: string;
|
||||
outputPath: string;
|
||||
// Video Settings
|
||||
width: number;
|
||||
height: number;
|
||||
maxDuration: number;
|
||||
trimStart: number;
|
||||
trimEnd: number;
|
||||
|
||||
// Presets
|
||||
workflowConfig: string;
|
||||
sdModelToken: string;
|
||||
// loraModelToken: string;
|
||||
// loraModelStrength: number;
|
||||
|
||||
//basics
|
||||
inputFps: number;
|
||||
posPrompt: string;
|
||||
negPrompt: string;
|
||||
visibility: string;
|
||||
|
||||
//advance
|
||||
cnCanny: number;
|
||||
cnDepth: number;
|
||||
cnLineArtAnime: number;
|
||||
cnLineArtRealistic: number;
|
||||
cnLipsStrength: number;
|
||||
cnOpenPose: number;
|
||||
cnPipeFace: number;
|
||||
cnSparseScribble: number;
|
||||
cnSoftEdge: number;
|
||||
cnRegularSteps: number;
|
||||
};
|
||||
|
||||
export function isInputValid(keyValues: {
|
||||
[key: string]: number | string | boolean | undefined;
|
||||
}) {
|
||||
return (
|
||||
keyValues.sdModelToken &&
|
||||
keyValues.sdModelToken !== "" &&
|
||||
keyValues.posPrompt &&
|
||||
keyValues.posPrompt !== ""
|
||||
);
|
||||
}
|
||||
|
||||
export function mapRequest(vstValues: VSTType) {
|
||||
//TODO: improve the typing of this
|
||||
return {
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
maybe_sd_model: vstValues.sdModelToken,
|
||||
maybe_workflow_config: vstValues.workflowConfig,
|
||||
maybe_input_file: vstValues.fileToken,
|
||||
maybe_trim_start_seconds: 0, //vstValues.trimStart
|
||||
maybe_trim_end_seconds: 3, //vstValues.trimEnd
|
||||
maybe_output_path: vstValues.outputPath,
|
||||
creator_set_visibility: vstValues.visibility,
|
||||
maybe_json_modifications: {
|
||||
"$.154.inputs.Value": vstValues.inputFps,
|
||||
"$.510.inputs.Text": hiddenValues.posPrompt + vstValues.posPrompt,
|
||||
"$.8.inputs.text": hiddenValues.negPrompt + vstValues.negPrompt,
|
||||
|
||||
"$.401.inputs.Value": 0.7, //Denoise First Pass
|
||||
"$.140.inputs.Value": 1, // Every nth frame
|
||||
"$.536.inputs.boolean_number": 1, // use LCM
|
||||
"$.1075.inputs.Value": 1280,
|
||||
"$.1076.inputs.Value": 720,
|
||||
"$.1079.inputs.Value": 1280,
|
||||
"$.1080.inputs.Value": 720,
|
||||
|
||||
"$.403.inputs.Value": vstValues.cnSparseScribble,
|
||||
"$.771.inputs.Value": vstValues.cnOpenPose,
|
||||
"$.772.inputs.Value": vstValues.cnDepth,
|
||||
"$.796.inputs.Value": vstValues.cnLineArtRealistic,
|
||||
"$.797.inputs.Value": vstValues.cnLineArtAnime,
|
||||
"$.1398.inputs.Value": vstValues.cnSoftEdge,
|
||||
"$.1531.inputs.Value": vstValues.cnRegularSteps,
|
||||
|
||||
//"$.800.inputs.Value": 0, // vstValues.cnCanny,
|
||||
//"$.1636.inputs.Value": 0, //vstValues.cnLipsStrength,
|
||||
|
||||
// "$.208.inputs.lora_01": vstValues.loraModelToken,
|
||||
// "$.208.inputs.strength_01": vstValues.loraModelStrength
|
||||
// "$.1449.inputs.filename_prefix": "vid2vid/SparseUpscaleInterp",
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from "./StudioVSTPage";
|
||||
-273
@@ -1,273 +0,0 @@
|
||||
import React, {useState} from 'react';
|
||||
|
||||
import {
|
||||
faBuildingColumns,
|
||||
faFaceViewfinder,
|
||||
faPerson,
|
||||
// faRotateLeft,
|
||||
faStar,
|
||||
// faSparkles,
|
||||
faText,
|
||||
faUser,
|
||||
|
||||
}
|
||||
from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
import {
|
||||
// Accordion,
|
||||
Button,
|
||||
Label,
|
||||
// NumberSliderV2
|
||||
} from 'components/common';
|
||||
import { VSTType } from './helpers';
|
||||
import {
|
||||
CNPreset,
|
||||
closeupPreset,
|
||||
halfbodyPreset,
|
||||
fullbodyPreset,
|
||||
landscapePreset,
|
||||
typogPreset,
|
||||
defaultPreset,
|
||||
} from './cnPresets';
|
||||
|
||||
|
||||
export default function SectionAdvanceOptions({
|
||||
vstValues: vstVal,
|
||||
onChange: handleOnChange
|
||||
}:{
|
||||
vstValues : VSTType,
|
||||
onChange: (val:{[key: string]: number|string|boolean|undefined})=>void
|
||||
}){
|
||||
|
||||
const [preset, pickPreset] = useState<CNPreset>('default')
|
||||
function handlePreset(newPreset: CNPreset){
|
||||
switch (newPreset){
|
||||
case 'closeup':
|
||||
handleOnChange(closeupPreset);
|
||||
break;
|
||||
case 'halfbody':
|
||||
handleOnChange(halfbodyPreset);
|
||||
break;
|
||||
case 'fullbody':
|
||||
handleOnChange(fullbodyPreset);
|
||||
break;
|
||||
case 'landscape':
|
||||
handleOnChange(landscapePreset);
|
||||
break;
|
||||
case 'typog':
|
||||
handleOnChange(typogPreset);
|
||||
break;
|
||||
case 'custom':
|
||||
default:
|
||||
handleOnChange(defaultPreset);
|
||||
break;
|
||||
}
|
||||
pickPreset(newPreset);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Label label="Video's Camera Angle"/>
|
||||
{/* <div className="d-flex flex-wrap w-100">
|
||||
<div className="my-1 me-1">
|
||||
<Button
|
||||
icon={faStar}
|
||||
label="Default"
|
||||
isActive={preset==='default'}
|
||||
onClick={()=>handlePreset('default')}
|
||||
/>
|
||||
</div>
|
||||
<div className="my-1 me-1">
|
||||
<Button
|
||||
icon={faSparkles}
|
||||
label="Custom"
|
||||
isActive={preset==='custom'}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="d-flex flex-wrap w-100">
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faStar}
|
||||
label="Default"
|
||||
isActive={preset==='default'}
|
||||
onClick={()=>handlePreset('default')}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faFaceViewfinder}
|
||||
label="Face Closeups"
|
||||
isActive={preset==='closeup'}
|
||||
onClick={()=>handlePreset('closeup')}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faUser}
|
||||
label="Half Body Shots"
|
||||
isActive={preset==='halfbody'}
|
||||
onClick={()=>handlePreset('halfbody')}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faPerson}
|
||||
label="Full Body Shots"
|
||||
isActive={preset==='fullbody'}
|
||||
onClick={()=>handlePreset('fullbody')}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faBuildingColumns}
|
||||
label="Architecture or Landscape"
|
||||
isActive={preset==='landscape'}
|
||||
onClick={()=>handlePreset('landscape')}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faText}
|
||||
label="Flat Logos, or Typographies"
|
||||
isActive={preset==='typog'}
|
||||
onClick={()=>handlePreset('typog')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* <Accordion className="mt-4">
|
||||
<Accordion.Item title={"Advanced Options"}>
|
||||
<div className="row g-3 p-3">
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnCanny,
|
||||
label: "Canny",
|
||||
thumbTip: "Canny",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnCanny: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnDepth,
|
||||
label: "Depth",
|
||||
thumbTip: "Depth",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnDepth: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className="row g-3 p-3">
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnLineArtAnime,
|
||||
label: "Line Art - Anime",
|
||||
thumbTip: "Line Art - Anime",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnLineArtAnime: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnLineArtRealistic,
|
||||
label: "Line Art - Realistic",
|
||||
thumbTip: "Line Art - Realistic)",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnLineArtRealistic: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row g-3 p-3">
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnOpenPose,
|
||||
label: "OpenPose",
|
||||
thumbTip: "OpenPose",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnOpenPose: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnPipeFace,
|
||||
label: "Media Pipe Face",
|
||||
thumbTip: "Media Pipe Face",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnPipeFace: val})
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row g-3 p-3">
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnSparseScribble,
|
||||
label: "Sparse Scribble",
|
||||
thumbTip: "Sparse Scribble",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnSparseScribble: val})
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnSoftEdge,
|
||||
label: "Soft Edge",
|
||||
thumbTip: "SoftEdge",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnSoftEdge: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="row g-3 p-3">
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 1, max: 64, step: 1,
|
||||
initialValue: vstVal.cnRegularSteps,
|
||||
label: "Regular Steps",
|
||||
thumbTip: "Regular Steps",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnRegularSteps: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-flex p-3 justify-content-end">
|
||||
<Button
|
||||
icon={faRotateLeft}
|
||||
label="Reset to Default"
|
||||
onClick={()=>{
|
||||
handlePreset('default');
|
||||
pickPreset('default');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Accordion.Item>
|
||||
</Accordion> */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
@import "scss/colours.scss";
|
||||
|
||||
.studio-tutorial-page {
|
||||
display: flex;
|
||||
background: $panel;
|
||||
|
||||
.studio-tutorial-style {
|
||||
min-width: fit-content;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
.tutorial-style-tab {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.tutorial-tab-loading {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,326 +0,0 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { StudioNotAvailable } from "v2/view/_common/StudioNotAvailable";
|
||||
import { BasicTabs, Spinner } from "components/common";
|
||||
import { usePrefixedDocumentTitle } from "common/UsePrefixedDocumentTitle";
|
||||
import { useHistory, useParams, useLocation } from "react-router-dom";
|
||||
import { useInferenceJobs, useMedia } from "hooks";
|
||||
import { EnqueueEngineCompositing } from "@storyteller/components/src/api/engine_compositor/EnqueueEngineCompositing";
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { jobStateCanChange } from "@storyteller/components/src/jobs/JobStates";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import Scene3D from "components/common/Scene3D/Scene3D";
|
||||
import { EngineMode } from "components/common/Scene3D/EngineMode";
|
||||
import { SplitFirstPeriod } from "utils/SplitFirstPeriod";
|
||||
import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
|
||||
|
||||
import StyleEditor from "./StyleEditor";
|
||||
|
||||
import { initialValues } from "../storyteller_studio_intro/StudioVST/defaultValues";
|
||||
import { VSTType } from "../storyteller_studio_intro/StudioVST/helpers";
|
||||
|
||||
import "./StudioTutorial.scss";
|
||||
|
||||
import {
|
||||
EnqueueVST,
|
||||
EnqueueVSTResponse,
|
||||
} from "@storyteller/components/src/api/workflows/EnqueueVST";
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper;
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
}
|
||||
|
||||
export default function StudioTutorial(props: Props) {
|
||||
// NB: The URL parameter might be a raw media token (for .scn.ron files), or it might
|
||||
// have an appended suffix to assist the engine in loading the correct scene format.
|
||||
// For example, this is a valid "mediaTokenSpec": `m_zk0qkm1tgsdbh6e3c9kedy34vaympd.glb`
|
||||
const { mediaToken: mediaTokenSpec } = useParams<{ mediaToken: string }>();
|
||||
|
||||
const [vstValues, setVstValues] = useState<VSTType>({
|
||||
...initialValues,
|
||||
// fileToken: job?.maybe_result?.entity_token || "",
|
||||
});
|
||||
|
||||
const { base: mediaToken, maybeRemainder: maybeExtension } =
|
||||
SplitFirstPeriod(mediaTokenSpec);
|
||||
|
||||
// for updating url state
|
||||
|
||||
const history = useHistory();
|
||||
const { pathname, search: locSearch } = useLocation();
|
||||
const urlQueries = new URLSearchParams(locSearch);
|
||||
const queryCompositeJob = urlQueries.get("compositeJobToken");
|
||||
const queryStyleJob = urlQueries.get("styleJobToken");
|
||||
|
||||
// side bar tab state
|
||||
|
||||
const [selectedTab, selectedTabSet] = useState("");
|
||||
|
||||
// for both jobs
|
||||
|
||||
const { enqueue, inferenceJobs = [] } = useInferenceJobs();
|
||||
|
||||
// engine compositor job state
|
||||
|
||||
const [compositeJobToken, compositeJobTokenSet] = useState(
|
||||
queryCompositeJob || ""
|
||||
);
|
||||
const compositeJobStatus = inferenceJobs.find(
|
||||
(item: any) => item.jobToken === compositeJobToken
|
||||
);
|
||||
const compositing =
|
||||
compositeJobStatus && jobStateCanChange(compositeJobStatus.jobState);
|
||||
const compositeMediaToken = compositeJobStatus?.maybeResultToken || "";
|
||||
const [refreshedCompositor, refreshedCompositorSet] = useState(false);
|
||||
|
||||
// video style style transfer job state
|
||||
|
||||
const [styleJobToken, styleJobTokenSet] = useState(queryStyleJob || "");
|
||||
const [styleEnqueued, styleEnqueuedSet] = useState(false);
|
||||
const styleJobStatus = inferenceJobs.find(
|
||||
(item: any) => item.jobToken === styleJobToken
|
||||
);
|
||||
const styling = styleJobStatus && jobStateCanChange(styleJobStatus.jobState);
|
||||
const styleMediaToken = styleJobStatus?.maybeResultToken || "";
|
||||
const [refreshedStyle, refreshedStyleSet] = useState(false);
|
||||
|
||||
const { media: styleMedia } = useMedia({
|
||||
mediaToken: styleMediaToken,
|
||||
});
|
||||
|
||||
const styleMediaLink =
|
||||
styleMediaToken &&
|
||||
styleMedia &&
|
||||
new BucketConfig().getGcsUrl(styleMedia?.public_bucket_path || "");
|
||||
|
||||
// If the user saves the scene in the engine, we'll need to use the new token
|
||||
// for subsequent steps of this flow.
|
||||
const [savedMediaToken, setSavedMediaToken] = useState(mediaToken);
|
||||
|
||||
// We don't show the "next step" buttons until the engine loads.
|
||||
// Unfortunately the engine sometimes fires this twice, with one instance
|
||||
// being called before the scene loads. Until this is fixed, we'll count the
|
||||
// number of event fires and assume we must have two calls.
|
||||
const [sceneIsLoadedCount, sceneIsLoadedCountSet] = useState(0);
|
||||
|
||||
// If the scene is saved, we know the user must have interacted.
|
||||
// This can serve as a second optional gate for enabling the next steps.
|
||||
const [sceneIsSaved, sceneIsSavedSet] = useState(false);
|
||||
|
||||
const [
|
||||
camera,
|
||||
// cameraSet
|
||||
] = useState("zoom");
|
||||
|
||||
usePrefixedDocumentTitle("Storyteller Studio");
|
||||
|
||||
const onSaveCallback = useCallback(
|
||||
(sceneMediaToken: string) => {
|
||||
setSavedMediaToken(sceneMediaToken);
|
||||
sceneIsSavedSet(true); // Just in case we missed the "scene loaded" event.
|
||||
},
|
||||
[setSavedMediaToken, sceneIsSavedSet]
|
||||
);
|
||||
|
||||
const onSceneReadyCallback = useCallback(() => {
|
||||
sceneIsLoadedCountSet(sceneIsLoadedCount + 1);
|
||||
}, [sceneIsLoadedCount, sceneIsLoadedCountSet]);
|
||||
|
||||
let assetDescriptor;
|
||||
|
||||
// We should prefer to start the onboarding flow with an existing scene, but if
|
||||
// one is unavailable, we should show the sample room.
|
||||
if (maybeExtension !== undefined) {
|
||||
assetDescriptor = {
|
||||
sceneImportToken: mediaToken,
|
||||
extension: maybeExtension,
|
||||
};
|
||||
} else if (mediaToken) {
|
||||
assetDescriptor = {
|
||||
storytellerSceneMediaFileToken: mediaToken,
|
||||
};
|
||||
} else {
|
||||
assetDescriptor = {
|
||||
objectId: "sample-room.gltf",
|
||||
};
|
||||
}
|
||||
|
||||
const compositorStart = () => {
|
||||
// This opens the job modal. Needs to be disabled.
|
||||
EnqueueEngineCompositing("", {
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
media_file_token: savedMediaToken,
|
||||
camera: camera,
|
||||
camera_speed: 0.2,
|
||||
skybox: "meadow_4k",
|
||||
}).then((res: any) => {
|
||||
if (res && res.success) {
|
||||
let newURLQueries = new URLSearchParams({
|
||||
compositeJobToken: res.inference_job_token,
|
||||
}).toString();
|
||||
|
||||
history.replace({ pathname, search: newURLQueries });
|
||||
// enqueue(res.inference_job_token,false,FrontendInferenceJobType.EngineComposition);
|
||||
compositeJobTokenSet(res.inference_job_token);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const tabs = [
|
||||
{ value: "animation", label: "Animation" },
|
||||
{ value: "camera", label: "Camera" },
|
||||
{ value: "audio", label: "Audio" },
|
||||
{ value: "style", label: "Style" },
|
||||
];
|
||||
|
||||
const sceneIsLoaded = sceneIsLoadedCount > 0 || sceneIsSaved;
|
||||
|
||||
const workingText = () => {
|
||||
if (compositing && !styling) return "Compositing";
|
||||
else if (styling && !compositing) return "Styling";
|
||||
return "";
|
||||
};
|
||||
|
||||
const tabContent = () => {
|
||||
if (!sceneIsLoaded || compositing || styling)
|
||||
return (
|
||||
<div {...{ className: "tutorial-tab-loading" }}>
|
||||
<div>
|
||||
<h3>{workingText()}</h3>
|
||||
<Spinner />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
else if (styleMediaToken)
|
||||
return (
|
||||
<div>
|
||||
<video controls {...{ src: styleMediaLink }} />
|
||||
</div>
|
||||
);
|
||||
else if (sceneIsLoaded)
|
||||
return <StyleEditor {...{ compositorStart, setVstValues, vstValues }} />;
|
||||
else return null;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const enqueueStyle = () => {
|
||||
console.log("💜 style enqueue started", { vstValues, styleEnqueued });
|
||||
EnqueueVST("", {
|
||||
creator_set_visibility: vstValues.visibility,
|
||||
enable_lipsync: true,
|
||||
input_file: compositeMediaToken || "",
|
||||
negative_prompt: vstValues.negPrompt,
|
||||
prompt: "A dog in a sunny field with lots of flowers",
|
||||
style: vstValues.sdModelToken,
|
||||
trim_end_millis: 3000,
|
||||
trim_start_millis: 0,
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
}).then((res: EnqueueVSTResponse) => {
|
||||
console.log("✅", res);
|
||||
if (res.success && res.inference_job_token) {
|
||||
let newURLQueries = new URLSearchParams({
|
||||
compositeJobToken,
|
||||
engineJobToken: res.inference_job_token,
|
||||
}).toString();
|
||||
// enqueue(res.inference_job_token,false,FrontendInferenceJobType.VideoStyleTransfer);
|
||||
styleJobTokenSet(res.inference_job_token);
|
||||
history.replace({ pathname, search: newURLQueries });
|
||||
// console.log("Job enqueued successfully", res.inference_job_token);
|
||||
// history.push(`/studio-intro/result/${res.inference_job_token}`);
|
||||
} else {
|
||||
console.log("Failed to enqueue job", res);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (compositeMediaToken && !styleEnqueued) {
|
||||
styleEnqueuedSet(true);
|
||||
enqueueStyle();
|
||||
}
|
||||
|
||||
if (sceneIsLoaded && !selectedTab) {
|
||||
selectedTabSet("style");
|
||||
}
|
||||
|
||||
if (compositeJobToken && !compositeJobStatus && !refreshedCompositor) {
|
||||
console.log("🧱", "compositor refreshed");
|
||||
refreshedCompositorSet(true);
|
||||
enqueue(
|
||||
compositeJobToken,
|
||||
FrontendInferenceJobType.EngineComposition,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if (styleJobToken && !styleJobStatus && !refreshedStyle) {
|
||||
console.log("🎨", "styler refreshed");
|
||||
refreshedStyleSet(true);
|
||||
enqueue(
|
||||
styleJobToken,
|
||||
FrontendInferenceJobType.VideoStyleTransfer,
|
||||
false
|
||||
);
|
||||
}
|
||||
}, [
|
||||
camera,
|
||||
enqueue,
|
||||
compositeJobStatus,
|
||||
compositeJobToken,
|
||||
compositeMediaToken,
|
||||
history,
|
||||
pathname,
|
||||
refreshedCompositor,
|
||||
refreshedStyle,
|
||||
savedMediaToken,
|
||||
selectedTab,
|
||||
sceneIsLoaded,
|
||||
styleEnqueued,
|
||||
styleJobStatus,
|
||||
styleJobToken,
|
||||
vstValues,
|
||||
]);
|
||||
|
||||
console.log("🚒 tutorial overall state", {
|
||||
compositeJobStatus,
|
||||
compositing,
|
||||
compositeMediaToken,
|
||||
queryCompositeJob,
|
||||
queryStyleJob,
|
||||
sceneIsLoadedCount,
|
||||
styleJobStatus,
|
||||
styleEnqueued,
|
||||
styling,
|
||||
styleMediaToken,
|
||||
urlQueries,
|
||||
styleMediaLink,
|
||||
});
|
||||
|
||||
return !props.sessionWrapper.canAccessStudio() ? (
|
||||
<StudioNotAvailable />
|
||||
) : (
|
||||
<div className="studio-tutorial-page">
|
||||
<Scene3D
|
||||
{...{
|
||||
asset: assetDescriptor,
|
||||
mode: EngineMode.Studio,
|
||||
onSaveCallback,
|
||||
onSceneReadyCallback,
|
||||
// overrideURL: "http://127.0.0.1:4200", // COMMENT OUT BEFORE PUSHING
|
||||
}}
|
||||
/>
|
||||
<div {...{ className: "studio-tutorial-style" }}>
|
||||
<BasicTabs
|
||||
{...{
|
||||
onChange: ({ target }: { target: any }) =>
|
||||
selectedTabSet(target.value),
|
||||
tabs,
|
||||
value: selectedTab,
|
||||
}}
|
||||
/>
|
||||
{tabContent()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Button, TextArea } from "components/common";
|
||||
|
||||
import SelectionBubblesV2 from "components/common/SelectionBubblesV2";
|
||||
|
||||
import { VSTType } from "../storyteller_studio_intro/StudioVST/helpers";
|
||||
|
||||
interface Props {
|
||||
compositorStart: () => any,
|
||||
setVstValues: (input: any) => any,
|
||||
vstValues: VSTType,
|
||||
}
|
||||
|
||||
export default function StyleEditor({ compositorStart, setVstValues, vstValues }: Props) {
|
||||
const styleOptions = [
|
||||
{
|
||||
label: "2D Anime",
|
||||
imageUrl: "/images/landing/onboarding/styles/style-2d-anime.webp",
|
||||
token: "anime_2d_flat",
|
||||
},
|
||||
{
|
||||
label: "3D Cartoon",
|
||||
imageUrl: "/images/landing/onboarding/styles/style-3d-cartoon.webp",
|
||||
token: "cartoon_3d",
|
||||
},
|
||||
{
|
||||
label: "Ink B&W",
|
||||
imageUrl: "/images/landing/onboarding/styles/style-ink-bw.webp",
|
||||
token: "ink_bw_style",
|
||||
},
|
||||
{
|
||||
label: "Origami",
|
||||
imageUrl: "/images/landing/onboarding/styles/style-origami.webp",
|
||||
token: "paper_origami",
|
||||
},
|
||||
];
|
||||
|
||||
const selectStyle = (selectedLabel: any) => {
|
||||
const selectedOption = styleOptions.find(
|
||||
option => option.label === selectedLabel
|
||||
);
|
||||
const selectedSdModelToken = selectedOption ? selectedOption.token : null;
|
||||
if (selectedSdModelToken) {
|
||||
setVstValues((curr: VSTType) => ({ ...curr, sdModelToken: selectedSdModelToken }));
|
||||
}
|
||||
};
|
||||
|
||||
const handleOnChange = (val: {
|
||||
[key: string]: number | string | boolean | undefined;
|
||||
}) => {
|
||||
setVstValues((curr: VSTType) => ({ ...curr, ...val }));
|
||||
};
|
||||
|
||||
|
||||
return <div {...{ className: "tutorial-style-tab" }}>
|
||||
<SelectionBubblesV2 {...{
|
||||
options: Object.values(styleOptions),
|
||||
onSelect: selectStyle,
|
||||
mobileSideScroll: true,
|
||||
selectedStyle: "outline",
|
||||
variant: "card"
|
||||
}}/>
|
||||
<TextArea
|
||||
label="Enter a prompt"
|
||||
placeholder="Enter your description..."
|
||||
onChange={e => handleOnChange({ posPrompt: e.target.value })}
|
||||
value={vstValues.posPrompt}
|
||||
required={false}
|
||||
rows={5}
|
||||
resize={false}
|
||||
/>
|
||||
<TextArea
|
||||
label="Negative prompt"
|
||||
placeholder="Enter your description..."
|
||||
onChange={e => handleOnChange({ negPrompt: e.target.value })}
|
||||
value={vstValues.negPrompt}
|
||||
required={false}
|
||||
rows={5}
|
||||
resize={false}
|
||||
/>
|
||||
<Button {...{
|
||||
label: "Generate Your Movie",
|
||||
onClick: compositorStart,
|
||||
}} />
|
||||
</div>;
|
||||
};
|
||||
@@ -1,63 +0,0 @@
|
||||
import React, { useReducer, useEffect } from "react";
|
||||
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { useInferenceJobs, useLocalize } from "hooks";
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { Container } from "components/common";
|
||||
|
||||
import { states, reducer } from "./reducer";
|
||||
import SubRoutes from "./routes";
|
||||
import PageHeaderWithImage from "components/layout/PageHeaderWithImage";
|
||||
import { faFilms } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { VideoStyleTransferNotAvailable } from "v2/view/_common/VideoStyleTransferNotAvailable";
|
||||
|
||||
export default function VideoStyleTransfer({
|
||||
sessionWrapper,
|
||||
}: {
|
||||
sessionWrapper: SessionWrapper;
|
||||
}) {
|
||||
const debug = false;
|
||||
const { t } = useLocalize("VideoStyleTransfer");
|
||||
const { NO_FILE } = states;
|
||||
const [pageState, dispatchPageState] = useReducer(reducer, {
|
||||
status: NO_FILE,
|
||||
});
|
||||
|
||||
const { enqueueInferenceJob } = useInferenceJobs();
|
||||
useEffect(() => {
|
||||
if (
|
||||
pageState.status === states.JOB_ENQUEUED &&
|
||||
pageState.inferenceJobToken
|
||||
) {
|
||||
enqueueInferenceJob(
|
||||
pageState.inferenceJobToken,
|
||||
FrontendInferenceJobType.VideoStyleTransfer
|
||||
);
|
||||
dispatchPageState({
|
||||
type: "enqueueJobSuccess",
|
||||
payload: { inferenceJobToken: undefined },
|
||||
});
|
||||
}
|
||||
}, [pageState, enqueueInferenceJob]);
|
||||
|
||||
if (!sessionWrapper.canAccessVideoStyleTransfer()) {
|
||||
return <VideoStyleTransferNotAvailable />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Container type="panel" className="mb-5">
|
||||
{debug && (
|
||||
<p>{`Status:${pageState.status} MediaToken:${pageState.mediaFileToken}`}</p>
|
||||
)}
|
||||
<PageHeaderWithImage
|
||||
headerImage="/mascot/vst.webp"
|
||||
titleIcon={faFilms}
|
||||
title={t("headings.title")}
|
||||
subText={t("headings.subtitle")}
|
||||
yOffset="80%"
|
||||
/>
|
||||
|
||||
<SubRoutes {...{ debug, t, pageState, dispatchPageState }} />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
export const inferenceFailures = (fail = "") => {
|
||||
switch (fail) {
|
||||
case "sample case":
|
||||
return "Sample Case, this should not have been shown";
|
||||
default:
|
||||
return "Unknown failure";
|
||||
}
|
||||
};
|
||||
|
||||
export function TableOfKeyValues(
|
||||
{
|
||||
title,
|
||||
keyValues,
|
||||
height
|
||||
}:{
|
||||
title: string;
|
||||
keyValues:{
|
||||
[key:string]:number|string|boolean|undefined
|
||||
|{ [key:string]:number|string}
|
||||
};
|
||||
height?: number | string
|
||||
}){
|
||||
return(<table style={{
|
||||
display:'block',
|
||||
height: height || "100%",
|
||||
overflowY: "scroll",
|
||||
overflowX: "clip",
|
||||
// border: "1px solid white",
|
||||
// borderTopLeftRadius: "1rem",
|
||||
// borderBottomLeftRadius: "1rem",
|
||||
}}><tbody>
|
||||
<tr><th>{title}</th></tr>
|
||||
{
|
||||
Object.entries(keyValues).map(([key, val], index: number)=>{
|
||||
if(key!=="defaultCN" && key!=="defaultPrompts")
|
||||
return <tr key={index}><td>{`${key}`}</td><td>{`${val}`}</td></tr>
|
||||
else return null
|
||||
})
|
||||
}
|
||||
</tbody></table>);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import React, { memo } from "react";
|
||||
import { NavLink } from "react-router-dom";
|
||||
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import InferenceJobsList from "components/layout/InferenceJobsList";
|
||||
import { Analytics } from "common/Analytics";
|
||||
import { Button, Spinner } from "components/common";
|
||||
import { states, Action, State } from "../reducer";
|
||||
import { inferenceFailures } from "../commons";
|
||||
|
||||
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.generateNew")} variant="primary" />
|
||||
</NavLink>
|
||||
</div>
|
||||
{pageState.status === states.JOB_ENQUEUEING && (
|
||||
<div>
|
||||
<h2>t("message.requestingJob")</h2>
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
<InferenceJobsList
|
||||
{...{
|
||||
showNoJobs: true,
|
||||
failures: inferenceFailures,
|
||||
onSelect: () => Analytics.voiceConversionClickDownload(),
|
||||
jobType: FrontendInferenceJobType.VideoStyleTransfer,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
import React, {
|
||||
useState
|
||||
} from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import {
|
||||
Accordion,
|
||||
Button,
|
||||
TempTextArea as TextArea,
|
||||
} from "components/common";
|
||||
|
||||
import { mapRequest, VSTType } from './helpers';
|
||||
import { TableOfKeyValues } from "../../commons";
|
||||
import { Action } from "../../reducer";
|
||||
import EnqueueVideoStyleTransfer from "@storyteller/components/src/api/video_styleTransfer";
|
||||
|
||||
export const CompAdminPanel = ({
|
||||
parentPath,
|
||||
vstValues,
|
||||
dispatchPageState
|
||||
}:{
|
||||
parentPath: string;
|
||||
vstValues : VSTType;
|
||||
dispatchPageState: (action: Action) => void;
|
||||
})=>{
|
||||
const history = useHistory();
|
||||
const exampleJSON = JSON.stringify(mapRequest(vstValues), null, 4);
|
||||
const [jsonRequest, setJsonRequest] = useState<string>(exampleJSON);
|
||||
const handleSendRequest = ()=>{
|
||||
EnqueueVideoStyleTransfer(JSON.parse(jsonRequest)).then(res => {
|
||||
if (res.success && res.inference_job_token) {
|
||||
dispatchPageState({
|
||||
type: "enqueueJobSuccess",
|
||||
payload: {
|
||||
inferenceJobToken: res.inference_job_token,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
alert("Error, Check Console Log");
|
||||
console.log(res);
|
||||
}
|
||||
});
|
||||
dispatchPageState({ type: "enqueueJob" });
|
||||
history.push(`${parentPath}/jobs`);
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion className="mt-4">
|
||||
<Accordion.Item title={"Admin Panel"}>
|
||||
<div className="row p-3 g-3">
|
||||
<div className="col-8">
|
||||
<TextArea
|
||||
{...{
|
||||
label:"JSON Input",
|
||||
rows: 10,
|
||||
placeholder: "Paste JSON here and send request directly",
|
||||
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) =>
|
||||
setJsonRequest(e.target.value),
|
||||
value: jsonRequest,
|
||||
required: false,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-4 pt-5">
|
||||
<Button
|
||||
label="Console Log JSON Reqest"
|
||||
variant="secondary"
|
||||
onClick={()=>{
|
||||
console.log(JSON.parse(jsonRequest));
|
||||
}}
|
||||
/>
|
||||
<br/>
|
||||
<Button
|
||||
label="Send JSON"
|
||||
onClick={handleSendRequest}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row p-3 g-3">
|
||||
<div className="col-8">
|
||||
<TableOfKeyValues
|
||||
title="All values in the VST app state"
|
||||
keyValues={vstValues}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-4">
|
||||
<p className="me-3"><b>Log Debug Values: </b></p>
|
||||
<br/>
|
||||
<Button
|
||||
label="Console Log State"
|
||||
variant="secondary"
|
||||
onClick={()=>{
|
||||
console.log(vstValues);
|
||||
}}
|
||||
/>
|
||||
<br/>
|
||||
<Button
|
||||
label="Console Log Request"
|
||||
variant="secondary"
|
||||
onClick={()=>{
|
||||
const request = mapRequest(vstValues);
|
||||
console.log(request);
|
||||
}}
|
||||
/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
);
|
||||
}
|
||||
-277
@@ -1,277 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import {
|
||||
faBuildingColumns,
|
||||
faFaceViewfinder,
|
||||
faPerson,
|
||||
// faRotateLeft,
|
||||
faStar,
|
||||
// faSparkles,
|
||||
faText,
|
||||
faUser,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
import {
|
||||
// Accordion,
|
||||
Button,
|
||||
Label,
|
||||
// NumberSliderV2
|
||||
} from "components/common";
|
||||
import { VSTType } from "./helpers";
|
||||
import {
|
||||
CNPreset,
|
||||
closeupPreset,
|
||||
halfbodyPreset,
|
||||
fullbodyPreset,
|
||||
landscapePreset,
|
||||
typogPreset,
|
||||
// defaultPreset,
|
||||
} from "./dataCnPresets";
|
||||
|
||||
export default function CompAdvanceOptions({
|
||||
debug: propsDebug = false,
|
||||
t,
|
||||
vstValues: vstVal,
|
||||
onChange: handleOnChange,
|
||||
currDefaultCN: defaultPreset
|
||||
}: {
|
||||
debug?: boolean;
|
||||
t: Function;
|
||||
vstValues: VSTType;
|
||||
currDefaultCN: {[key: string]: number};
|
||||
onChange: (val: {
|
||||
[key: string]: number | string | boolean | undefined;
|
||||
}) => void;
|
||||
}) {
|
||||
const [preset, pickPreset] = useState<CNPreset>("default");
|
||||
function handlePreset(newPreset: CNPreset) {
|
||||
switch (newPreset) {
|
||||
case "closeup":
|
||||
handleOnChange(closeupPreset);
|
||||
break;
|
||||
case "halfbody":
|
||||
handleOnChange(halfbodyPreset);
|
||||
break;
|
||||
case "fullbody":
|
||||
handleOnChange(fullbodyPreset);
|
||||
break;
|
||||
case "landscape":
|
||||
handleOnChange(landscapePreset);
|
||||
break;
|
||||
case "typog":
|
||||
handleOnChange(typogPreset);
|
||||
break;
|
||||
case "custom":
|
||||
default:
|
||||
handleOnChange(defaultPreset);
|
||||
break;
|
||||
}
|
||||
pickPreset(newPreset);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Label label="Video's Camera Angle" />
|
||||
{/* <div className="d-flex flex-wrap w-100">
|
||||
<div className="my-1 me-1">
|
||||
<Button
|
||||
icon={faStar}
|
||||
label="Default"
|
||||
isActive={preset==='default'}
|
||||
onClick={()=>handlePreset('default')}
|
||||
/>
|
||||
</div>
|
||||
<div className="my-1 me-1">
|
||||
<Button
|
||||
icon={faSparkles}
|
||||
label="Custom"
|
||||
isActive={preset==='custom'}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="d-flex flex-wrap w-100">
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faStar}
|
||||
label="Default"
|
||||
isActive={preset === "default"}
|
||||
onClick={() => handlePreset("default")}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faFaceViewfinder}
|
||||
label="Face Closeups"
|
||||
isActive={preset === "closeup"}
|
||||
onClick={() => handlePreset("closeup")}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faUser}
|
||||
label="Half Body Shots"
|
||||
isActive={preset === "halfbody"}
|
||||
onClick={() => handlePreset("halfbody")}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faPerson}
|
||||
label="Full Body Shots"
|
||||
isActive={preset === "fullbody"}
|
||||
onClick={() => handlePreset("fullbody")}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faBuildingColumns}
|
||||
label="Architecture or Landscape"
|
||||
isActive={preset === "landscape"}
|
||||
onClick={() => handlePreset("landscape")}
|
||||
/>
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<Button
|
||||
icon={faText}
|
||||
label="Flat Logos, or Typographies"
|
||||
isActive={preset === "typog"}
|
||||
onClick={() => handlePreset("typog")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* <Accordion className="mt-4">
|
||||
<Accordion.Item title={"Advanced Options"}>
|
||||
<div className="row g-3 p-3">
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnCanny,
|
||||
label: "Canny",
|
||||
thumbTip: "Canny",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnCanny: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnDepth,
|
||||
label: "Depth",
|
||||
thumbTip: "Depth",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnDepth: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className="row g-3 p-3">
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnLineArtAnime,
|
||||
label: "Line Art - Anime",
|
||||
thumbTip: "Line Art - Anime",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnLineArtAnime: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnLineArtRealistic,
|
||||
label: "Line Art - Realistic",
|
||||
thumbTip: "Line Art - Realistic)",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnLineArtRealistic: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row g-3 p-3">
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnOpenPose,
|
||||
label: "OpenPose",
|
||||
thumbTip: "OpenPose",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnOpenPose: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnPipeFace,
|
||||
label: "Media Pipe Face",
|
||||
thumbTip: "Media Pipe Face",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnPipeFace: val})
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row g-3 p-3">
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnSparseScribble,
|
||||
label: "Sparse Scribble",
|
||||
thumbTip: "Sparse Scribble",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnSparseScribble: val})
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 0, max: 1, step: 0.1,
|
||||
initialValue: vstVal.cnSoftEdge,
|
||||
label: "Soft Edge",
|
||||
thumbTip: "SoftEdge",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnSoftEdge: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="row g-3 p-3">
|
||||
<div className="col-md-6">
|
||||
<NumberSliderV2 {...{
|
||||
min: 1, max: 64, step: 1,
|
||||
initialValue: vstVal.cnRegularSteps,
|
||||
label: "Regular Steps",
|
||||
thumbTip: "Regular Steps",
|
||||
onChange: (val)=>{
|
||||
handleOnChange({cnRegularSteps: val});
|
||||
pickPreset('custom');
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-flex p-3 justify-content-end">
|
||||
<Button
|
||||
icon={faRotateLeft}
|
||||
label="Reset to Default"
|
||||
onClick={()=>{
|
||||
handlePreset('default');
|
||||
pickPreset('default');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Accordion.Item>
|
||||
</Accordion> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
|
||||
import { MasonryGrid, WeightsCards } from "components/common";
|
||||
import { SelectModalV2 } from "components/common/SelectModal";
|
||||
import { WeightCategory } from "@storyteller/components/src/api/_common/enums/WeightCategory";
|
||||
|
||||
import styleModels from "./dataStyleModels";
|
||||
import { defaultPreset as noStyleCNPreset } from "./dataCnPresets";
|
||||
|
||||
export default function CompStyleModal({
|
||||
debug,
|
||||
t,
|
||||
value,
|
||||
onChange,
|
||||
}: {
|
||||
debug?: boolean;
|
||||
t: Function;
|
||||
value: string;
|
||||
onChange: (val: {
|
||||
[key: string]:
|
||||
| number
|
||||
| string
|
||||
| boolean
|
||||
| undefined
|
||||
| { [key: string]: number | string };
|
||||
}) => void;
|
||||
}) {
|
||||
const gridContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
const [onSelectTimeStamp, setOnSelectTimeStamp] = useState<Date>(new Date());
|
||||
return (
|
||||
<SelectModalV2
|
||||
modalTitle={t("input.title.selectStyle")}
|
||||
label={t("input.label.selectStyle")}
|
||||
value={value}
|
||||
placeholder={t("input.placeholder.selectStyle")}
|
||||
forcedClose={onSelectTimeStamp}
|
||||
onClear={() =>
|
||||
onChange({
|
||||
sdModelToken: "",
|
||||
sdModelTitle: "",
|
||||
defaultCN: noStyleCNPreset,
|
||||
defaultPrompts: {
|
||||
positivePrompt: "",
|
||||
negativePrompt: "",
|
||||
positivePromptHidden: "",
|
||||
negativePromptHidden: "",
|
||||
},
|
||||
...noStyleCNPreset,
|
||||
positivePrompt: "",
|
||||
negativePrompt: "",
|
||||
positivePromptHidden: "",
|
||||
negativePromptHidden: "",
|
||||
})
|
||||
}
|
||||
>
|
||||
<MasonryGrid
|
||||
gridRef={gridContainerRef}
|
||||
onLayoutComplete={() => {
|
||||
if (debug) console.log("Layout complete!");
|
||||
}}
|
||||
>
|
||||
{styleModels.map((data: any, key: number) => {
|
||||
const weightProps: any = {
|
||||
data,
|
||||
type: "weights",
|
||||
inSelectModal: true,
|
||||
onResultSelect: (data: any) => {
|
||||
const selectedStyle = styleModels.find(
|
||||
styleItem => (styleItem.weight_token = data.token)
|
||||
);
|
||||
if (selectedStyle !== undefined) {
|
||||
onChange({
|
||||
sdModelToken: data.token,
|
||||
sdModelTitle: data.title,
|
||||
defaultCN: selectedStyle.defaultCN,
|
||||
defaultPrompts: selectedStyle.defaultPrompts,
|
||||
...selectedStyle.defaultCN,
|
||||
...selectedStyle.defaultPrompts,
|
||||
});
|
||||
setOnSelectTimeStamp(new Date());
|
||||
}
|
||||
},
|
||||
};
|
||||
//console.log(data);
|
||||
return (
|
||||
<div
|
||||
key={key}
|
||||
className="col-12 col-sm-6 col-lg-6 col-xl-4 col-xxl-3 grid-item"
|
||||
>
|
||||
<WeightsCards type={WeightCategory.SD} props={weightProps} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</MasonryGrid>
|
||||
</SelectModalV2>
|
||||
);
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
type CNPreset =
|
||||
'custom'|
|
||||
'closeup'|
|
||||
'default' |
|
||||
'halfbody'|
|
||||
'fullbody'|
|
||||
'landscape'|
|
||||
'typog';
|
||||
|
||||
const defaultPreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0,
|
||||
cnLineArtAnime: 0,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 0,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0,
|
||||
cnSoftEdge: 0,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
const closeupPreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 0,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0.7,
|
||||
cnSoftEdge: 0.7,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
const halfbodyPreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 0.7,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0,
|
||||
cnSoftEdge: 1,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
const fullbodyPreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 1,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0,
|
||||
cnSoftEdge: 1,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
const landscapePreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0.4,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 0,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0,
|
||||
cnSoftEdge: 0,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
const typogPreset = {
|
||||
cnCanny: 0,
|
||||
cnDepth: 0,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 0,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0,
|
||||
cnSoftEdge: 0.7,
|
||||
cnRegularSteps: 20,
|
||||
}
|
||||
|
||||
export type {
|
||||
CNPreset
|
||||
}
|
||||
export {
|
||||
defaultPreset,
|
||||
closeupPreset,
|
||||
halfbodyPreset,
|
||||
fullbodyPreset,
|
||||
landscapePreset,
|
||||
typogPreset,
|
||||
};
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
// import { defaultPreset as defaultCN } from "./dataCnPresets";
|
||||
import styleModels from "./dataStyleModels";
|
||||
import { VSTType } from "./helpers";
|
||||
export {initialValues, hiddenValues};
|
||||
|
||||
const initialValues: VSTType = {
|
||||
//files Settings
|
||||
fileToken: "",
|
||||
outputPath: "vid2vid/SparseUpscaleInterp_00001.mp4",
|
||||
|
||||
//video Settings
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
maxDuration: 0,
|
||||
trimStart: 0,
|
||||
trimEnd: 0,
|
||||
|
||||
//Presents
|
||||
workflowConfig: "weight_0a04e66y14t4e2bwxjfyg1mb2",
|
||||
sdModelToken: styleModels[0].weight_token,
|
||||
sdModelTitle: styleModels[0].title,
|
||||
// loraModelToken: "",
|
||||
// loraModelStrength: 0,
|
||||
|
||||
//basics
|
||||
inputFps: 24,
|
||||
...styleModels[0].defaultPrompts,
|
||||
// positivePrompt:"",
|
||||
// negativePrompt:"",
|
||||
// positivePromptHidden:"",
|
||||
// negativePromptHidden:"",
|
||||
visibility: "private",
|
||||
|
||||
//Control Net
|
||||
...styleModels[0].defaultCN,
|
||||
// cnCanny: 0,
|
||||
// cnDepth: 0,
|
||||
// cnLineArtAnime: 0,
|
||||
// cnLineArtRealistic: 0,
|
||||
// cnLipsStrength: 0,
|
||||
// cnOpenPose: 0,
|
||||
// cnPipeFace: 0,
|
||||
// cnSparseScribble: 0,
|
||||
// cnSoftEdge: 0,
|
||||
// cnRegularSteps: 0,
|
||||
|
||||
defaultCN:styleModels[0].defaultCN,
|
||||
defaultPrompts:styleModels[0].defaultPrompts,
|
||||
};
|
||||
|
||||
const hiddenValues = {
|
||||
posPrompt: "",
|
||||
negPrompt: "flare, lens flare, glare,naked, nsfw, text, logo, watermark:1.3, letterboxed,embedding:easynegative, embedding:badhandv4,(worst quality, low quality:1.4), lowres, blurry, monochrome, ",
|
||||
}
|
||||
-95
@@ -1,95 +0,0 @@
|
||||
const styleModels = [
|
||||
{
|
||||
"weight_token": "weight_yqexh77ntqyawzgh9fzash798",
|
||||
"weight_type": "sd_1.5",
|
||||
"weight_category": "image_generation",
|
||||
"title": "Flat2D Animerge v3",
|
||||
"maybe_cover_image_public_bucket_path": "/media/2/t/5/a/q/2t5aq2nvtdt4zcfvmx8xm6xqzg0tka7n/upload_2t5aq2nvtdt4zcfvmx8xm6xqzg0tka7n.png",
|
||||
"cover_image": {
|
||||
"maybe_cover_image_public_bucket_path": "/media/2/t/5/a/q/2t5aq2nvtdt4zcfvmx8xm6xqzg0tka7n/upload_2t5aq2nvtdt4zcfvmx8xm6xqzg0tka7n.png",
|
||||
"default_cover": {
|
||||
"image_index": 16,
|
||||
"color_index": 2
|
||||
}
|
||||
},
|
||||
"creator": {
|
||||
"user_token": "U:38X9ACM68GFK7",
|
||||
"username": "crossproduct1",
|
||||
"display_name": "crossproduct1",
|
||||
"gravatar_hash": "e7cc43eed149c304c917383c665fe9e2",
|
||||
"default_avatar": {
|
||||
"image_index": 4,
|
||||
"color_index": 8
|
||||
}
|
||||
},
|
||||
"creator_set_visibility": "public",
|
||||
"file_size_bytes": 0,
|
||||
"file_checksum_sha2": "5dd56bfa12e9ea2f1f3e86a04d0d2cde06a58f2cdf3bfc46cbff6aaa8f00921d",
|
||||
"creator_username": "crossproduct1",
|
||||
"creator_display_name": "crossproduct1",
|
||||
"creator_email_gravatar_hash": "e7cc43eed149c304c917383c665fe9e2",
|
||||
"stats": {
|
||||
"positive_rating_count": 2,
|
||||
"bookmark_count": 1
|
||||
},
|
||||
"created_at": "2024-02-28T21:00:43Z",
|
||||
"updated_at": "2024-02-28T21:00:43Z",
|
||||
defaultCN:{
|
||||
cnCanny: 0,
|
||||
cnDepth: 0,
|
||||
cnLineArtAnime: 0.7,
|
||||
cnLineArtRealistic: 0,
|
||||
cnLipsStrength: 0,
|
||||
cnOpenPose: 1,
|
||||
cnPipeFace: 0,
|
||||
cnSparseScribble: 0,
|
||||
cnSoftEdge: 1,
|
||||
cnRegularSteps: 20,
|
||||
},
|
||||
defaultPrompts:{
|
||||
positivePrompt:"perfect anime illustration,(best-quality:0.8),",
|
||||
negativePrompt:"",
|
||||
positivePromptHidden:"",
|
||||
negativePromptHidden:"flare, lens flare, glare,naked, nsfw, text, logo, watermark:1.3, letterboxed,embedding:easynegative, embedding:badhandv4,(worst quality, low quality:1.4), lowres, blurry, monochrome, ",
|
||||
}
|
||||
},
|
||||
// {
|
||||
// "weight_token": "weight_vbz0wq7wkv80casj3vfptrrpg",
|
||||
// "title": "Aniverse V15 Pruned",
|
||||
// "weight_type": "sd_1.5",
|
||||
// "weight_category": "image_generation",
|
||||
// "description_markdown": "Used In Ghibli Style with Ghubli Lora",
|
||||
// "description_rendered_html": "",
|
||||
// "creator": {
|
||||
// "user_token": "U:38X9ACM68GFK7",
|
||||
// "username": "crossproduct1",
|
||||
// "display_name": "crossproduct1",
|
||||
// "gravatar_hash": "e7cc43eed149c304c917383c665fe9e2",
|
||||
// "default_avatar": {
|
||||
// "image_index": 4,
|
||||
// "color_index": 8
|
||||
// }
|
||||
// },
|
||||
// "creator_set_visibility": "public",
|
||||
// "file_size_bytes": 0,
|
||||
// "file_checksum_sha2": "3335ce7830ff1de58ba1b120c91091935c8e84581244f63c94d01eeb53d42797",
|
||||
// "cover_image": {
|
||||
// "maybe_cover_image_public_bucket_path": "/media/3/x/5/z/5/3x5z550m80v7cz0x23jmb7aerbwasq71/upload_3x5z550m80v7cz0x23jmb7aerbwasq71.png",
|
||||
// "default_cover": {
|
||||
// "image_index": 1,
|
||||
// "color_index": 5
|
||||
// }
|
||||
// },
|
||||
// "maybe_cover_image_public_bucket_path": "/media/3/x/5/z/5/3x5z550m80v7cz0x23jmb7aerbwasq71/upload_3x5z550m80v7cz0x23jmb7aerbwasq71.png",
|
||||
// "stats": {
|
||||
// "positive_rating_count": 1,
|
||||
// "bookmark_count": 1
|
||||
// },
|
||||
// "version": 0,
|
||||
// "created_at": "2024-02-29T19:49:52Z",
|
||||
// "updated_at": "2024-02-29T19:49:52Z"
|
||||
// }
|
||||
]
|
||||
|
||||
export default styleModels;
|
||||
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
export type VSTType = {
|
||||
// File Settings
|
||||
fileToken: string;
|
||||
outputPath: string;
|
||||
// Video Settings
|
||||
width: number;
|
||||
height: number;
|
||||
maxDuration: number;
|
||||
trimStart: number;
|
||||
trimEnd: number;
|
||||
|
||||
// Presets
|
||||
workflowConfig: string;
|
||||
sdModelToken: string;
|
||||
sdModelTitle: string;
|
||||
// loraModelToken: string;
|
||||
// loraModelStrength: number;
|
||||
|
||||
//basics
|
||||
inputFps: number;
|
||||
positivePrompt: string;
|
||||
negativePrompt: string;
|
||||
positivePromptHidden:string,
|
||||
negativePromptHidden:string,
|
||||
visibility: string;
|
||||
|
||||
//advance
|
||||
cnCanny: number;
|
||||
cnDepth: number;
|
||||
cnLineArtAnime: number;
|
||||
cnLineArtRealistic: number;
|
||||
cnLipsStrength: number;
|
||||
cnOpenPose: number;
|
||||
cnPipeFace: number;
|
||||
cnSparseScribble: number;
|
||||
cnSoftEdge: number;
|
||||
cnRegularSteps: number
|
||||
|
||||
defaultCN: {
|
||||
cnCanny: number;
|
||||
cnDepth: number;
|
||||
cnLineArtAnime: number;
|
||||
cnLineArtRealistic: number;
|
||||
cnLipsStrength: number;
|
||||
cnOpenPose: number;
|
||||
cnPipeFace: number;
|
||||
cnSparseScribble: number;
|
||||
cnSoftEdge: number;
|
||||
cnRegularSteps: number
|
||||
},
|
||||
defaultPrompts:{
|
||||
positivePrompt:string,
|
||||
negativePrompt:string,
|
||||
positivePromptHidden:string,
|
||||
negativePromptHidden:string,
|
||||
}
|
||||
}
|
||||
|
||||
export function isInputValid(keyValues: {[key:string]:number|string|boolean|undefined}){
|
||||
return (
|
||||
keyValues.sdModelToken
|
||||
&& keyValues.sdModelToken !== ""
|
||||
&& keyValues.posPrompt
|
||||
&& keyValues.posPrompt !== ""
|
||||
);
|
||||
}
|
||||
|
||||
export function mapRequest(vstValues: VSTType){
|
||||
//TODO: improve the typing of this
|
||||
return{
|
||||
"uuid_idempotency_token": uuidv4(),
|
||||
"maybe_sd_model": vstValues.sdModelToken,
|
||||
"maybe_workflow_config":vstValues.workflowConfig,
|
||||
"maybe_input_file": vstValues.fileToken,
|
||||
"maybe_trim_start_seconds": vstValues.trimStart,
|
||||
"maybe_trim_end_seconds": vstValues.trimEnd,
|
||||
"maybe_output_path": vstValues.outputPath,
|
||||
"creator_set_visibility": vstValues.visibility,
|
||||
"maybe_json_modifications": {
|
||||
"$.154.inputs.Value": vstValues.inputFps,
|
||||
"$.510.inputs.Text":
|
||||
vstValues.positivePromptHidden + vstValues.positivePrompt,
|
||||
"$.8.inputs.text":
|
||||
vstValues.negativePromptHidden+ vstValues.negativePrompt,
|
||||
|
||||
"$.401.inputs.Value": 0.7, //Denoise First Pass
|
||||
"$.140.inputs.Value": 1, // Every nth frame
|
||||
"$.536.inputs.boolean_number": 1, // use LCM
|
||||
"$.1075.inputs.Value": 1280,
|
||||
"$.1076.inputs.Value": 720,
|
||||
"$.1079.inputs.Value": 1280,
|
||||
"$.1080.inputs.Value": 720,
|
||||
|
||||
"$.403.inputs.Value": vstValues.cnSparseScribble,
|
||||
"$.771.inputs.Value": vstValues.cnOpenPose,
|
||||
"$.772.inputs.Value": vstValues.cnDepth,
|
||||
"$.796.inputs.Value": vstValues.cnLineArtRealistic,
|
||||
"$.797.inputs.Value": vstValues.cnLineArtAnime,
|
||||
"$.1398.inputs.Value": vstValues.cnSoftEdge,
|
||||
"$.1531.inputs.Value": vstValues.cnRegularSteps,
|
||||
|
||||
//"$.800.inputs.Value": 0, // vstValues.cnCanny,
|
||||
//"$.1636.inputs.Value": 0, //vstValues.cnLipsStrength,
|
||||
|
||||
// "$.208.inputs.lora_01": vstValues.loraModelToken,
|
||||
// "$.208.inputs.strength_01": vstValues.loraModelStrength
|
||||
// "$.1449.inputs.filename_prefix": "vid2vid/SparseUpscaleInterp",
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
export { default } from "./pageVSTApp";
|
||||
-160
@@ -1,160 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import { useParams, useHistory } from "react-router-dom";
|
||||
|
||||
import { Button, Panel, TextArea } from "components/common";
|
||||
import {VideoPlayerQuickTrim} from "components/common/VideoPlayerQuickTrim";
|
||||
import EnqueueVideoStyleTransfer from "@storyteller/components/src/api/video_styleTransfer";
|
||||
|
||||
import { Action, State } from "../../reducer";
|
||||
import { initialValues } from "./dataDefaultValues";
|
||||
import { mapRequest, VSTType } from "./helpers";
|
||||
|
||||
import CompStyleModal from "./compStyleModal";
|
||||
import CompAdvanceOptions from "./compAdvanceOptions";
|
||||
import { CompAdminPanel } from "./compAdminPanel";
|
||||
|
||||
export default function PageVSTApp({
|
||||
debug: debugProps,
|
||||
t,
|
||||
pageState,
|
||||
dispatchPageState,
|
||||
parentPath,
|
||||
}: {
|
||||
debug?: boolean;
|
||||
t: Function;
|
||||
pageState: State;
|
||||
parentPath: string;
|
||||
dispatchPageState: (action: Action) => void;
|
||||
}) {
|
||||
const debug = debugProps || true;
|
||||
const { mediaToken } = useParams<any>();
|
||||
|
||||
const [vstValues, setVstValues] = useState<VSTType>({
|
||||
...initialValues,
|
||||
fileToken: pageState.mediaFileToken || mediaToken,
|
||||
});
|
||||
|
||||
const handleOnChange = (val: {
|
||||
[key: string]:
|
||||
number |
|
||||
string |
|
||||
boolean |
|
||||
undefined |
|
||||
{[key: string]: number | string}
|
||||
;
|
||||
}) => {
|
||||
setVstValues(curr => ({ ...curr, ...val }));
|
||||
};
|
||||
|
||||
const history = useHistory();
|
||||
const handleGenerate = () => {
|
||||
if (debug) console.log(vstValues);
|
||||
|
||||
const request = mapRequest(vstValues);
|
||||
if (debug) console.log(request);
|
||||
EnqueueVideoStyleTransfer(request).then(res => {
|
||||
if (res.success && res.inference_job_token) {
|
||||
dispatchPageState({
|
||||
type: "enqueueJobSuccess",
|
||||
payload: {
|
||||
inferenceJobToken: res.inference_job_token,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
console.log(res);
|
||||
}
|
||||
});
|
||||
dispatchPageState({ type: "enqueueJob" });
|
||||
history.push(`${parentPath}/jobs`);
|
||||
};
|
||||
|
||||
return (
|
||||
<Panel padding={true}>
|
||||
<div className="row g-5 mb-4">
|
||||
<div className="col-12 col-md-6">
|
||||
<VideoPlayerQuickTrim
|
||||
trimStartMs={vstValues.trimStart}
|
||||
trimEndMs={vstValues.trimEnd}
|
||||
mediaToken={vstValues.fileToken}
|
||||
onSelectTrim={(val: {
|
||||
trimStartMs: number;
|
||||
trimEndMs: number;
|
||||
}) =>{
|
||||
handleOnChange({
|
||||
trimStart: val.trimStartMs,
|
||||
trimEnd: val.trimEndMs,
|
||||
})
|
||||
}}
|
||||
onResponse={res => {
|
||||
dispatchPageState({
|
||||
type: "loadFileSuccess",
|
||||
payload: {
|
||||
mediaFile: res,
|
||||
mediaFileToken: pageState.mediaFileToken || mediaToken,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-12 col-md-6 d-flex flex-column gap-3">
|
||||
<TextArea
|
||||
{...{
|
||||
label: t("input.label.prompt"),
|
||||
placeholder: t("input.placeholder.prompt"),
|
||||
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) =>
|
||||
handleOnChange({ posPrompt: e.target.value }),
|
||||
value: vstValues.positivePrompt,
|
||||
required: false,
|
||||
}}
|
||||
/>
|
||||
<TextArea
|
||||
{...{
|
||||
label: t("input.label.negPrompt"),
|
||||
placeholder: t("input.placeholder.negPrompt"),
|
||||
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) =>
|
||||
handleOnChange({ negPrompt: e.target.value }),
|
||||
value: vstValues.negativePrompt,
|
||||
required: false,
|
||||
}}
|
||||
/>
|
||||
|
||||
<CompStyleModal
|
||||
debug={debug}
|
||||
t={t}
|
||||
value={vstValues.sdModelTitle}
|
||||
onChange={handleOnChange}
|
||||
/>
|
||||
<CompAdvanceOptions
|
||||
debug={debug}
|
||||
t={t}
|
||||
currDefaultCN={vstValues.defaultCN}
|
||||
onChange={handleOnChange}
|
||||
vstValues={vstValues}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row g-3 mt-4">
|
||||
<div className="col-12 d-flex justify-content-between">
|
||||
<NavLink to={`${parentPath}`}>
|
||||
<Button label={t("button.cancel")} variant="secondary" />
|
||||
</NavLink>
|
||||
<Button
|
||||
label={t("button.enqueue")}
|
||||
onClick={handleGenerate}
|
||||
variant="primary"
|
||||
disabled={vstValues.trimEnd === 0}
|
||||
/>
|
||||
</div>
|
||||
{debug &&
|
||||
<CompAdminPanel
|
||||
parentPath={parentPath}
|
||||
dispatchPageState={dispatchPageState}
|
||||
vstValues={vstValues}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import InferenceJobsList from "components/layout/InferenceJobsList";
|
||||
import { Analytics } from "common/Analytics";
|
||||
import { inferenceFailures } from "../commons";
|
||||
|
||||
import { Panel, Tabs } from "components/common";
|
||||
|
||||
import { State, Action } from "../reducer";
|
||||
import TabContentUpload from "./tabContentUpload";
|
||||
import TabContentLibrary from "./tabContentLibrary";
|
||||
|
||||
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>
|
||||
<InferenceJobsList
|
||||
{...{
|
||||
showNoJobs: false,
|
||||
failures: inferenceFailures,
|
||||
onSelect: () => Analytics.voiceConversionClickDownload(),
|
||||
jobType: FrontendInferenceJobType.VideoStyleTransfer,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
import React from "react";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import { states, Action, State } from "../reducer";
|
||||
import { Button } from "components/common";
|
||||
import { SelectModalVideoTabs, SelectModalData } from "components/common/";
|
||||
import VideoFakeyou from "components/common/VideoFakeyou";
|
||||
|
||||
export default function TabContentLibrary({
|
||||
t, pageState, dispatchPageState
|
||||
}: {
|
||||
t: Function;
|
||||
pageState: State;
|
||||
dispatchPageState: (action: Action) => void;
|
||||
}){
|
||||
console.log(`Tab Rerender, selected: ${pageState.mediaFileToken}`);
|
||||
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">
|
||||
<SelectModalVideoTabs
|
||||
value={pageState.mediaFileToken}
|
||||
modalTitle="Select a Video"
|
||||
inputLabel="Select a Video"
|
||||
onSelect={handleOnSelect}
|
||||
/>
|
||||
<br/>
|
||||
{pageState.mediaFileToken &&
|
||||
<VideoFakeyou
|
||||
height={500}
|
||||
mediaToken={pageState.mediaFileToken}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
{pageState.status === states.FILE_SELECTED &&
|
||||
<div className="col-12 d-flex justify-content-center mt-4">
|
||||
<NavLink to={`load/${pageState.mediaFileToken}`}>
|
||||
<Button
|
||||
label={t("button.proceed")}
|
||||
onClick={handleProceed}
|
||||
/>
|
||||
</NavLink>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
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 />;
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
export {default} from "./VideoStyleTransfer";
|
||||
@@ -1,86 +0,0 @@
|
||||
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,
|
||||
JOB_ENQUEUEING,
|
||||
JOB_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: 'enqueueJob'}
|
||||
| {type: 'enqueueJobSuccess', 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 'enqueueJob':
|
||||
return {
|
||||
...state,
|
||||
status: states.JOB_ENQUEUEING
|
||||
}
|
||||
case 'enqueueJobSuccess':
|
||||
return {
|
||||
...state,
|
||||
status: states.JOB_ENQUEUED,
|
||||
inferenceJobToken: action.payload.inferenceJobToken
|
||||
}
|
||||
case 'reset':
|
||||
default:
|
||||
return {status: states.NO_FILE};
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import React from "react";
|
||||
import {Switch, Route, useRouteMatch, Redirect, useHistory} from "react-router-dom";
|
||||
import PageVSTApp from "./components/pageVSTApp";
|
||||
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`} >
|
||||
<PageVSTApp {...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>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user