resolve merge conflicts

This commit is contained in:
wil committed 2024-02-29 10:25:01 -05:00
commit eb345128da
16 files changed
+946 -86

No files matched your search

@@ -2,18 +2,23 @@ import React from "react";
interface LoadingSpinnerProps {
className?: string;
label?: string;
}
export default function LoadingSpinner({ className }: LoadingSpinnerProps) {
export default function LoadingSpinner({
className,
label,
}: LoadingSpinnerProps) {
return (
<div
className={`pt-2 d-flex justify-content-center overflow-hidden ${
className={`pt-2 d-flex justify-content-center align-items-center overflow-hidden gap-3 ${
className ? className : ""
}`.trim()}
>
<div className="spinner-border text-light" role="status">
<span className="visually-hidden">Loading...</span>
</div>
{label && <div className="fw-medium">{label}</div>}
</div>
);
}
@@ -11,3 +11,9 @@
width: 100%;
border-radius: 0.5rem;
}
.fy-scene-3d-fullscreen-intro {
height: calc(100vh - 66px - 66px);
width: 100%;
border-radius: 0rem;
}
@@ -12,6 +12,7 @@ interface Scene3DProps {
urlParams?: string;
objectId?: string;
sceneMediaFileToken?: string;
className?: string;
}
export default function Scene3D({
@@ -20,8 +21,8 @@ export default function Scene3D({
objectId,
sceneMediaFileToken,
urlParams,
className,
}: Scene3DProps) {
let engineUrl = `https://engine.fakeyou.com?mode=${mode}`;
if (sceneMediaFileToken) {
@@ -35,14 +36,9 @@ export default function Scene3D({
<div
className={`${
fullScreen ? "fy-scene-3d-fullscreen" : "fy-scene-3d-default"
}`.trim()}
} ${className ? className : ""}`.trim()}
>
<IframeResizer
src={engineUrl}
width="100%"
height="100%"
id=""
/>
<IframeResizer src={engineUrl} width="100%" height="100%" id="" />
</div>
);
}
@@ -12,13 +12,9 @@ import {
faPause,
faVolume,
faVolumeSlash,
} from "@fortawesome/pro-solid-svg-icons"
} from "@fortawesome/pro-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
Button,
SelectionBubbles,
VideoFakeyou
} from "components/common";
import { Button, SelectionBubbles, VideoFakeyou } from "components/common";
import { VideoFakeyouProps } from "../VideoFakeyou/VideoFakeyou";
import { QuickTrimData, TrimStates, PlaybarStates } from "./types";
@@ -26,35 +22,35 @@ import { formatSecondsToHHMMSSCS } from "./helpers";
import TrimScrbber from "./TrimScrubber";
import './styles.scss'
interface VideoQuickTrimProps extends VideoFakeyouProps{
onSelect: (values: QuickTrimData)=>void;
interface VideoQuickTrimProps extends VideoFakeyouProps {
onSelect: (values: QuickTrimData) => void;
}
const trimOptions: { [key: string]: number } = {
"3s": 3,
"5s": 5,
"10s": 10,
"15s" : 15,
"15s": 15,
};
const initialTrimState:TrimStates = {
const initialTrimState: TrimStates = {
canNotTrim: true,
isScrubbingTrim: false,
trimDuration: 0,
trimStart: 0,
trimEnd: 0,
maxDuration: 0,
}
};
const initialPlaybarState:PlaybarStates = {
const initialPlaybarState: PlaybarStates = {
playbarWidth: 0,
timeCursorOffset: 0,
}
};
export default memo(function VideoQuickTrim({
onSelect,
...rest
}: VideoQuickTrimProps){
}: VideoQuickTrimProps) {
// console.log("VideoQuickTrim Rerender!!");
const videoRef = useRef<HTMLVideoElement | null>(null);
@@ -120,29 +116,30 @@ export default memo(function VideoQuickTrim({
}, [playbarWidth, onSelect, isRepeatOn, trimEnd]); //END videoRefCallback
function handleWindowResize() {
if(playbarRef.current !== null){
if (playbarRef.current !== null) {
const newWidth = playbarRef.current.getBoundingClientRect().width;
setPlaybarState((curr)=>({
setPlaybarState(curr => ({
playbarWidth: newWidth,
timeCursorOffset: (curr.timeCursorOffset / (curr.playbarWidth-8)) * (newWidth-8)
timeCursorOffset:
(curr.timeCursorOffset / (curr.playbarWidth - 8)) * (newWidth - 8),
}));
}
}
const playbarRefCallback = useCallback(node => {
if(node !== null) {
if (node !== null) {
playbarRef.current = node;
setPlaybarState((curr)=>({
setPlaybarState(curr => ({
...curr,
playbarWidth: node.getBoundingClientRect().width
playbarWidth: node.getBoundingClientRect().width,
}));
}
}, []);
useLayoutEffect(()=>{
window.addEventListener('resize', handleWindowResize);
useLayoutEffect(() => {
window.addEventListener("resize", handleWindowResize);
return () => {
window.removeEventListener('resize', handleWindowResize);
window.removeEventListener("resize", handleWindowResize);
};
},[]);
}, []);
const handleChangeTrimDuration = (selected: string) =>{
if(!canNotTrim){
@@ -171,7 +168,7 @@ export default memo(function VideoQuickTrim({
}else{
videoRef.current?.pause();
}
}
};
const trimScrubberWidth = videoRef.current
? trimDuration > 0 && trimDuration < videoRef.current.duration
@@ -190,24 +187,29 @@ export default memo(function VideoQuickTrim({
/>
<div className="playpause-overlay" onClick={handlePlaypause}>
{playpause === 'paused' &&
<FontAwesomeIcon className="playpause-icon"
icon={faPlay} size="8x"
{playpause === "paused" && (
<FontAwesomeIcon
className="playpause-icon"
icon={faPlay}
size="8x"
/>
}
{playpause === 'playing' &&
<FontAwesomeIcon className="playpause-icon"
icon={faPause} size="8x"
)}
{playpause === "playing" && (
<FontAwesomeIcon
className="playpause-icon"
icon={faPause}
size="8x"
/>
}
)}
</div>
{videoRef.current && canNotTrim &&
{videoRef.current && canNotTrim && (
<div className="warning-too-short">
<div className="background"></div>
<p>Warning: Sorry Your Video is TOO Short</p>
</div>
}
</div>{/* END of Video Wrapper */}
)}
</div>
{/* END of Video Wrapper */}
<div className="playbar" ref={playbarRefCallback}>
<div className="playbar-bg" />
<TrimScrbber width={trimScrubberWidth} />
@@ -218,7 +220,7 @@ export default memo(function VideoQuickTrim({
<div className="playpause-external d-flex align-items-center flex-wrap mb-2">
<Button
className="button-playpause"
icon={playpause === 'playing' ? faPause : faPlay}
icon={playpause === "playing" ? faPause : faPlay}
variant="secondary"
onClick={handlePlaypause}
/>
@@ -232,12 +234,14 @@ export default memo(function VideoQuickTrim({
className="button-mute"
icon={isMuted ? faVolumeSlash : faVolume}
variant="secondary"
onClick={()=>setIsMuted((curr)=>(!curr))}
onClick={() => setIsMuted(curr => !curr)}
/>
<div className="playtime d-flex">
<span >
<p>
{`${formatSecondsToHHMMSSCS(videoRef.current?.currentTime || 0)}`}
{`${formatSecondsToHHMMSSCS(
videoRef.current?.currentTime || 0
)}`}
</p>
</span>
<div>/</div>
@@ -251,6 +255,7 @@ export default memo(function VideoQuickTrim({
<SelectionBubbles
options={Object.keys(trimOptions)}
onSelect={handleChangeTrimDuration}
selectedStyle="outline"
/>
</div>
</div>
@@ -3,7 +3,7 @@
$playbar-height: 2rem;
.fy-video-quicktrim {
.video-wrapper{
.video-wrapper {
position: relative;
background-color: $bg;
border-radius: 0.5rem 0.5rem 0 0;
@@ -11,71 +11,76 @@ $playbar-height: 2rem;
border-left: $panel-inner-border 1px solid;
border-right: $panel-inner-border 1px solid;
}
.fy-video{
height: 500px;
.fy-video {
max-height: 500px;
margin-bottom: -7px;
video {
border-radius: 0.5rem 0.5rem 0 0;
}
}
.playpause-overlay{
.playpause-overlay {
position: absolute;
cursor: pointer;
height: 100%;
width: 100%;
top:0;
left:0;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
svg{
svg {
opacity: 0;
transition: opacity 0.5s;
transition: opacity 0.5s;
}
&:hover svg{
&:hover svg {
opacity: 1;
}
}
.warning-too-short{
.warning-too-short {
position: absolute;
height: 100%;
width: 100%;
top:0;
left:0;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
div{
div {
position: absolute;
height: 100%;
width: 100%;
top:0;
left:0;
top: 0;
left: 0;
background-color: #e66462;
opacity: 70%;
}
p{
p {
position: absolute;
margin-top: 230px;
width: 100%;
top:0;
top: 0;
}
}
.playbar{
position:relative;
.playbar {
position: relative;
height: $playbar-height;
width: 100%;
}
.playbar-bg{
.playbar-bg {
position: absolute;
height: 100%;
width: 100%;
top:0;
top: 0;
left: 0;
background-color: $panel-inner-border;
border-radius: 0 0 0.5rem 0.5rem;
}
.trim-scrubber{
position: absolute;
top:-1rem;
top: -1rem;
height: 3rem;
background-color: #e66462;
opacity: 0.8;
@@ -92,16 +97,16 @@ $playbar-height: 2rem;
color: $panel-inner-border;
}
}
.playcursor{
.playcursor {
position: absolute;
top:0;
top: 0;
width: 0.5rem;
height: $playbar-height;
background-color: $white;
}
.playpause-external{
.button-playpause{
.playpause-external {
.button-playpause {
width: 55px;
height: 40px;
margin-right: 0.5rem;
@@ -116,7 +121,7 @@ $playbar-height: 2rem;
span{
width: 50px;
}
div{
div {
width: 10px;
margin-left: 3px;
margin-right: 5px;
@@ -124,4 +129,4 @@ $playbar-height: 2rem;
}
}
}
}
}
@@ -24,6 +24,7 @@ const resultPaths = {
EngineComposition: "/media",
FaceAnimation: "/media",
TextToSpeech: "/media",
VideoStyleTransfer: "/media",
VoiceConversion: "/media",
VoiceDesignerCreateVoice: "/voice-designer/voice",
VoiceDesignerTts: "/media",
@@ -123,6 +123,9 @@ import TextToImagePage from "./pages/text_to_image/TextToImagePage";
import DomainConfigProvider from "context/DomainConfigContext";
import DevUpload from "./pages/dev_upload/DevUpload";
import DevMediaInput from "./pages/dev_upload/DevMediaInput";
import { StudioIntroPage } from "./pages/storyteller_studio_intro/StudioIntroPage";
import StudioVSTPage from "./pages/storyteller_studio_intro/StudioVST/StudioVSTPage";
import { StudioIntroResultPage } from "./pages/storyteller_studio_intro/StudioIntroResultPage";
interface Props {
sessionWrapper: SessionWrapper;
@@ -755,6 +758,28 @@ class PageContainer extends React.Component<
/>
</Route>
<Route path="/studio-intro/result/:jobToken?">
<StudioIntroResultPage
sessionWrapper={this.props.sessionWrapper}
sessionSubscriptionsWrapper={
this.props.sessionSubscriptionsWrapper
}
/>
</Route>
<Route path="/studio-intro/style/:jobToken?">
<StudioVSTPage />
</Route>
<Route path="/studio-intro/:mediaToken?">
<StudioIntroPage
sessionWrapper={this.props.sessionWrapper}
sessionSubscriptionsWrapper={
this.props.sessionSubscriptionsWrapper
}
/>
</Route>
<Route path="/commissions">
<CommunityCommissionsPage />
</Route>
@@ -783,6 +808,11 @@ class PageContainer extends React.Component<
<DevMediaInput />
</Route>
{
// <Route path="/dev-tts">
// <DevTTS />
// </Route>
}
{/* Route for initial voice creation */}
<Route exact path="/voice-designer/create">
<VoiceDesignerFormPage
@@ -1309,15 +1339,6 @@ class PageContainer extends React.Component<
/>
</Route>
<Route path="/studio">
<StorytellerStudioListPage
sessionWrapper={this.props.sessionWrapper}
sessionSubscriptionsWrapper={
this.props.sessionSubscriptionsWrapper
}
/>
</Route>
<Route path="/commissions">
<CommunityCommissionsPage />
</Route>
@@ -0,0 +1,9 @@
.studio-intro-page {
display: flex;
flex-direction: column;
height: calc(100vh - 66px);
}
.result-video-wrapper {
max-width: 1100px;
}
@@ -0,0 +1,72 @@
import React 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, Scene3D } 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";
interface Props {
sessionWrapper: SessionWrapper;
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
}
function StudioIntroPage(props: Props) {
const { mediaToken } = useParams<{ mediaToken: string }>();
const history = useHistory();
const inferenceJobs = useInferenceJobs(
FrontendInferenceJobType.EngineComposition
);
usePrefixedDocumentTitle("Storyteller Studio");
if (!props.sessionWrapper.canAccessStudio()) {
return <StudioNotAvailable />;
}
let engineParams = {};
if (mediaToken) {
engineParams = {
sceneMediaFileToken: mediaToken,
};
} else {
engineParams = {
objectId: "sample-room.gltf",
};
}
const onClick = () => {
// This opens the job modal. Needs to be disabled.
EnqueueEngineCompositing("", {
uuid_idempotency_token: uuidv4(),
media_file_token: mediaToken || "",
}).then((res: any) => {
if (res && res.success) {
inferenceJobs.enqueue(res.inference_job_token);
history.push(`/studio-intro/style/${res.inference_job_token}`);
}
});
};
return (
<div className="studio-intro-page">
<Scene3D
fullScreen={true}
mode="studio"
className="flex-grow-1"
{...engineParams}
/>
<div className="d-flex justify-content-center p-3">
<Button label="Create Movie from 3D Scene" onClick={onClick} />
</div>
</div>
);
}
export { StudioIntroPage };
@@ -0,0 +1,79 @@
import React, { 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 } from "hooks";
import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
import { MediaFileType } from "@storyteller/components/src/api/media_files";
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 { jobToken } = useParams<{ jobToken: string }>();
const history = useHistory();
const [mediaToken, setMediaToken] = useState(
"m_f5kp3hm74qeq16eq7536jb73jkbvkh"
); // Set the media token after polling success
// const [jobExists, setJobExists] = useState<boolean | null>(null);
const [mediaFile, setMediaFile] = useState<MediaFileType>();
useMedia({
mediaToken: mediaToken,
onSuccess: (res: any) => {
setMediaFile(res);
},
});
const mediaLink =
mediaFile && new BucketConfig().getGcsUrl(mediaFile.public_bucket_path);
usePrefixedDocumentTitle("Storyteller Studio");
if (!jobToken) {
history.push("/");
}
// 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">
{mediaToken ? (
<video src={mediaLink} controls />
) : (
<LoadingSpinner label="Generating your movie..." />
)}
</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 };
@@ -0,0 +1,161 @@
import React, { useRef, useState } from "react";
import { NavLink, useParams, useHistory } from "react-router-dom";
import {
Button,
Container,
Panel,
SelectionBubbles,
TextArea,
} from "components/common";
import VideoQuickTrim, {
QuickTrimData,
} from "components/common/VideoQuickTrim";
import EnqueueVideoStyleTransfer from "@storyteller/components/src/api/video_styleTransfer";
import { initialValues } from "./defaultValues";
import { mapRequest, VSTType } from "./helpers";
import LoadingSpinner from "components/common/LoadingSpinner";
// import SectionAdvanceOptions from "./sectionAdvanceOptions";
export default function PageVSTApp() {
const { jobToken } = useParams<{ jobToken: string }>();
const videoRef = useRef<HTMLVideoElement>(null);
const history = useHistory();
const [mediaToken, setMediaToken] = useState(
"m_wnnz9jey96dwhss9qk1891v9gmvnj8" // Currently hardcoded video media token value. Let a job polling function set the value when job returns media on success.
);
// const [jobExists, setJobExists] = useState<boolean | null>(null);
const [vstValues, setVstValues] = useState<VSTType>({
...initialValues,
fileToken: mediaToken,
});
const handleOnChange = (val: {
[key: string]: number | string | boolean | undefined;
}) => {
setVstValues(curr => ({ ...curr, ...val }));
};
const handleGenerate = () => {
const request = mapRequest(vstValues);
EnqueueVideoStyleTransfer(request).then(res => {
if (res.success && res.inference_job_token) {
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 styleMap: { [key: string]: string } = {
Anime: "weight_yqexh77ntqyawzgh9fzash798", // set SD Model Weight Tokens, currently hardcoded all to Anime style
Pixel: "weight_yqexh77ntqyawzgh9fzash798",
Painting: "weight_yqexh77ntqyawzgh9fzash798",
};
const handleStyleSelection = (selected: string) => {
const selectedSdModelToken = styleMap[selected];
setVstValues(curr => ({ ...curr, sdModelToken: selectedSdModelToken }));
};
const styleOptions = Object.keys(styleMap);
if (!jobToken) {
history.push("/");
}
// Should also check if job actually exists or not
//
// if (!jobExists) {
// history.push("/");
// }
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">
{vstValues.fileToken ? (
<VideoQuickTrim
mediaToken={vstValues.fileToken}
onSelect={(val: QuickTrimData) =>
handleOnChange({
trimStart: val.trimStartSeconds,
trimEnd: val.trimEndSeconds,
})
}
/>
) : (
<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>
<SelectionBubbles
options={styleOptions}
onSelect={handleStyleSelection}
selectedStyle="outline"
/>
</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={!vstValues.fileToken}
/>
</div>
</div>
</div>
</Panel>
</Container>
);
}
@@ -0,0 +1,98 @@
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,
};
@@ -0,0 +1,36 @@
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: 0,
//Presents
workflowConfig: "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, ",
};
@@ -0,0 +1,92 @@
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": 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":
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",
},
}
}
@@ -0,0 +1 @@
export { default } from "./StudioVSTPage";
@@ -0,0 +1,273 @@
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> */}
</>
);
}