diff --git a/packages/components/src/api/ApiConfig.ts b/packages/components/src/api/ApiConfig.ts index 59df11f2ba..42c934ed21 100644 --- a/packages/components/src/api/ApiConfig.ts +++ b/packages/components/src/api/ApiConfig.ts @@ -496,8 +496,8 @@ class ApiConfig { return `${this.getApiOrigin()}/v1/mocap/mocapnet/create`; } - // =============== Storyteller Filter =============== - enqueueStorytellerFilter(): string { + // =============== Video Workflow =============== + enqueueVideoWorkflow(): string { return `${this.getApiOrigin()}/v1/workflow/comfy/create`; } diff --git a/packages/components/src/api/session/GetSessionInfo.ts b/packages/components/src/api/session/GetSessionInfo.ts index 1b9d8ea1a8..f9bade4f3c 100644 --- a/packages/components/src/api/session/GetSessionInfo.ts +++ b/packages/components/src/api/session/GetSessionInfo.ts @@ -18,6 +18,9 @@ export interface UserInfo { display_name: string, email_gravatar_hash: string, + // Rollout feature flags + can_access_studio: boolean, + // Usage can_use_tts: boolean, can_use_w2l: boolean, diff --git a/packages/components/src/api/storyteller_filter/index.ts b/packages/components/src/api/storyteller_filter/index.ts deleted file mode 100644 index aebe56e156..0000000000 --- a/packages/components/src/api/storyteller_filter/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type { - EnqueueStorytellerFilterRequest, EnqueueStorytellerFilterResponse, -} from './EnqueueStorytellerFilter'; - -export { - EnqueueStorytellerFilter -} from './EnqueueStorytellerFilter'; \ No newline at end of file diff --git a/packages/components/src/api/storyteller_filter/EnqueueStorytellerFilter.tsx b/packages/components/src/api/video_workflow/EnqueueVideoWorkflow.tsx similarity index 83% rename from packages/components/src/api/storyteller_filter/EnqueueStorytellerFilter.tsx rename to packages/components/src/api/video_workflow/EnqueueVideoWorkflow.tsx index 1da9000fc3..db261cff39 100644 --- a/packages/components/src/api/storyteller_filter/EnqueueStorytellerFilter.tsx +++ b/packages/components/src/api/video_workflow/EnqueueVideoWorkflow.tsx @@ -1,6 +1,6 @@ import { ApiConfig } from "@storyteller/components"; -export interface EnqueueStorytellerFilterRequest { +export interface EnqueueVideoWorkflowRequest { "uuid_idempotency_token": string, "maybe_sd_model": string, @@ -29,16 +29,16 @@ export interface EnqueueStorytellerFilterRequest { } } -export interface EnqueueStorytellerFilterResponse { +export interface EnqueueVideoWorkflowResponse { success: boolean, inference_job_token?: string, } -export async function EnqueueStorytellerFilter(request: EnqueueStorytellerFilterRequest) : Promise +export async function EnqueueVideoWorkflow(request: EnqueueVideoWorkflowRequest) : Promise { // const endpoint = "/v1/workflow/comfy/create"; - const endpoint = new ApiConfig().enqueueStorytellerFilter(); + const endpoint = new ApiConfig().enqueueVideoWorkflow(); return await fetch(endpoint, { method: 'POST', diff --git a/packages/components/src/api/video_workflow/index.ts b/packages/components/src/api/video_workflow/index.ts new file mode 100644 index 0000000000..6c3f2ee01b --- /dev/null +++ b/packages/components/src/api/video_workflow/index.ts @@ -0,0 +1,7 @@ +export type { + EnqueueVideoWorkflowRequest, EnqueueVideoWorkflowResponse, +} from './EnqueueVideoWorkflow'; + +export { + EnqueueVideoWorkflow +} from './EnqueueVideoWorkflow'; \ No newline at end of file diff --git a/packages/components/src/jobs/InferenceJob.ts b/packages/components/src/jobs/InferenceJob.ts index 88388e07b2..4ff6ad37db 100644 --- a/packages/components/src/jobs/InferenceJob.ts +++ b/packages/components/src/jobs/InferenceJob.ts @@ -12,7 +12,7 @@ export enum FrontendInferenceJobType { VideoMotionCapture, ConvertFbxtoGltf, EngineComposition, - StorytellerFilter, + VideoWorkflow, } // NB: Many of these fields are optional despite the response payload containing them diff --git a/packages/components/src/session/SessionWrapper.ts b/packages/components/src/session/SessionWrapper.ts index 0e9cc9c14e..33b8c5d2e6 100644 --- a/packages/components/src/session/SessionWrapper.ts +++ b/packages/components/src/session/SessionWrapper.ts @@ -1,4 +1,5 @@ import { GetSessionInfo, GetSessionInfoIsOk, SessionInfoSuccessResponse } from '../api/session/GetSessionInfo' +import { StudioRolloutHostnameAllowed } from '../utils/StudioRolloutHostnameAllowed'; // A lot of the APIs return null or leave values absent. // I need to pick a single strategy and stick with it. @@ -44,6 +45,14 @@ export class SessionWrapper { return this.sessionStateResponse?.logged_in || false; } + // Feature flag rollout for Storyteller Studio + // This depends on the domain name and the backend. + public canAccessStudio() : boolean { + const hostnameAllowed = StudioRolloutHostnameAllowed(); + const userAllowed = this.sessionStateResponse?.user?.can_access_studio || false; + return hostnameAllowed && userAllowed; + } + // Username is all lowercase public getUsername() : string | undefined { return this.sessionStateResponse?.user?.username; diff --git a/packages/components/src/utils/StudioRolloutHostnameAllowed.ts b/packages/components/src/utils/StudioRolloutHostnameAllowed.ts new file mode 100644 index 0000000000..e98bfd83b9 --- /dev/null +++ b/packages/components/src/utils/StudioRolloutHostnameAllowed.ts @@ -0,0 +1,19 @@ + +// Check if hostname is allowed to display studio features. +// This should allow more frequently landing against production. +export function StudioRolloutHostnameAllowed() : boolean { + const allowed = StudioRolloutHostnameCheck(); + return allowed; +} + +function StudioRolloutHostnameCheck() : boolean { + // Do not allow "production" or "staging" domains to use studio yet. + // Other domains (local development and feature branches) are allowed. + switch (window.location.hostname) { + case 'fakeyou.com': + case 'storyteller.ai': + return false; + default: + return true; + } +} diff --git a/packages/fakeyou.com/src/App.tsx b/packages/fakeyou.com/src/App.tsx index e6b7de0e21..1eaa81b114 100644 --- a/packages/fakeyou.com/src/App.tsx +++ b/packages/fakeyou.com/src/App.tsx @@ -210,7 +210,7 @@ function initInferenceJobsByCategoryMap(): Map< inferenceJobsByCategory.set(FrontendInferenceJobType.VideoMotionCapture, []); inferenceJobsByCategory.set(FrontendInferenceJobType.ImageGeneration, []); inferenceJobsByCategory.set(FrontendInferenceJobType.ConvertFbxtoGltf, []); - inferenceJobsByCategory.set(FrontendInferenceJobType.StorytellerFilter, []) + inferenceJobsByCategory.set(FrontendInferenceJobType.VideoWorkflow, []) return inferenceJobsByCategory; } diff --git a/packages/fakeyou.com/src/components/common/BasicVideo/BasicVideo.tsx b/packages/fakeyou.com/src/components/common/BasicVideo/BasicVideo.tsx index dbc74d9aba..619a2ce4be 100644 --- a/packages/fakeyou.com/src/components/common/BasicVideo/BasicVideo.tsx +++ b/packages/fakeyou.com/src/components/common/BasicVideo/BasicVideo.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, forwardRef } from "react"; import { a, useSpring } from "@react-spring/web"; import { useVideo } from "hooks"; import makeClass from "resources/makeClass"; @@ -13,12 +13,12 @@ interface Props { description?: string; } -export default function BasicVideo({ +export default forwardRef(function BasicVideo({ className, src, title, - description -}: Props) { + description, +}: Props, ref:React.ForwardedRef) { const [tint,tintSet] = useState(true); const [{ playCtrl },vidProps] = useVideo({ onEnded: () => tintSet(true) }); const style = useSpring({ @@ -31,7 +31,7 @@ export default function BasicVideo({ }; return
-
; -}; \ No newline at end of file +}); \ No newline at end of file diff --git a/packages/fakeyou.com/src/components/common/SelectModal/SelectModal.tsx b/packages/fakeyou.com/src/components/common/SelectModal/SelectModal.tsx index 20eb445b2e..6e84965fdc 100644 --- a/packages/fakeyou.com/src/components/common/SelectModal/SelectModal.tsx +++ b/packages/fakeyou.com/src/components/common/SelectModal/SelectModal.tsx @@ -2,7 +2,7 @@ import React, { useState, memo, useEffect } from "react"; import Searcher from "../Searcher"; import Modal from "../Modal"; import NonRouteTabs from "../Tabs/NonRouteTabs"; -import Input from "../Input"; +import Input from "../TempInput"; import Button from "../Button"; import { faTrash } from "@fortawesome/free-solid-svg-icons"; import SelectMediaList from "./SelectMediaList"; @@ -122,7 +122,7 @@ const SelectModal = memo( /> { + wrapperClassName ?: string; className?: string; icon?: IconDefinition; invalidReason?: string; @@ -14,6 +15,7 @@ interface InputProps extends React.InputHTMLAttributes { } export default function TempInput({ + wrapperClassName, className, label, icon, @@ -24,8 +26,8 @@ export default function TempInput({ }: InputProps) { return ( // Changed fragment to div here just so that it can be laid out with bootstrap easily using d-flex, flex-column and responsive gaps which requires grouping. -
-