mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-09 19:41:32 +00:00
Merge branch 'master' into feature/mvp
This commit is contained in:
14 files changed
+413
-152
No files matched your search
@@ -24,5 +24,8 @@ export enum MediaFileType {
|
||||
// This is a temporary format that will eventually go away.
|
||||
SceneRon = "scene_ron",
|
||||
|
||||
// Engine scene
|
||||
SceneJson = "scene_json",
|
||||
|
||||
None = "none",
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import MakeRequest from "../MakeRequest";
|
||||
|
||||
export interface CreateFeaturedItemRequest {
|
||||
entity_token: string,
|
||||
entity_type: string,
|
||||
}
|
||||
|
||||
export interface CreateFeaturedItemResponse {
|
||||
success: boolean
|
||||
}
|
||||
|
||||
export const CreateFeaturedItem = MakeRequest<
|
||||
string,
|
||||
CreateFeaturedItemRequest,
|
||||
CreateFeaturedItemResponse,
|
||||
{}
|
||||
>({
|
||||
method: "POST",
|
||||
routingFunction: () => "/v1/featured_item/create",
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
import MakeRequest from "../MakeRequest";
|
||||
|
||||
export interface DeleteFeaturedItemRequest {
|
||||
entity_token: string,
|
||||
entity_type: string,
|
||||
}
|
||||
|
||||
export interface DeleteFeaturedItemResponse {
|
||||
success: boolean
|
||||
}
|
||||
|
||||
export const DeleteFeaturedItem = MakeRequest<
|
||||
string,
|
||||
DeleteFeaturedItemRequest,
|
||||
DeleteFeaturedItemResponse,
|
||||
{}
|
||||
>({
|
||||
method: "DELETE",
|
||||
routingFunction: () => "/v1/featured_item/delete",
|
||||
});
|
||||
@@ -19,8 +19,7 @@ export interface MediaFile {
|
||||
maybe_creator_user: UserDetailsLight | null;
|
||||
maybe_prompt_token: string | null;
|
||||
creator_set_visibility: string;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
is_featured: boolean;
|
||||
maybe_model_weight_info: {
|
||||
title: string;
|
||||
weight_token: string;
|
||||
@@ -36,6 +35,8 @@ export interface MediaFile {
|
||||
},
|
||||
maybe_cover_image_public_bucket_path: string | null
|
||||
};
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface GetMediaRequest {}
|
||||
|
||||
@@ -1,4 +1,24 @@
|
||||
{
|
||||
"MediaCategories": {
|
||||
"all": "All",
|
||||
"audio": "Audio",
|
||||
"image": "Image",
|
||||
"video": "Video",
|
||||
"engine_asset": "3D Asset"
|
||||
},
|
||||
"MediaCategoriesPlural": {
|
||||
"all": "All",
|
||||
"audio": "Audio",
|
||||
"image": "Images",
|
||||
"video": "Videos",
|
||||
"engine_asset": "3D Assets"
|
||||
},
|
||||
"WeightsCategories": {
|
||||
"all": "All",
|
||||
"faceAnimation": "Face Animator",
|
||||
"tts": "Text to speech",
|
||||
"voiceConversion": "Voice conversion"
|
||||
},
|
||||
"WeightTypes": {
|
||||
"all": "All weights",
|
||||
"hifigan_tt2": "HiFi-GAN TT2",
|
||||
@@ -20,5 +40,5 @@
|
||||
"glb": "GLB",
|
||||
"gltf": "gltf",
|
||||
"fbx": "FBX"
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,24 @@ export type VstStyle
|
||||
| "pop_art"
|
||||
| "realistic_1"
|
||||
| "realistic_2"
|
||||
|
||||
| "hr_giger"
|
||||
| "simpsons"
|
||||
| "carnage"
|
||||
| "pastel_cute_anime"
|
||||
| "bloom_lighting"
|
||||
| "25d_horror"
|
||||
| "creepy"
|
||||
| "creepy_vhs"
|
||||
| "trail_cam_footage"
|
||||
| "old_black_white_movie"
|
||||
| "horror_noir_black_white"
|
||||
| "techno_noir_black_white"
|
||||
| "black_white_20s"
|
||||
| "cyberpunk_anime"
|
||||
| "dragonball"
|
||||
| "realistic_matrix"
|
||||
| "realistic_cyberpunk"
|
||||
;
|
||||
|
||||
// Definition of the different options.
|
||||
@@ -102,6 +120,80 @@ export const STYLE_OPTIONS: readonly StyleOption[] = [
|
||||
label: "Realistic 2",
|
||||
value: "realistic_2",
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
label: "HR Giger",
|
||||
value: "hr_giger",
|
||||
},
|
||||
{
|
||||
label: "Simpsons",
|
||||
value: "simpsons",
|
||||
},
|
||||
{
|
||||
label: "Carnage",
|
||||
value: "carnage",
|
||||
},
|
||||
{
|
||||
label: "Anime Pastel Cute",
|
||||
value: "pastel_cute_anime",
|
||||
},
|
||||
{
|
||||
label: "iBloom Lighting",
|
||||
value: "bloom_lighting",
|
||||
},
|
||||
{
|
||||
label: "Horror 2.5D",
|
||||
value: "25d_horror",
|
||||
},
|
||||
{
|
||||
label: "Creepy",
|
||||
value: "creepy",
|
||||
},
|
||||
{
|
||||
label: "Creepy VHS",
|
||||
value: "creepy_vhs",
|
||||
},
|
||||
{
|
||||
label: "Trail Cam Footage",
|
||||
value: "trail_cam_footage",
|
||||
},
|
||||
{
|
||||
label: "Old Black and White Movie",
|
||||
value: "old_black_white_movie",
|
||||
},
|
||||
{
|
||||
label: "Horror Noir Black and White",
|
||||
value: "horror_noir_black_white",
|
||||
},
|
||||
{
|
||||
label: "Techno Noir Black and White",
|
||||
value: "techno_noir_black_white",
|
||||
},
|
||||
{
|
||||
label: "Black White 20s",
|
||||
value: "black_white_20s",
|
||||
},
|
||||
{
|
||||
label: "Cyberpunk Anime",
|
||||
value: "cyberpunk_anime",
|
||||
},
|
||||
{
|
||||
label: "Dragonball",
|
||||
value: "dragonball",
|
||||
},
|
||||
{
|
||||
label: "Realistic Matrix",
|
||||
value: "realistic_matrix",
|
||||
},
|
||||
{
|
||||
label: "Realistic Cyberpunk",
|
||||
value: "realistic_cyberpunk",
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
];
|
||||
|
||||
export const STYLES_BY_KEY : Map<string, StyleOption> = new Map(STYLE_OPTIONS.map((opt) => [opt.value, opt]));
|
||||
@@ -75,6 +75,7 @@ describe('media files', () => {
|
||||
updated_at: new Date(),
|
||||
maybe_creator_user: null,
|
||||
creator_set_visibility: "public",
|
||||
is_featured: false,
|
||||
// TODO(bt,2024-03-11): Make these fields optional
|
||||
maybe_model_weight_info: {
|
||||
title: "title",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { enumToKeyArr } from "resources";
|
||||
import { UploadMediaResponse } from "@storyteller/components/src/api/media_files/UploadMedia";
|
||||
import { UploadEngineAssetResponse }from "@storyteller/components/src/api/media_files/UploadEngineAsset";
|
||||
import { UploadEngineAssetResponse } from "@storyteller/components/src/api/media_files/UploadEngineAsset";
|
||||
|
||||
// 1
|
||||
|
||||
@@ -10,7 +10,7 @@ import { UploadEngineAssetResponse }from "@storyteller/components/src/api/media_
|
||||
export enum EntityType {
|
||||
unknown,
|
||||
media,
|
||||
weights
|
||||
weights,
|
||||
}
|
||||
|
||||
// 2
|
||||
@@ -23,14 +23,14 @@ export enum MediaFilters {
|
||||
audio,
|
||||
image,
|
||||
video,
|
||||
engine_asset
|
||||
engine_asset,
|
||||
}
|
||||
|
||||
export enum WeightsCategories {
|
||||
all,
|
||||
faceAnimation,
|
||||
tts,
|
||||
voiceConversion
|
||||
voiceConversion,
|
||||
}
|
||||
|
||||
// 3
|
||||
@@ -49,7 +49,7 @@ export enum WeightsFilters {
|
||||
so_vits_svc,
|
||||
tt2,
|
||||
loRA,
|
||||
vall_e
|
||||
vall_e,
|
||||
}
|
||||
|
||||
// media file types
|
||||
@@ -60,17 +60,17 @@ export enum EngineTypes {
|
||||
glb,
|
||||
gltf,
|
||||
obj,
|
||||
ron
|
||||
ron,
|
||||
}
|
||||
|
||||
export enum AudioTypes {
|
||||
mp3,
|
||||
wav
|
||||
wav,
|
||||
}
|
||||
|
||||
export enum ImageTypes {
|
||||
jpg,
|
||||
png
|
||||
png,
|
||||
}
|
||||
|
||||
export enum VideoTypes {
|
||||
@@ -128,15 +128,19 @@ export type JobSelection = WeightCategoriesProp | WeightFilterProp;
|
||||
export type UploaderResponse = UploadEngineAssetResponse | UploadMediaResponse;
|
||||
|
||||
export const ListEntityFilters = (mode?: EntityInputMode) => {
|
||||
|
||||
// this an object of all types
|
||||
// in most cases it is better to have granular caterogization of types
|
||||
// but because any entity can/could(?) be bookmarked all types are agregated here
|
||||
// this is condensed because typescript didn't like when I broke it apart.
|
||||
// Will clean up soon, I promise
|
||||
const bookmarkFilters = Object.keys({ ...MediaFilters, ...WeightsFilters }).filter(val => isNaN(Number(val))).reduce((obj,current) => ({ ...obj, [current]: current }),{});
|
||||
const bookmarkFilters = Object.keys({ ...MediaFilters, ...WeightsFilters })
|
||||
.filter(val => isNaN(Number(val)))
|
||||
.reduce((obj, current) => ({ ...obj, [current]: current }), {});
|
||||
|
||||
const selectedFilters = mode !== undefined ? [bookmarkFilters,MediaFilters,WeightsFilters,WeightsFilters][mode] : EntityInputMode;
|
||||
const selectedFilters =
|
||||
mode !== undefined
|
||||
? [bookmarkFilters, MediaFilters, WeightsFilters, WeightsFilters][mode]
|
||||
: EntityInputMode;
|
||||
|
||||
return Object.values(selectedFilters).filter(val => isNaN(Number(val)));
|
||||
};
|
||||
@@ -145,36 +149,59 @@ export const ListEntityFilters = (mode?: EntityInputMode) => {
|
||||
// note the use t() to translate labels
|
||||
// this allows easily maintained translations for inputs
|
||||
|
||||
export const EntityFilterOptions = (mode?: EntityInputMode, t = (v:string) => v) => {
|
||||
return ListEntityFilters(mode).map((value) => {
|
||||
if (typeof value === "string") return { value, label: t(value) }
|
||||
return { label: "all", value: "all" };
|
||||
export const EntityFilterOptions = (
|
||||
mode?: EntityInputMode,
|
||||
t = (v: string) => v
|
||||
) => {
|
||||
const translationNamespaces = [
|
||||
"BookmarksCategories",
|
||||
"MediaCategoriesPlural",
|
||||
"WeightsCategories",
|
||||
"WeightsCategories",
|
||||
];
|
||||
const selectedNamespace = translationNamespaces[mode || -1];
|
||||
return ListEntityFilters(mode).map(value => {
|
||||
if (typeof value === "string")
|
||||
return {
|
||||
value,
|
||||
label:
|
||||
selectedNamespace !== undefined
|
||||
? t(`${selectedNamespace}.${value}`)
|
||||
: value,
|
||||
};
|
||||
return { label: t(`${selectedNamespace}.all`), value: "all" };
|
||||
});
|
||||
};
|
||||
|
||||
export const getMediaTypesByCategory = (mediaCategory: MediaFilters) => enumToKeyArr([
|
||||
{ ...AudioTypes, ...ImageTypes, ...VideoTypes, ...EngineTypes },
|
||||
AudioTypes,
|
||||
ImageTypes,
|
||||
VideoTypes,
|
||||
EngineTypes
|
||||
][mediaCategory]);
|
||||
export const getMediaTypesByCategory = (mediaCategory: MediaFilters) =>
|
||||
enumToKeyArr(
|
||||
[
|
||||
{ ...AudioTypes, ...ImageTypes, ...VideoTypes, ...EngineTypes },
|
||||
AudioTypes,
|
||||
ImageTypes,
|
||||
VideoTypes,
|
||||
EngineTypes,
|
||||
][mediaCategory]
|
||||
);
|
||||
|
||||
export const isSelectedType = (mediaCategory: MediaFilters, fileExtension: string) =>
|
||||
getMediaTypesByCategory(mediaCategory).includes(fileExtension);
|
||||
export const isSelectedType = (
|
||||
mediaCategory: MediaFilters,
|
||||
fileExtension: string
|
||||
) => getMediaTypesByCategory(mediaCategory).includes(fileExtension);
|
||||
|
||||
export const mediaCategoryfromString = (categoryStr: string) => enumToKeyArr(MediaFilters).indexOf(categoryStr);
|
||||
export const mediaCategoryfromString = (categoryStr: string) =>
|
||||
enumToKeyArr(MediaFilters).indexOf(categoryStr);
|
||||
|
||||
//renaming to getMediaCatgoryByType
|
||||
export const getMediaCategory = (fileExtension: string) => {
|
||||
isSelectedType(MediaFilters.image,fileExtension);
|
||||
if (isSelectedType(MediaFilters.engine_asset, fileExtension)) return MediaFilters.engine_asset;
|
||||
if (isSelectedType(MediaFilters.audio, fileExtension)) return MediaFilters.audio;
|
||||
if (isSelectedType(MediaFilters.image, fileExtension)) return MediaFilters.image;
|
||||
if (isSelectedType(MediaFilters.video, fileExtension)) return MediaFilters.video;
|
||||
isSelectedType(MediaFilters.image, fileExtension);
|
||||
if (isSelectedType(MediaFilters.engine_asset, fileExtension))
|
||||
return MediaFilters.engine_asset;
|
||||
if (isSelectedType(MediaFilters.audio, fileExtension))
|
||||
return MediaFilters.audio;
|
||||
if (isSelectedType(MediaFilters.image, fileExtension))
|
||||
return MediaFilters.image;
|
||||
if (isSelectedType(MediaFilters.video, fileExtension))
|
||||
return MediaFilters.video;
|
||||
return MediaFilters.all; // will change to "unknown" eventually
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
@@ -9,6 +9,7 @@ export const mediaTypeLabels = {
|
||||
[MediaFileType.GLB]: "GLB",
|
||||
[MediaFileType.GLTF]: "glTF",
|
||||
[MediaFileType.SceneRon]: "RON",
|
||||
[MediaFileType.SceneJson]: "Scene",
|
||||
[MediaFileType.FBX]: "FBX",
|
||||
[MediaFileType.None]: "Unknown",
|
||||
};
|
||||
@@ -36,13 +36,16 @@ import { useBookmarks, useMedia, useRatings, useSession } from "hooks";
|
||||
import { WeightCategory } from "@storyteller/components/src/api/_common/enums/WeightCategory";
|
||||
import SdBatchMediaPanel from "./components/SdBatchMediaPanel/SdBatchMediaPanel";
|
||||
import { GetMediaBatchImages } from "@storyteller/components/src/api/media_files/GetMediaBatchImages";
|
||||
import { CreateFeaturedItem } from "@storyteller/components/src/api/featured_items/CreateFeaturedItem";
|
||||
import { DeleteFeaturedItem } from "@storyteller/components/src/api/featured_items/DeleteFeaturedItem";
|
||||
import { mediaTypeLabels } from "utils/mediaTypeLabels";
|
||||
import { EngineMediaPanel } from "./components/EngineMediaPanel/EngineMediaPanel";
|
||||
import { GetMediaFileTitle } from "common/GetMediaFileTitle";
|
||||
import { STYLES_BY_KEY } from "common/StyleOptions";
|
||||
import { faStarShooting } from "@fortawesome/pro-duotone-svg-icons";
|
||||
|
||||
export default function MediaPage() {
|
||||
const { canAccessStudio, canEditMediaFile, user } = useSession();
|
||||
const { canAccessStudio, canEditMediaFile, canBanUsers, user } = useSession();
|
||||
const { token } = useParams<{ token: string }>();
|
||||
const bookmarks = useBookmarks();
|
||||
const ratings = useRatings();
|
||||
@@ -70,6 +73,8 @@ export default function MediaPage() {
|
||||
mediaFile?.maybe_creator_user?.user_token || ""
|
||||
);
|
||||
|
||||
const viewerCanMakeFeatured = canBanUsers() || false;
|
||||
|
||||
// Inside MediaPage.tsx
|
||||
|
||||
useEffect(() => {
|
||||
@@ -99,6 +104,31 @@ export default function MediaPage() {
|
||||
|
||||
const deleteMedia = () => remove(!!user?.can_ban_users);
|
||||
|
||||
const handleFeatureMedia = async () => {
|
||||
setFeatureMedia(!mediaFile?.is_featured);
|
||||
};
|
||||
|
||||
const setFeatureMedia = async (setFeatured: boolean) => {
|
||||
if (mediaFile === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const request = {
|
||||
entity_type: "media_file",
|
||||
entity_token: mediaFile.token,
|
||||
};
|
||||
|
||||
// NB: Victor, I don't know how to re-query media with the media context thing. :(
|
||||
// Sorry, I'm forcing a page reload instead. I know this sucks.
|
||||
if (setFeatured) {
|
||||
await CreateFeaturedItem("", request);
|
||||
window.location.reload();
|
||||
} else {
|
||||
await DeleteFeaturedItem("", request);
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
const copyToClipboard = async (
|
||||
text: string,
|
||||
setButtonText: React.Dispatch<React.SetStateAction<string>>
|
||||
@@ -167,16 +197,15 @@ export default function MediaPage() {
|
||||
{prompt?.maybe_style_name && (
|
||||
<>
|
||||
<div className="d-flex gap-3 align-items-center mb-2 mt-3">
|
||||
<h6 className="fw-semibold mb-0 flex-grow-1">
|
||||
Style Name
|
||||
</h6>
|
||||
<h6 className="fw-semibold mb-0 flex-grow-1">Style Name</h6>
|
||||
</div>
|
||||
<div className="panel-inner p-2 rounded">
|
||||
<p className="fs-7">{STYLES_BY_KEY.get(prompt.maybe_style_name)?.label}</p>
|
||||
<p className="fs-7">
|
||||
{STYLES_BY_KEY.get(prompt.maybe_style_name)?.label}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
</Panel>
|
||||
)}
|
||||
</>
|
||||
@@ -270,8 +299,24 @@ export default function MediaPage() {
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
case MediaFileType.SceneJson:
|
||||
return (
|
||||
<div
|
||||
{...{
|
||||
className:
|
||||
"rounded w-100 h-100 panel d-flex align-items-center justify-content-center p-3",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
{...{
|
||||
label: "View in engine",
|
||||
href: `https://studio.storyteller.ai/${mediaFile.token}`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return <div>Unsupported media type</div>;
|
||||
return <div>Unsupported media typeaaa</div>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,30 +520,37 @@ export default function MediaPage() {
|
||||
const title = GetMediaFileTitle(mediaFile);
|
||||
|
||||
const showEngineCover = () => {
|
||||
const coverMediaPath = mediaFile?.cover_image?.maybe_cover_image_public_bucket_path || "";
|
||||
const coverMediaPath =
|
||||
mediaFile?.cover_image?.maybe_cover_image_public_bucket_path || "";
|
||||
if (mediaFile) {
|
||||
switch (mediaFile.media_type) {
|
||||
case MediaFileType.BVH:
|
||||
case MediaFileType.GLB:
|
||||
case MediaFileType.GLTF:
|
||||
case MediaFileType.SceneRon: return <WeightCoverImage {...{
|
||||
...coverMediaPath ? { src: bucketConfig.getGcsUrl(coverMediaPath) } : {},
|
||||
...viewerCanEdit ? { to: `/edit-cover-image/${ token }` } : {},
|
||||
coverIndex: mediaFile.cover_image.default_cover.image_index,
|
||||
}}/>;
|
||||
default: return null;
|
||||
case MediaFileType.BVH:
|
||||
case MediaFileType.GLB:
|
||||
case MediaFileType.GLTF:
|
||||
case MediaFileType.SceneRon:
|
||||
return (
|
||||
<WeightCoverImage
|
||||
{...{
|
||||
...(coverMediaPath
|
||||
? { src: bucketConfig.getGcsUrl(coverMediaPath) }
|
||||
: {}),
|
||||
...(viewerCanEdit ? { to: `/edit-cover-image/${token}` } : {}),
|
||||
coverIndex: mediaFile.cover_image.default_cover.image_index,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Container type="panel" className="mb-5">
|
||||
<Panel clear={true} className="py-4">
|
||||
<div className="d-flex flex-column flex-lg-row gap-3 gap-lg-2">
|
||||
{
|
||||
showEngineCover()
|
||||
}
|
||||
{showEngineCover()}
|
||||
<div>
|
||||
<div className="d-flex gap-2 align-items-center flex-wrap">
|
||||
<h1 className="fw-bold mb-2">{title}</h1>
|
||||
@@ -578,7 +630,8 @@ export default function MediaPage() {
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{ canAccessStudio() && mediaFile?.media_type === MediaFileType.Video ? (
|
||||
{canAccessStudio() &&
|
||||
mediaFile?.media_type === MediaFileType.Video ? (
|
||||
<Button
|
||||
{...{
|
||||
icon: faArrowRightArrowLeft,
|
||||
@@ -813,7 +866,7 @@ export default function MediaPage() {
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
{ viewerCanEdit && (
|
||||
{viewerCanEdit && (
|
||||
<>
|
||||
<div className="d-flex gap-2">
|
||||
<Button
|
||||
@@ -832,6 +885,23 @@ export default function MediaPage() {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{viewerCanMakeFeatured && (
|
||||
<>
|
||||
<div className="d-flex gap-2">
|
||||
<Button
|
||||
full={true}
|
||||
variant="secondary"
|
||||
icon={faStarShooting}
|
||||
label={
|
||||
mediaFile?.is_featured
|
||||
? "Remove Featured"
|
||||
: "Set Featured"
|
||||
}
|
||||
onClick={handleFeatureMedia}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,11 +2,18 @@ import React, { useState } from "react";
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { useInferenceJobs, useSession } from "hooks";
|
||||
import { Button, Container, Panel, TextArea, TempSelect as Select } from "components/common";
|
||||
import {
|
||||
Button,
|
||||
Container,
|
||||
Panel,
|
||||
SegmentButtons,
|
||||
TextArea,
|
||||
TempSelect as Select,
|
||||
} from "components/common";
|
||||
import { EntityInput } from "components/entities";
|
||||
import {
|
||||
EnqueueVST,
|
||||
EnqueueVSTResponse
|
||||
EnqueueVSTResponse,
|
||||
} from "@storyteller/components/src/api/video_styleTransfer/Enqueue_VST";
|
||||
import "./StyleVideo.scss";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -19,24 +26,28 @@ export default function StyleVideo() {
|
||||
const [mediaToken, mediaTokenSet] = useState(pageMediaToken || "");
|
||||
const [prompt, promptSet] = useState("");
|
||||
const [negativePrompt, negativePromptSet] = useState("");
|
||||
const [length, lengthSet] = useState(3000);
|
||||
const { enqueue } = useInferenceJobs();
|
||||
|
||||
const onClick = () => {
|
||||
if (mediaToken) {
|
||||
EnqueueVST("",{
|
||||
EnqueueVST("", {
|
||||
creator_set_visibility: "private",
|
||||
enable_lipsync: true,
|
||||
input_file: mediaToken,
|
||||
negative_prompt: negativePrompt,
|
||||
prompt,
|
||||
style,
|
||||
trim_end_millis: 3000,
|
||||
trim_end_millis: length,
|
||||
trim_start_millis: 0,
|
||||
uuid_idempotency_token: uuidv4()
|
||||
})
|
||||
.then((res: EnqueueVSTResponse) => {
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
}).then((res: EnqueueVSTResponse) => {
|
||||
if (res.success && res.inference_job_token) {
|
||||
enqueue(res.inference_job_token,true,FrontendInferenceJobType.VideoStyleTransfer);
|
||||
enqueue(
|
||||
res.inference_job_token,
|
||||
true,
|
||||
FrontendInferenceJobType.VideoStyleTransfer
|
||||
);
|
||||
} else {
|
||||
console.log("Failed to enqueue job", res);
|
||||
}
|
||||
@@ -44,55 +55,92 @@ export default function StyleVideo() {
|
||||
}
|
||||
};
|
||||
|
||||
const options = STYLE_OPTIONS.map((option) => {
|
||||
const styleOptions = STYLE_OPTIONS.map(option => {
|
||||
return {
|
||||
label: option.label,
|
||||
label: option.label,
|
||||
value: option.value,
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return studioAccessCheck(<Container {...{ className: "fy-style-video-page mt-5", type: "panel" }}>
|
||||
const lengthOptions = [
|
||||
{ label: 3, value: 3000 },
|
||||
{ label: 5, value: 5000 },
|
||||
{ label: 7, value: 7000 },
|
||||
];
|
||||
|
||||
return studioAccessCheck(
|
||||
<Container {...{ className: "fy-style-video-page mt-5", type: "panel" }}>
|
||||
<Panel {...{ padding: true }}>
|
||||
<header className="d-flex gap-3 flex-wrap">
|
||||
<h1 className="fw-semibold">
|
||||
Style a Video
|
||||
</h1>
|
||||
<h1 className="fw-semibold">Style a Video</h1>
|
||||
</header>
|
||||
<EntityInput {...{
|
||||
accept: ["video"],
|
||||
aspectRatio: "landscape",
|
||||
label: "Choose a video",
|
||||
name: "mediaToken",
|
||||
value: pageMediaToken,
|
||||
onChange: ({ target }: { target: any }) => { mediaTokenSet(target.value) },
|
||||
type: "media"
|
||||
}}/>
|
||||
<Select {...{
|
||||
label: "Style",
|
||||
onChange: ({ target }: { target: any }) => { styleSet(target.value) },
|
||||
options,
|
||||
value: style
|
||||
}}/>
|
||||
<EntityInput
|
||||
{...{
|
||||
accept: ["video"],
|
||||
aspectRatio: "landscape",
|
||||
label: "Choose a video",
|
||||
name: "mediaToken",
|
||||
value: pageMediaToken,
|
||||
onChange: ({ target }: { target: any }) => {
|
||||
mediaTokenSet(target.value);
|
||||
},
|
||||
type: "media",
|
||||
}}
|
||||
/>
|
||||
<Select
|
||||
{...{
|
||||
label: "Style",
|
||||
onChange: ({ target }: { target: any }) => {
|
||||
styleSet(target.value);
|
||||
},
|
||||
options: styleOptions,
|
||||
value: style,
|
||||
}}
|
||||
/>
|
||||
<div {...{ className: "prompt-row" }}>
|
||||
<TextArea {...{
|
||||
label: "Positive prompt",
|
||||
rows: 5,
|
||||
onChange: ({ target }: { target: any }) => { promptSet(target.value) },
|
||||
}}/>
|
||||
<TextArea {...{
|
||||
label: "Negative prompt",
|
||||
rows: 5,
|
||||
onChange: ({ target }: { target: any }) => { negativePromptSet(target.value) },
|
||||
}}/>
|
||||
<TextArea
|
||||
{...{
|
||||
label: "Positive prompt",
|
||||
rows: 5,
|
||||
onChange: ({ target }: { target: any }) => {
|
||||
promptSet(target.value);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<TextArea
|
||||
{...{
|
||||
label: "Negative prompt",
|
||||
rows: 5,
|
||||
onChange: ({ target }: { target: any }) => {
|
||||
negativePromptSet(target.value);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div {...{ className: "prompt-row" }}>
|
||||
<SegmentButtons
|
||||
{...{
|
||||
className: "fy-style-video-length",
|
||||
label: "Final video length (seconds)",
|
||||
onChange: ({ target }: { target: any }) => {
|
||||
lengthSet(target.value);
|
||||
},
|
||||
options: lengthOptions,
|
||||
value: length,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div {...{ className: "d-flex justify-content-center mt-3" }}>
|
||||
<Button {...{
|
||||
disabled: !mediaToken,
|
||||
label: "Style",
|
||||
onClick,
|
||||
variant: "primary"
|
||||
}} />
|
||||
<Button
|
||||
{...{
|
||||
disabled: !mediaToken,
|
||||
label: "Style",
|
||||
onClick,
|
||||
variant: "primary",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Panel>
|
||||
</Container>);
|
||||
};
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
File renamed without changes.
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
MASTER_BRANCH='master'
|
||||
PRODUCTION_BRANCH='production-storyteller'
|
||||
|
||||
git stash
|
||||
git checkout $MASTER_BRANCH
|
||||
git pull
|
||||
|
||||
if git show-ref --verify --quiet "refs/heads/$PRODUCTION_BRANCH"; then
|
||||
echo "Deleting branch ${PRODUCTION_BRANCH}"
|
||||
git branch -D $PRODUCTION_BRANCH
|
||||
fi
|
||||
|
||||
git checkout -b $PRODUCTION_BRANCH
|
||||
git push --set-upstream origin $PRODUCTION_BRANCH
|
||||
|
||||
git checkout $MASTER_BRANCH
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
MASTER_BRANCH='master'
|
||||
PRODUCTION_BRANCH='production-trumped'
|
||||
|
||||
git stash
|
||||
git checkout $MASTER_BRANCH
|
||||
git pull
|
||||
|
||||
if git show-ref --verify --quiet "refs/heads/$PRODUCTION_BRANCH"; then
|
||||
echo "Deleting branch ${PRODUCTION_BRANCH}"
|
||||
git branch -D $PRODUCTION_BRANCH
|
||||
fi
|
||||
|
||||
git checkout -b $PRODUCTION_BRANCH
|
||||
git push --set-upstream origin $PRODUCTION_BRANCH
|
||||
|
||||
git checkout $MASTER_BRANCH
|
||||
|
||||
Reference in new issue
Block a user