mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-06 02:00:46 +00:00
Merge branch 'feature/mvp' into feature/page/video_transfer
This commit is contained in:
commit
d8a50334fd
35 files changed
+386
-288
No files matched your search
@@ -8,6 +8,7 @@ export interface UploadLoraRequest {
|
||||
maybe_name: String,
|
||||
maybe_description: String,
|
||||
visibility: String,
|
||||
maybe_cover_image_media_file_token?: String,
|
||||
}
|
||||
|
||||
export interface UploadLoraResponse {
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface UploadModelRequest {
|
||||
maybe_name: String,
|
||||
maybe_description: String,
|
||||
visibility: String,
|
||||
maybe_cover_image_media_file_token?: String,
|
||||
}
|
||||
|
||||
export interface UploadModelResponse {
|
||||
|
||||
@@ -21,6 +21,7 @@ export interface MediaFile {
|
||||
maybe_weight_creator: UserDetailsLight;
|
||||
maybe_cover_image_public_bucket_path: string;
|
||||
};
|
||||
maybe_text_transcript?: string;
|
||||
}
|
||||
|
||||
export enum MediaFileLookupError {
|
||||
|
||||
@@ -300,6 +300,8 @@ class App extends React.Component<Props, State> {
|
||||
await this.querySessionSubscriptions();
|
||||
|
||||
setInterval(async () => {
|
||||
// See warnings in the following methods when adding new methods
|
||||
// that affect global "state"
|
||||
await this.querySession();
|
||||
await this.querySessionSubscriptions();
|
||||
}, 60000);
|
||||
@@ -310,6 +312,10 @@ class App extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
querySession = async () => {
|
||||
// WARNING: Making setState calls in this scope without checking existing
|
||||
// state can cause the whole site to refresh/worsen UX. Double check if
|
||||
// state needs to be set here, or if instead can be refreshed locally on
|
||||
// the page where the new "state" needed
|
||||
const sessionWrapper = await SessionWrapper.lookupSession();
|
||||
const username = sessionWrapper.getDisplayName();
|
||||
const cookies = new Cookies();
|
||||
@@ -337,7 +343,15 @@ class App extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
querySessionSubscriptions = async () => {
|
||||
this.setState({ sessionFetched: true });
|
||||
// WARNING: Making setState calls in this scope without checking existing
|
||||
// state can cause the whole site to refresh/worsen UX. Double check if
|
||||
// state needs to be set here, or if instead can be refreshed locally on
|
||||
// the page where the new "state" needed
|
||||
|
||||
if (this.state.sessionFetched === false){
|
||||
this.setState({ sessionFetched: true });
|
||||
}
|
||||
|
||||
const cookies = new Cookies();
|
||||
|
||||
const sessionSubscriptionsWrapper =
|
||||
|
||||
@@ -106,17 +106,22 @@ export default function AudioCard({
|
||||
</div>
|
||||
|
||||
<h6 className="fw-semibold text-white mb-1 mt-3">
|
||||
{data.origin.maybe_model
|
||||
{data.origin?.maybe_model
|
||||
? data.origin.maybe_model.title
|
||||
: "Media Audio"}
|
||||
</h6>
|
||||
<p className="fs-7 opacity-75">{timeAgo}</p>
|
||||
{data.maybe_text_transcript && (
|
||||
<p className="fs-7 mt-2 two-line-ellipsis">
|
||||
{data.maybe_text_transcript}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<AudioPlayer src={data.public_bucket_path} id={data.token} />
|
||||
<AudioPlayer src={data.details?.maybe_media_file_data?.public_bucket_path || data.public_bucket_path} id={data.token} />
|
||||
<CardFooter
|
||||
{...{
|
||||
creator: data?.maybe_creator,
|
||||
entityToken: data.token,
|
||||
creator: data?.maybe_creator || data.details?.maybe_media_file_data?.maybe_creator,
|
||||
entityToken: data.details?.entity_token || data.token,
|
||||
entityType: "media_file",
|
||||
makeBookmarksProps: bookmarks?.makeProps,
|
||||
makeRatingsProps: ratings?.makeProps,
|
||||
@@ -178,8 +183,7 @@ export default function AudioCard({
|
||||
</div>
|
||||
<CardFooter
|
||||
{...{
|
||||
creator:
|
||||
data?.creator || data.details.maybe_weight_data?.maybe_creator,
|
||||
creator: data?.creator || data.details.maybe_weight_data?.maybe_creator,
|
||||
entityToken: data.weight_token || data.details?.entity_token,
|
||||
entityType: "model_weight",
|
||||
makeBookmarksProps: bookmarks?.makeProps,
|
||||
|
||||
@@ -55,8 +55,8 @@ export default function BVHCard({
|
||||
<p className="fs-7 opacity-75 mb-0">{timeAgo}</p>
|
||||
</div>
|
||||
<CardFooter {...{
|
||||
creator: data?.maybe_creator,
|
||||
entityToken: data.token,
|
||||
creator: data?.maybe_creator || data.details?.maybe_media_file_data?.maybe_creator,
|
||||
entityToken: data.details?.entity_token || data.token,
|
||||
entityType: "media_file",
|
||||
makeBookmarksProps: bookmarks?.makeProps,
|
||||
makeRatingsProps: ratings?.makeProps,
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import React from "react";
|
||||
import MediaCards from "components/common/Card/MediaCards";
|
||||
import WeightsCards from "components/common/Card/WeightsCards";
|
||||
|
||||
interface Props {
|
||||
entityType: string;
|
||||
props: any;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export default function BookmarksCards({ entityType, props, type }: Props) {
|
||||
return entityType === "media_file" ?
|
||||
<MediaCards { ...{ props, type }} /> : <WeightsCards { ...{ props, type }} />;
|
||||
}
|
||||
@@ -54,8 +54,8 @@ export default function FBXCard({
|
||||
<p className="fs-7 opacity-75 mb-0">{timeAgo}</p>
|
||||
</div>
|
||||
<CardFooter {...{
|
||||
creator: data?.maybe_creator,
|
||||
entityToken: data.token,
|
||||
creator: data?.maybe_creator || data.details?.maybe_media_file_data?.maybe_creator,
|
||||
entityToken: data.details?.entity_token || data.token,
|
||||
entityType: "media_file",
|
||||
makeBookmarksProps: bookmarks?.makeProps,
|
||||
makeRatingsProps: ratings?.makeProps,
|
||||
|
||||
@@ -54,8 +54,8 @@ export default function GLBCard({
|
||||
<p className="fs-7 opacity-75 mb-0">{timeAgo}</p>
|
||||
</div>
|
||||
<CardFooter {...{
|
||||
creator: data?.maybe_creator,
|
||||
entityToken: data.token,
|
||||
creator: data?.maybe_creator || data.details?.maybe_media_file_data?.maybe_creator,
|
||||
entityToken: data.details?.entity_token || data.token,
|
||||
entityType: "media_file",
|
||||
makeBookmarksProps: bookmarks?.makeProps,
|
||||
makeRatingsProps: ratings?.makeProps,
|
||||
|
||||
@@ -54,8 +54,8 @@ export default function GLTFCard({
|
||||
<p className="fs-7 opacity-75 mb-0">{timeAgo}</p>
|
||||
</div>
|
||||
<CardFooter {...{
|
||||
creator: data?.maybe_creator,
|
||||
entityToken: data.token,
|
||||
creator: data?.maybe_creator || data.details?.maybe_media_file_data?.maybe_creator,
|
||||
entityToken: data.details?.entity_token || data.token,
|
||||
entityType: "media_file",
|
||||
makeBookmarksProps: bookmarks?.makeProps,
|
||||
makeRatingsProps: ratings?.makeProps,
|
||||
|
||||
@@ -66,7 +66,7 @@ export default function ImageCard({
|
||||
let coverImage = undefined;
|
||||
|
||||
if (type === "media") {
|
||||
coverImage = bucketConfig.getCdnUrl(data.public_bucket_path, 600, 100);
|
||||
coverImage = bucketConfig.getCdnUrl(data.details?.maybe_media_file_data?.public_bucket_path || data.public_bucket_path, 600, 100);
|
||||
} else if (type === "weights") {
|
||||
coverImage = `/images/default-covers/${
|
||||
data?.cover_image?.default_cover.image_index || 0
|
||||
@@ -121,8 +121,8 @@ export default function ImageCard({
|
||||
</div>
|
||||
<CardFooter
|
||||
{...{
|
||||
creator: data?.maybe_creator,
|
||||
entityToken: data.token,
|
||||
creator: data?.maybe_creator || data.details?.maybe_media_file_data?.maybe_creator,
|
||||
entityToken: data.details?.entity_token || data.token,
|
||||
entityType: "media_file",
|
||||
makeBookmarksProps: bookmarks?.makeProps,
|
||||
makeRatingsProps: ratings?.makeProps,
|
||||
|
||||
@@ -17,6 +17,6 @@ export default function WeightsCards({ props, type }: Props) {
|
||||
case WeightCategory.SD:
|
||||
return <ImageCard {...props} />;
|
||||
default:
|
||||
return <div>Unsupported media type</div>;
|
||||
return <div>Unsupported weight type</div>;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
const getCardUrl = (data: any, source: string, type: string) => {
|
||||
let prefix = type === "media" ? `/media/${data.token}` : `/weight/${data.weight_token || data.details?.entity_token}`;
|
||||
let isBookmark = data.token && data.token.startsWith("ub_");
|
||||
let bookmarkedToken = data.details?.entity_token;
|
||||
let prefix = type === "media" ? `/media/${isBookmark ? bookmarkedToken : data.token}` : `/weight/${isBookmark ? bookmarkedToken : data.weight_token }`;
|
||||
let suffix = source ? "?source=" + source : "";
|
||||
return prefix + suffix;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import Button from "../Button";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import SelectMediaList from "./SelectMediaList";
|
||||
import SelectWeightsList from "./SelectWeightsList";
|
||||
import { useSession } from "hooks";
|
||||
|
||||
export type SelectModalData = {
|
||||
token: string;
|
||||
@@ -39,6 +40,7 @@ const SelectModal = memo(
|
||||
required,
|
||||
}: SelectModalProps) => {
|
||||
const emptyValue = { token: "", title: "" };
|
||||
const { user } = useSession();
|
||||
const [{ isModalOpen, selectedValue, valueType, activeTab }, setState] =
|
||||
useState({
|
||||
isModalOpen: false,
|
||||
@@ -98,12 +100,20 @@ const SelectModal = memo(
|
||||
{tab.type === "weights" && (
|
||||
<>
|
||||
{tab.onlyBookmarked ? (
|
||||
<SelectWeightsList
|
||||
weightType={valueType}
|
||||
listKey={tab.tabKey}
|
||||
onResultBookmarkSelect={handleOnSelect}
|
||||
onlyBookmarked={tab.onlyBookmarked}
|
||||
/>
|
||||
<>
|
||||
{user ? (
|
||||
<SelectWeightsList
|
||||
weightType={valueType}
|
||||
listKey={tab.tabKey}
|
||||
onResultBookmarkSelect={handleOnSelect}
|
||||
onlyBookmarked={tab.onlyBookmarked}
|
||||
/>
|
||||
) : (
|
||||
<div className="text-center py-3">
|
||||
<p>Please login to view your bookmarks.</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<SelectWeightsList
|
||||
weightType={valueType}
|
||||
|
||||
@@ -4,8 +4,10 @@ import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
import ReactSelect, { Props as ReactSelectProps } from "react-select";
|
||||
import "./TempSelect.scss";
|
||||
|
||||
type OptionValue = string | number | boolean;
|
||||
|
||||
export interface Option {
|
||||
value: string | number | boolean;
|
||||
value: OptionValue;
|
||||
label: string;
|
||||
}
|
||||
|
||||
@@ -33,8 +35,14 @@ export default function Select({
|
||||
}: SelectProps) {
|
||||
const valueLabel =
|
||||
options.find((option: any) => option.value === value)?.label || "";
|
||||
const onChange = ({ value }: any) =>
|
||||
inChange({ target: { value, name, type: "select" } });
|
||||
const onChange = (option: any, x: any) => {
|
||||
// console.log("🧪",option, x); // WIP -V
|
||||
if (Array.isArray(option)) {
|
||||
|
||||
} else {
|
||||
inChange({ target: {value: option.value, name, type: "select" } });
|
||||
}
|
||||
}
|
||||
const className = `${icon ? " input-icon" : ""}${
|
||||
small ? " select-small" : ""
|
||||
}`;
|
||||
|
||||
@@ -21,6 +21,7 @@ import MocapInput from "./MocapInput";
|
||||
import Modal from "./Modal";
|
||||
import NumberSlider from "./NumberSlider";
|
||||
import NumberSliderV2 from "./NumberSliderV2";
|
||||
import Pagination from "./Pagination";
|
||||
import Panel from "./Panel";
|
||||
import Radio from "./Radio";
|
||||
import SegmentButtons from "./SegmentButtons";
|
||||
@@ -66,6 +67,7 @@ export {
|
||||
Modal,
|
||||
NumberSlider,
|
||||
NumberSliderV2,
|
||||
Pagination,
|
||||
Panel,
|
||||
Radio,
|
||||
SegmentButtons,
|
||||
|
||||
@@ -3,45 +3,27 @@ import { useLocation } from "react-router-dom";
|
||||
import { a, useTransition } from "@react-spring/web";
|
||||
import { MediaFile } from "@storyteller/components/src/api/media_files/GetMedia";
|
||||
import Iframe from "react-iframe";
|
||||
import { MediaBrowser } from "components/modals";
|
||||
import { FileWrapper, Label, Spinner } from "components/common";
|
||||
import { EntityType, MediaFilterProp, WeightFilterProp } from "components/entities/EntityTypes";
|
||||
import { Label, Spinner } from "components/common";
|
||||
import { AcceptTypes, EntityInputMode, EntityModeProp } from "components/entities/EntityTypes";
|
||||
import { useFile, useMedia, useModal, useSession } from "hooks";
|
||||
import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
|
||||
import { faDiagramSankey, faFile, faFileArrowUp, faGrid, faImage, faPersonWalking, faWaveform } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { FontAwesomeIcon as Icon } from "@fortawesome/react-fontawesome";
|
||||
import { UploadMedia, UploadMediaResponse } from "@storyteller/components/src/api/media_files/UploadMedia";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import EntityInputEmpty from "./EntityInputEmpty";
|
||||
import "./EntityInput.scss";
|
||||
|
||||
// enum EntityInputMode {
|
||||
// Bookmarks = "bookmarks",
|
||||
// Media = "media",
|
||||
// Weights = "weights",
|
||||
// SearchWeights = "searchWeights",
|
||||
// }
|
||||
|
||||
interface Props {
|
||||
accept?: AcceptTypes | AcceptTypes[],
|
||||
aspectRatio?: "square" | "landscape" | "portrait",
|
||||
mediaType?: MediaFilterProp,
|
||||
label?: string,
|
||||
onChange?: any,
|
||||
type: string,
|
||||
weightType?: WeightFilterProp
|
||||
type: EntityModeProp,
|
||||
}
|
||||
|
||||
interface SlideProps {
|
||||
export interface SlideProps {
|
||||
media?: MediaFile
|
||||
};
|
||||
|
||||
interface EmptySlideProps extends SlideProps {
|
||||
entityType: EntityType,
|
||||
filterType: MediaFilterProp | WeightFilterProp,
|
||||
inputProps?: any,
|
||||
open: any,
|
||||
user: any
|
||||
};
|
||||
|
||||
interface AniProps {
|
||||
animating: boolean,
|
||||
className: string,
|
||||
@@ -56,12 +38,12 @@ const MediaBusy = () => {
|
||||
|
||||
const MocapInputFull = ({ media }: SlideProps) => {
|
||||
const bucketConfig = new BucketConfig();
|
||||
const bvhUrl = media?.public_bucket_path ? bucketConfig.getGcsUrl(media.public_bucket_path) : "";
|
||||
const mediaUrl = media?.public_bucket_path ? bucketConfig.getGcsUrl(media.public_bucket_path) : "";
|
||||
|
||||
return <>
|
||||
<Iframe
|
||||
{...{
|
||||
url: `https://engine.fakeyou.com?mode=viewer&bvh=${bvhUrl}`,
|
||||
url: `https://engine.fakeyou.com?mode=viewer&${media?.media_type}=${mediaUrl}`,
|
||||
className: "fy-entity-input-mocap-preview",
|
||||
}}
|
||||
/>
|
||||
@@ -71,42 +53,6 @@ const MocapInputFull = ({ media }: SlideProps) => {
|
||||
</>;
|
||||
};
|
||||
|
||||
const MediaPickerEmpty = ({ entityType, filterType, open, inputProps, user, ...rest }: EmptySlideProps) => {
|
||||
const browserClick = () => open({
|
||||
component: MediaBrowser,
|
||||
props: { entityType, filterType, username: user?.username || "", ...rest }
|
||||
});
|
||||
|
||||
const mediaIcons = () => {
|
||||
switch (filterType) {
|
||||
case "audio": return faWaveform;
|
||||
case "image": return faImage;
|
||||
case "bvh": return faPersonWalking;
|
||||
default: return faFile;
|
||||
}
|
||||
}
|
||||
|
||||
return <>
|
||||
<Icon {...{ className: "fy-entity-input-icon", icon: [faFile,mediaIcons(),faDiagramSankey][entityType] }}/>
|
||||
<div {...{ className: "fy-entity-input-empty-controls" }}>
|
||||
{ entityType === EntityType.media &&
|
||||
<FileWrapper {...{ containerClass: "fy-entity-input-row", panelClass: "fy-entity-input-button", noStyle: true, ...inputProps }}>
|
||||
<>
|
||||
<Icon {...{ className: "fy-entity-input-label-icon", icon: faFileArrowUp }}/>
|
||||
<div {...{ className: "fy-entity-input-upload-detail" }}>
|
||||
Upload, click or drag here
|
||||
{ filterType !== "all" && <span>{ filterType } files supported</span> }
|
||||
</div>
|
||||
</>
|
||||
</FileWrapper> }
|
||||
<div {...{ className: "fy-entity-input-row fy-entity-input-button", onClick: browserClick }}>
|
||||
<Icon {...{ className: "fy-entity-input-label-icon", icon: faGrid }}/>
|
||||
Choose from your { ["","media","weights"][entityType] }
|
||||
</div>
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
|
||||
const AniMod = ({ animating, className, isLeaving, render: Render, style, ...rest }: AniProps) => <a.div {...{
|
||||
className: `fy-slide-frame${ className ? " " + className : "" }`,
|
||||
style
|
||||
@@ -114,15 +60,21 @@ const AniMod = ({ animating, className, isLeaving, render: Render, style, ...res
|
||||
<Render {...{ ...rest, animating }} />
|
||||
</a.div>;
|
||||
|
||||
export default function EntityInput({ aspectRatio = "square", label, onChange, mediaType, weightType, ...rest }: Props) {
|
||||
const entityType = mediaType ? EntityType.media : weightType ? EntityType.weights : EntityType.unknown;
|
||||
const filterType = mediaType || weightType || "all";
|
||||
export default function EntityInput({ accept: inAccept, aspectRatio = "square", label, onChange, type, ...rest }: Props) {
|
||||
const accept = Array.isArray(inAccept) ? inAccept : [inAccept];
|
||||
const inputMode = EntityInputMode[type];
|
||||
const { search } = useLocation();
|
||||
const presetToken = search ? new URLSearchParams(search).get("preset_token") : "";
|
||||
const [mediaToken,mediaTokenSet] = useState(presetToken || "");
|
||||
const { media, mediaSet } = useMedia({ mediaToken });
|
||||
const { user } = useSession();
|
||||
const { open } = useModal();
|
||||
|
||||
const selectToken = (token: string) => {
|
||||
mediaTokenSet(token);
|
||||
onChange({ target: { name: "temp", value: token } });
|
||||
};
|
||||
|
||||
const { clear, inputProps } = useFile({
|
||||
onChange: (inputFile: any) => {
|
||||
if (inputFile) UploadMedia({
|
||||
@@ -133,17 +85,17 @@ export default function EntityInput({ aspectRatio = "square", label, onChange, m
|
||||
.then((res: UploadMediaResponse) => {
|
||||
if ("media_file_token" in res) {
|
||||
clear();
|
||||
mediaTokenSet(res.media_file_token);
|
||||
selectToken(res.media_file_token);
|
||||
}
|
||||
});
|
||||
else console.log("🥺 no file");
|
||||
}
|
||||
});
|
||||
const onSelect = (data: MediaFile) => {
|
||||
mediaSet(data)
|
||||
console.log("🔅",data);
|
||||
onChange({ target: { name: "temp", value: data.token } });
|
||||
}
|
||||
mediaSet(data);
|
||||
selectToken(data.token);
|
||||
};
|
||||
|
||||
const busy = false;
|
||||
const index = busy ? 0 : media ? 1 : 2;
|
||||
const [animating,animatingSet] = useState(false);
|
||||
@@ -157,12 +109,10 @@ export default function EntityInput({ aspectRatio = "square", label, onChange, m
|
||||
onStart: () => animatingSet(true)
|
||||
});
|
||||
|
||||
|
||||
return <>
|
||||
<Label {...{ label }}/>
|
||||
<div {...{ className: `fy-entity-input panel-inner${ aspectRatio ? " fy-entity-input-" + aspectRatio : "" }`, }}>
|
||||
{
|
||||
// media ? <MocapInputFull {...{ media }}/> : <MediaPickerEmpty {...{ inputProps, media, onSelect, open, user }}/>
|
||||
transitions((style: any, i: number, state: any) => {
|
||||
let isLeaving = state.phase === "leave";
|
||||
let sharedProps = { animating, isLeaving, media, style };
|
||||
@@ -170,9 +120,8 @@ export default function EntityInput({ aspectRatio = "square", label, onChange, m
|
||||
return [
|
||||
<AniMod {...{ render: MediaBusy, className: "fy-entity-input-busy", ...sharedProps }}/>,
|
||||
<AniMod {...{ render: MocapInputFull, className: "fy-entity-input-full", ...sharedProps }}/>,
|
||||
<AniMod {...{ render: MediaPickerEmpty, className: "fy-entity-input-empty", entityType, filterType, inputProps, onSelect, open, user, ...sharedProps, ...rest }}/>
|
||||
<AniMod {...{ render: EntityInputEmpty, className: "fy-entity-input-empty", accept, inputMode, inputProps, onSelect, open, user, ...sharedProps, ...rest }}/>
|
||||
][i];
|
||||
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import React from "react";
|
||||
import { AcceptTypes, EntityInputMode, MediaFilters } from "components/entities/EntityTypes";
|
||||
import { SlideProps } from "./EntityInput";
|
||||
import { MediaBrowser } from "components/modals";
|
||||
import { FileWrapper } from "components/common";
|
||||
import { FontAwesomeIcon as Icon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faDiagramSankey,
|
||||
faFile,
|
||||
faFileArrowUp,
|
||||
faGrid,
|
||||
faImage,
|
||||
faPersonWalking,
|
||||
faWaveform
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
|
||||
interface EmptySlideProps extends SlideProps {
|
||||
accept?: AcceptTypes[],
|
||||
inputMode: EntityInputMode,
|
||||
inputProps?: any,
|
||||
open: any,
|
||||
user: any
|
||||
};
|
||||
|
||||
const mediaCheck = (value: string) => (value in MediaFilters);
|
||||
|
||||
export default function EntityInputEmpty({ accept, open, inputMode, inputProps, user, ...rest }: EmptySlideProps) {
|
||||
const accepted = accept ? accept : [];
|
||||
const isMedia = !!accepted.find(mediaCheck);
|
||||
const browserClick = () => open({
|
||||
component: MediaBrowser,
|
||||
props: { accept, inputMode, username: user?.username || "", ...rest }
|
||||
});
|
||||
|
||||
const mediaIcons = () => {
|
||||
switch (accepted[0]) {
|
||||
case "audio": return faWaveform;
|
||||
case "image": return faImage;
|
||||
case "bvh": return faPersonWalking;
|
||||
default: return faFile;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const supported = `${ accepted.length ? accepted.join(", ") : accepted[0] } files supported`;
|
||||
|
||||
return <>
|
||||
<Icon {...{ className: "fy-entity-input-icon", icon: [faFile,mediaIcons(),faDiagramSankey,mediaIcons()][inputMode] }}/>
|
||||
<div {...{ className: "fy-entity-input-empty-controls" }}>
|
||||
{ isMedia &&
|
||||
<FileWrapper {...{ containerClass: "fy-entity-input-row", fileTypes: accepted, panelClass: "fy-entity-input-button", noStyle: true, ...inputProps }}>
|
||||
<>
|
||||
<Icon {...{ className: "fy-entity-input-label-icon", icon: faFileArrowUp }}/>
|
||||
<div {...{ className: "fy-entity-input-upload-detail" }}>
|
||||
Upload, click or drag here
|
||||
{ accept && <span>{ supported }</span> }
|
||||
</div>
|
||||
</>
|
||||
</FileWrapper> }
|
||||
<div {...{ className: "fy-entity-input-row fy-entity-input-button", onClick: browserClick }}>
|
||||
<Icon {...{ className: "fy-entity-input-label-icon", icon: faGrid }}/>
|
||||
Choose from your { ["bookmarks","media","weights"][inputMode] }
|
||||
</div>
|
||||
</div>
|
||||
</>;
|
||||
};
|
||||
@@ -1,9 +1,17 @@
|
||||
export enum EntityInputMode {
|
||||
bookmarks,
|
||||
media,
|
||||
weights,
|
||||
searchWeights,
|
||||
}
|
||||
|
||||
export enum MediaFilters {
|
||||
all,
|
||||
audio,
|
||||
image,
|
||||
video,
|
||||
bvh,
|
||||
glb,
|
||||
gltf,
|
||||
fbx
|
||||
}
|
||||
@@ -21,8 +29,10 @@ export enum WeightsFilters {
|
||||
vall_e
|
||||
}
|
||||
|
||||
export type EntityModeProp = keyof typeof EntityInputMode;
|
||||
export type MediaFilterProp = keyof typeof MediaFilters;
|
||||
export type WeightFilterProp = keyof typeof WeightsFilters;
|
||||
export type AcceptTypes = MediaFilterProp | WeightFilterProp;
|
||||
|
||||
export enum EntityType {
|
||||
unknown,
|
||||
@@ -30,12 +40,15 @@ export enum EntityType {
|
||||
weights
|
||||
}
|
||||
|
||||
export const EntityFilterOptions = ( mode: EntityType, t = (v:string) => v) => {
|
||||
const filters = [{},MediaFilters,WeightsFilters][mode];
|
||||
return mode ? Object.values(filters)
|
||||
export const EntityFilterOptions = ( mode?: EntityInputMode, t = (v:string) => v) => {
|
||||
const bookmarkFilters = Object.keys({ ...MediaFilters, ...WeightsFilters }).filter(val => isNaN(Number(val))).reduce((obj,current) => ({ ...obj, [current]: current }),{});;
|
||||
|
||||
const filters = mode !== undefined ? [bookmarkFilters,MediaFilters,WeightsFilters,WeightsFilters][mode] : EntityInputMode;
|
||||
|
||||
return Object.values(filters)
|
||||
.filter(val => isNaN(Number(val)))
|
||||
.map((value) => {
|
||||
if (typeof value === "string") return { value, label: t(value) }
|
||||
return { label: "all", value: "all" };
|
||||
}) : [];
|
||||
});
|
||||
};
|
||||
@@ -24,7 +24,7 @@ const MediaCards = ({ props, type }: MediaCardsProps) => {
|
||||
return <CardWrapper {...{ ...props, card: OverlayCard, preview: ImagePreview }}/>;
|
||||
case "video":
|
||||
return <CardWrapper {...{ ...props, card: OverlayCard, preview: VideoPreview }}/>;
|
||||
case "bvh":
|
||||
case "bvh": case "glb": case "gltf":
|
||||
return <CardWrapper {...{ ...props, card: OverlayCard, preview: MocapPreview }}/>;
|
||||
default:
|
||||
return <div>Unsupported media type</div>;
|
||||
|
||||
@@ -352,30 +352,26 @@ export default function SideNav({
|
||||
);
|
||||
}
|
||||
|
||||
let maybeImageGeneration = <></>;
|
||||
|
||||
if (sessionWrapper.canAccessStudio()) {
|
||||
maybeImageGeneration = (
|
||||
<>
|
||||
<li className="sidebar-heading">Image Generation</li>
|
||||
<li>
|
||||
<NavLink
|
||||
to="/text-to-image"
|
||||
activeClassName="active-link"
|
||||
onClick={handleNavLinkClick}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faMessageImage}
|
||||
className="sidebar-heading-icon"
|
||||
/>
|
||||
Text to Image
|
||||
{/* {t("videoStorytellerStudio")} */}
|
||||
</NavLink>
|
||||
</li>
|
||||
<hr className="mb-3 mt-3" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
let maybeImageGeneration = (
|
||||
<>
|
||||
<li className="sidebar-heading">Image Generation</li>
|
||||
<li>
|
||||
<NavLink
|
||||
to="/text-to-image"
|
||||
activeClassName="active-link"
|
||||
onClick={handleNavLinkClick}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faMessageImage}
|
||||
className="sidebar-heading-icon"
|
||||
/>
|
||||
Text to Image
|
||||
{/* {t("videoStorytellerStudio")} */}
|
||||
</NavLink>
|
||||
</li>
|
||||
<hr className="mb-3 mt-3" />
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,33 +1,27 @@
|
||||
import React, { useState } from "react";
|
||||
import { MediaList } from "components/entities";
|
||||
import {
|
||||
EntityType,
|
||||
EntityFilterOptions,
|
||||
MediaFilterProp,
|
||||
WeightFilterProp,
|
||||
} from "components/entities/EntityTypes";
|
||||
import { TempSelect } from "components/common";
|
||||
import { AcceptTypes, EntityInputMode, EntityFilterOptions, } from "components/entities/EntityTypes";
|
||||
import { Pagination, TempSelect } from "components/common";
|
||||
import AudioPlayerProvider from "components/common/AudioPlayer/AudioPlayerContext";
|
||||
import SkeletonCard from "components/common/Card/SkeletonCard";
|
||||
import Pagination from "components/common/Pagination";
|
||||
import { GetBookmarksByUser } from "@storyteller/components/src/api/bookmarks/GetBookmarksByUser";
|
||||
import { GetMediaByUser } from "@storyteller/components/src/api/media_files/GetMediaByUser";
|
||||
import { GetWeightsByUser } from "@storyteller/components/src/api/weights/GetWeightsByUser";
|
||||
import { SearchWeights } from "@storyteller/components/src/api/weights/SearchWeights";
|
||||
import { MediaFile } from "@storyteller/components/src/api/media_files/GetMedia";
|
||||
import { Weight } from "@storyteller/components/src/api/weights/GetWeight";
|
||||
import { useListContent, useRatings } from "hooks";
|
||||
import {
|
||||
faArrowDownWideShort,
|
||||
faFilter,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import { useListContent,
|
||||
// useRatings
|
||||
} from "hooks";
|
||||
import { faArrowDownWideShort, faFilter } from "@fortawesome/pro-solid-svg-icons";
|
||||
import prepFilter from "resources/prepFilter";
|
||||
import ModalHeader from "../ModalHeader";
|
||||
import "./MediaBrowser.scss";
|
||||
|
||||
interface Props {
|
||||
entityType: EntityType;
|
||||
filterType?: MediaFilterProp | WeightFilterProp;
|
||||
accept?: AcceptTypes[],
|
||||
handleClose: any;
|
||||
inputMode: EntityInputMode;
|
||||
mediaToken: string;
|
||||
onSelect?: any;
|
||||
owner?: string;
|
||||
@@ -36,30 +30,28 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function MediaBrowser({
|
||||
entityType,
|
||||
filterType: inputFilter,
|
||||
accept,
|
||||
mediaToken,
|
||||
handleClose = () => {},
|
||||
inputMode,
|
||||
onSelect,
|
||||
owner,
|
||||
search,
|
||||
username,
|
||||
username
|
||||
}: Props) {
|
||||
const ratings = useRatings();
|
||||
// const ratings = useRatings();
|
||||
const [showMasonryGrid, setShowMasonryGrid] = useState(true);
|
||||
const [filterType, filterTypeSet] = useState(inputFilter || "all");
|
||||
const [filterType, filterTypeSet] = useState(accept ? accept[0] : "all");
|
||||
const [list, listSet] = useState<MediaFile | Weight[]>([]);
|
||||
const fetcher = search
|
||||
? SearchWeights
|
||||
: [() => {}, GetMediaByUser, GetWeightsByUser][entityType] ||
|
||||
GetMediaByUser;
|
||||
const fetcher = [GetBookmarksByUser,GetMediaByUser,GetWeightsByUser,SearchWeights][inputMode];
|
||||
|
||||
const entities = useListContent({
|
||||
debug: "media browser",
|
||||
addQueries: {
|
||||
...(search ? {} : { page_size: 24 }),
|
||||
...prepFilter(
|
||||
filterType,
|
||||
["", "filter_media_type", "maybe_scoped_weight_type"][entityType]
|
||||
["maybe_scoped_weight_type", "filter_media_type", "maybe_scoped_weight_type",""][inputMode]
|
||||
),
|
||||
},
|
||||
addSetters: { filterTypeSet },
|
||||
@@ -69,12 +61,12 @@ export default function MediaBrowser({
|
||||
onInputChange: () => setShowMasonryGrid(false),
|
||||
onSuccess: res => {
|
||||
// bookmarks.gather({ res, key: "token" });
|
||||
ratings.gather({ res, key: "token" });
|
||||
// ratings.gather({ res, key: "token" });
|
||||
setShowMasonryGrid(true);
|
||||
},
|
||||
...(search ? { request: { search_term: search } } : {}),
|
||||
requestList: true,
|
||||
...(search ? { resultsKey: "weights" } : {}),
|
||||
// ...(search ? { resultsKey: "weights" } : {}),
|
||||
urlParam: owner || username,
|
||||
urlUpdate: false,
|
||||
});
|
||||
@@ -95,16 +87,25 @@ export default function MediaBrowser({
|
||||
// { value: "mostliked", label: "Most Liked" },
|
||||
];
|
||||
|
||||
const title = ["", `${owner ? owner + "'s " : ""}Media`, "Weights"][
|
||||
entityType
|
||||
];
|
||||
const onwerTxt = (entityName: string) => `${ owner ? owner + "'s " : "" }${ entityName }`;
|
||||
|
||||
const title = [
|
||||
onwerTxt("Bookmarks"),
|
||||
onwerTxt("Media"),
|
||||
onwerTxt("Weights"),
|
||||
"Search"
|
||||
][inputMode];
|
||||
|
||||
const onClick = (data: any) => {
|
||||
console.log("🩵", data);
|
||||
onSelect(data);
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const filterOptions = accept ? accept.map((value: string) => ({
|
||||
value,
|
||||
label: value
|
||||
})) : EntityFilterOptions(inputMode);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ModalHeader {...{ handleClose, title }}>
|
||||
@@ -117,11 +118,11 @@ export default function MediaBrowser({
|
||||
value: entities.sort,
|
||||
}}
|
||||
/>
|
||||
{(!inputFilter || inputFilter === "all") && (
|
||||
{(!accept || (accept && accept.length) ) && (
|
||||
<TempSelect
|
||||
{...{
|
||||
icon: faFilter,
|
||||
options: EntityFilterOptions(entityType),
|
||||
options: filterOptions,
|
||||
name: "filterType",
|
||||
onChange: entities.onChange,
|
||||
value: filterType,
|
||||
@@ -143,7 +144,7 @@ export default function MediaBrowser({
|
||||
<div {...{ className: "fy-media-browser-list" }}>
|
||||
<MediaList
|
||||
{...{
|
||||
entityType,
|
||||
entityType: 1,
|
||||
list: entities.list,
|
||||
success: entities.status === 3,
|
||||
onClick,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { SessionContext } from "context";
|
||||
import { Modal } from "components/common";
|
||||
import AccountModal from "components/layout/AccountModal";
|
||||
import { ModalView } from "context/SessionContext";
|
||||
import { StudioNotAvailable } from "v2/view/_common/StudioNotAvailable";
|
||||
|
||||
interface Props {
|
||||
children?: any;
|
||||
@@ -41,12 +42,11 @@ export default function SessionProvider({
|
||||
}
|
||||
};
|
||||
const userTokenMatch = (otherUserToken: string) =>
|
||||
!otherUserToken || !user?.user_token
|
||||
? false
|
||||
: user.user_token === otherUserToken;
|
||||
!otherUserToken || !user?.user_token ? false : user.user_token === otherUserToken;
|
||||
const canEditTtsModel = (userToken: string) =>
|
||||
user?.canEditOtherUsersTtsModels || userTokenMatch(userToken);
|
||||
const canBanUsers = () => user?.can_ban_users || false;
|
||||
const studioAccessCheck = (content: React.ElementType) => !user?.can_access_studio ? <StudioNotAvailable /> : content;
|
||||
|
||||
return (
|
||||
<SessionContext.Provider
|
||||
@@ -60,6 +60,7 @@ export default function SessionProvider({
|
||||
querySession,
|
||||
querySubscriptions,
|
||||
sessionFetched,
|
||||
studioAccessCheck,
|
||||
user,
|
||||
userTokenMatch,
|
||||
},
|
||||
|
||||
@@ -21,6 +21,7 @@ interface SessionContextType {
|
||||
querySession?: any;
|
||||
querySubscriptions?: any;
|
||||
sessionFetched: boolean;
|
||||
studioAccessCheck: (x:any) => any,
|
||||
user?: any;
|
||||
userTokenMatch: (token: string) => boolean;
|
||||
}
|
||||
@@ -31,6 +32,7 @@ export default createContext<SessionContextType>({
|
||||
check: () => false,
|
||||
loggedIn: false,
|
||||
sessionFetched: false,
|
||||
studioAccessCheck: () => null,
|
||||
modal: {
|
||||
close: () => {},
|
||||
open: () => {},
|
||||
|
||||
@@ -53,6 +53,7 @@ export default function useListContent({
|
||||
const fetchError = status === FetchStatus.error;
|
||||
|
||||
const pageChange = (page: number) => {
|
||||
onInputChange();
|
||||
pageSet(page);
|
||||
statusSet(FetchStatus.ready);
|
||||
};
|
||||
|
||||
@@ -29,9 +29,9 @@ export default function useLoraUpload() {
|
||||
const upload = () => {
|
||||
writeStatusSet(FetchStatus.in_progress);
|
||||
UploadLora("", {
|
||||
//...(coverImg.token
|
||||
// ? { cover_image_media_file_token: coverImg.token }
|
||||
// : {}),
|
||||
...(coverImg.token
|
||||
? { maybe_cover_image_media_file_token: coverImg.token }
|
||||
: {}),
|
||||
maybe_name: title,
|
||||
maybe_description: descriptionMD,
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useState } from "react";
|
||||
import { UploadModel } from "@storyteller/components/src/api/image_generation/UploadModel";
|
||||
import { FetchStatus } from "@storyteller/components/src/api/_common/SharedFetchTypes";
|
||||
import { useCoverImgUpload } from "hooks";
|
||||
import { useCoverImgUpload, useInferenceJobs } from "hooks";
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
// this hook is mostly for organizational purposes while I work -V
|
||||
@@ -13,6 +14,7 @@ export default function useSdUpload() {
|
||||
const [descriptionMD, descriptionMDSet] = useState("");
|
||||
const [writeStatus, writeStatusSet] = useState(FetchStatus.paused);
|
||||
const coverImg = useCoverImgUpload();
|
||||
const { enqueue } = useInferenceJobs(FrontendInferenceJobType.ImageGeneration, true);
|
||||
|
||||
const onChange = ({ target }: { target: { name: string; value: any } }) => {
|
||||
const todo: { [key: string]: (x: any) => void } = {
|
||||
@@ -28,7 +30,7 @@ export default function useSdUpload() {
|
||||
writeStatusSet(FetchStatus.in_progress);
|
||||
UploadModel("", {
|
||||
...(coverImg.token
|
||||
? { cover_image_media_file_token: coverImg.token }
|
||||
? { maybe_cover_image_media_file_token: coverImg.token }
|
||||
: {}),
|
||||
maybe_description: descriptionMD,
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
@@ -39,8 +41,7 @@ export default function useSdUpload() {
|
||||
})
|
||||
.then((res: any) => {
|
||||
writeStatusSet(FetchStatus.success);
|
||||
console.log("🌠", res);
|
||||
// history.replace(`/weight/${token}`);
|
||||
enqueue(res.inference_job_token);
|
||||
})
|
||||
.catch(err => {
|
||||
writeStatusSet(FetchStatus.error);
|
||||
|
||||
@@ -60,11 +60,11 @@ export default function EngineCompositor({ value, sessionWrapper }: Props) {
|
||||
</header>
|
||||
<EntityInput
|
||||
{...{
|
||||
accept: ["bvh","glb","gltf"],
|
||||
aspectRatio: "landscape",
|
||||
label: "Choose 3D data",
|
||||
onChange,
|
||||
type: "media",
|
||||
mediaType: "bvh",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState } from "react";
|
||||
import { EntityInput } from "components/entities";
|
||||
import { EntityFilterOptions, EntityType, MediaFilterProp, WeightFilterProp } from "components/entities/EntityTypes";
|
||||
import { useModal } from "hooks";
|
||||
import { EntityFilterOptions, EntityInputMode, EntityModeProp } from "components/entities/EntityTypes";
|
||||
import { useModal, useSession } from "hooks";
|
||||
import { InferenceJobsModal } from "components/modals";
|
||||
import { Button, SegmentButtons, TempInput, TempSelect } from "components/common";
|
||||
|
||||
@@ -9,42 +9,69 @@ interface Props {
|
||||
value?: any;
|
||||
}
|
||||
|
||||
interface Yank {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
export default function DevMediaInput({ value }: Props) {
|
||||
const { studioAccessCheck } = useSession();
|
||||
const [mediaToken,mediaTokenSet] = useState();
|
||||
const [mediaType,mediaTypeSet] = useState<MediaFilterProp>("all");
|
||||
const [weightType,weightTypeSet] = useState<WeightFilterProp>("all");
|
||||
const [entityType,entityTypeSet] = useState(EntityType.media);
|
||||
const [mode, modeSet] = useState<EntityModeProp>("media");
|
||||
const [filters,filtersSet] = useState<Yank>({
|
||||
bookmarks: "",
|
||||
media: "",
|
||||
weights: "",
|
||||
searchWeights: "",
|
||||
});
|
||||
const [owner,ownerSet] = useState("");
|
||||
const onChange = ({ target }: any) => mediaTokenSet(target.value);
|
||||
|
||||
const { open } = useModal();
|
||||
|
||||
const options = [{ label: "Media", value: EntityType.media },{ label: "Weights", value: EntityType.weights }];
|
||||
const changeFilter = ({ target }: { target: any }) => [mediaTypeSet,mediaTypeSet,weightTypeSet][entityType](target.value);
|
||||
const inputMode = EntityInputMode[mode];
|
||||
|
||||
const options = EntityFilterOptions();
|
||||
const filterOptions = EntityFilterOptions(inputMode);
|
||||
|
||||
// console.log("❌", mode, inputMode, filterOptions);
|
||||
|
||||
const changeFilter = ({ target }: { target: any }) => filtersSet({ ...filters, [inputMode]: target.value });
|
||||
|
||||
const openModal = () => open({ component: InferenceJobsModal });
|
||||
|
||||
return <div {...{ className: "fy-engine-compositor"}}>
|
||||
return studioAccessCheck(<div {...{ className: "fy-engine-compositor"}}>
|
||||
<div {...{ className: "panel engine-compositor-container" }}>
|
||||
<header>
|
||||
<h2>{ [526,187].map((num = 0) => String.fromCodePoint(128000 + num)) }</h2>
|
||||
<SegmentButtons {...{ onChange: ({ target }: { target: any }) => entityTypeSet(target.value), options, value: entityType }}/>
|
||||
<SegmentButtons {...{ onChange: ({ target }: { target: any }) => modeSet(target.value), options, value: mode }}/>
|
||||
<TempInput {...{ value: owner, onChange: ({ target }: { target: any }) => ownerSet(target.value), placeholder: "User" }}/>
|
||||
<TempSelect {...{ options: EntityFilterOptions(entityType), value: ["",mediaType,weightType][entityType], onChange: changeFilter }}/>
|
||||
</header>
|
||||
<EntityInput {...{
|
||||
aspectRatio: "landscape",
|
||||
label: `Choose ${ ["","media file","weight"][entityType] }`,
|
||||
onChange,
|
||||
owner,
|
||||
search: "Dream",
|
||||
type: "Media",
|
||||
...([{},{ mediaType },{ weightType }][entityType])
|
||||
}}/>
|
||||
<Button {...{ className: "mt-3", label: "Open modal", onClick: openModal, variant: "primary" }}/>
|
||||
<div>
|
||||
{ mediaToken }
|
||||
</div>
|
||||
{
|
||||
// <div {...{ className: "d-flex" }}>
|
||||
// { filterOptions.map((option,i) => {
|
||||
// return <Button {...{ label: option.label }}/>
|
||||
// }) }
|
||||
// </div>
|
||||
}
|
||||
<TempSelect {...{
|
||||
isMulti: true,
|
||||
options: filterOptions,
|
||||
value: filters[inputMode],
|
||||
onChange: changeFilter
|
||||
}}/>
|
||||
<EntityInput {...{
|
||||
accept: ["bvh","glb","gltf"],
|
||||
aspectRatio: "landscape",
|
||||
label: "not now",
|
||||
// label: `Choose ${ ["","media file","weight"][entityType] }`,
|
||||
onChange,
|
||||
owner,
|
||||
search: "Dream",
|
||||
type: "media"
|
||||
}}/>
|
||||
<Button {...{ className: "mt-3", label: "Open modal", onClick: openModal, variant: "primary" }}/>
|
||||
<div>
|
||||
{ mediaToken }
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
</div>);
|
||||
};
|
||||
@@ -1,19 +1,18 @@
|
||||
import React, { useState } from "react";
|
||||
import Panel from "components/common/Panel";
|
||||
import Container from "components/common/Container";
|
||||
import PageHeader from "components/layout/PageHeader";
|
||||
import React, { useState } from "react";
|
||||
import { useSession } from "hooks";
|
||||
import { Button } from "components/common";
|
||||
import { faUpload } from "@fortawesome/pro-solid-svg-icons";
|
||||
import {
|
||||
UploadMedia,
|
||||
UploadMediaResponse,
|
||||
} from "@storyteller/components/src/api/media_files/UploadMedia";
|
||||
import { UploadMedia, UploadMediaResponse, } from "@storyteller/components/src/api/media_files/UploadMedia";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
interface DevUploadProps {}
|
||||
|
||||
export default function DevUpload(props: DevUploadProps) {
|
||||
const { studioAccessCheck } = useSession();
|
||||
const [file, fileSet] = useState<File | null>(null);
|
||||
const [tokens, tokensSet] = useState<string[]>([]);
|
||||
|
||||
@@ -38,7 +37,7 @@ export default function DevUpload(props: DevUploadProps) {
|
||||
else console.log("🥺 no file");
|
||||
};
|
||||
|
||||
return (
|
||||
return studioAccessCheck(
|
||||
<Container type="padded" className="pt-4 pt-lg-5">
|
||||
<PageHeader
|
||||
title="Upload Generic File"
|
||||
|
||||
@@ -75,19 +75,13 @@ export default function MediaPage() {
|
||||
<MediaAudioComponent mediaFile={mediaFile} />
|
||||
|
||||
{/* Show TTS text input if it is a TTS result */}
|
||||
{mediaFile.public_bucket_path.includes("tts_inference_output") && (
|
||||
{mediaFile.maybe_text_transcript && (
|
||||
<div className="mt-4">
|
||||
<h5 className="fw-semibold">
|
||||
<FontAwesomeIcon icon={faSquareQuote} className="me-2" />
|
||||
Audio Text
|
||||
Audio Text Transcript
|
||||
</h5>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
|
||||
do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
Pellentesque elit ullamcorper dignissim cras tincidunt
|
||||
lobortis. Integer malesuada nunc vel risus commodo viverra
|
||||
maecenas accumsan lacus.
|
||||
</p>
|
||||
<p>{mediaFile.maybe_text_transcript}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -401,14 +395,14 @@ export default function MediaPage() {
|
||||
}}
|
||||
/>
|
||||
<BookmarkButton
|
||||
{...{
|
||||
large: true,
|
||||
...bookmarks.makeProps({
|
||||
entityToken: token,
|
||||
entityType: "media_file",
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
{...{
|
||||
large: true,
|
||||
...bookmarks.makeProps({
|
||||
entityToken: token,
|
||||
entityType: "media_file",
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -444,11 +438,11 @@ export default function MediaPage() {
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{mediaFile?.media_type === MediaFileType.BVH ? (
|
||||
{mediaFile?.media_type === MediaFileType.BVH || mediaFile?.media_type === MediaFileType.GLTF || mediaFile?.media_type === MediaFileType.GLB ? (
|
||||
<Button
|
||||
{...{
|
||||
icon: faVideoPlus,
|
||||
label: "Use BVH in Engine Compositor",
|
||||
label: "Use in Engine Compositor",
|
||||
to: `/engine-compositor?preset_token=${mediaFile.token}`,
|
||||
variant: "primary",
|
||||
className: "flex-grow-1",
|
||||
|
||||
@@ -11,7 +11,7 @@ import Pagination from "components/common/Pagination";
|
||||
|
||||
import { useBookmarks, useListContent, useRatings } from "hooks";
|
||||
import { GetBookmarksByUser } from "@storyteller/components/src/api/bookmarks/GetBookmarksByUser";
|
||||
import WeightsCards from "components/common/Card/WeightsCards";
|
||||
import BookmarksCards from "components/common/Card/BookmarksCards";
|
||||
import prepFilter from "resources/prepFilter";
|
||||
|
||||
export default function BookmarksTab({ username }: { username: string }) {
|
||||
@@ -210,23 +210,17 @@ export default function BookmarksTab({ username }: { username: string }) {
|
||||
onLayoutComplete={() => console.log("Layout complete!")}
|
||||
>
|
||||
{dataList.map((data: any, key: number) => {
|
||||
let weightProps = {
|
||||
let props = {
|
||||
bookmarks,
|
||||
data,
|
||||
// origin,
|
||||
ratings,
|
||||
showCreator: true,
|
||||
source,
|
||||
type: "weights",
|
||||
type: data.details?.entity_type === "media_file" ?
|
||||
"media" : "weights", // this is gross, but I'm replacing all of this anyway -V
|
||||
};
|
||||
|
||||
// let mediaProps = {
|
||||
// bookmarks,
|
||||
// data,
|
||||
// origin,
|
||||
// type: "media",
|
||||
// showCreator: true,
|
||||
// };
|
||||
|
||||
return (
|
||||
<div
|
||||
{...{
|
||||
@@ -234,15 +228,11 @@ export default function BookmarksTab({ username }: { username: string }) {
|
||||
key,
|
||||
}}
|
||||
>
|
||||
<WeightsCards
|
||||
{...{
|
||||
type: data.details.maybe_weight_data?.weight_category,
|
||||
props: weightProps,
|
||||
}}
|
||||
/>
|
||||
{/* <MediaCards
|
||||
{...{ type: data.media_type, props: mediaProps }}
|
||||
/> */}
|
||||
<BookmarksCards {...{
|
||||
entityType: data.details?.entity_type,
|
||||
type: data.details.maybe_weight_data?.weight_category || data.details.maybe_media_file_data?.media_type,
|
||||
props,
|
||||
}} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { faMessageImage } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { StudioNotAvailable } from "v2/view/_common/StudioNotAvailable";
|
||||
//import { StudioNotAvailable } from "v2/view/_common/StudioNotAvailable";
|
||||
|
||||
interface TextToImagePageProps {
|
||||
inferenceJobs: Array<InferenceJob>;
|
||||
@@ -27,9 +27,9 @@ export default function TextToImagePage({
|
||||
enqueueInferenceJob,
|
||||
inferenceJobs,
|
||||
}: TextToImagePageProps) {
|
||||
if (!sessionWrapper.canAccessStudio()) {
|
||||
return <StudioNotAvailable />;
|
||||
}
|
||||
//if (!sessionWrapper.canAccessStudio()) {
|
||||
// return <StudioNotAvailable />;
|
||||
//}
|
||||
|
||||
return (
|
||||
<Container type="panel">
|
||||
|
||||
@@ -41,7 +41,7 @@ import WeightCoverImage from "components/common/WeightCoverImage";
|
||||
import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
|
||||
import SdInferencePanel from "./inference_panels/SdInferencePanel";
|
||||
import SdCoverImagePanel from "./cover_image_panels/SdCoverImagePanel";
|
||||
import { StudioNotAvailable } from "v2/view/_common/StudioNotAvailable";
|
||||
//import { StudioNotAvailable } from "v2/view/_common/StudioNotAvailable";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
|
||||
interface WeightProps {
|
||||
@@ -110,15 +110,15 @@ export default function WeightPage({
|
||||
|
||||
const deleteWeight = () => remove(!!user?.can_ban_users);
|
||||
|
||||
//Studio Access feature flag
|
||||
switch (weight?.weight_type) {
|
||||
case WeightType.SD_15:
|
||||
case WeightType.SDXL:
|
||||
case WeightType.LORA:
|
||||
if (!sessionWrapper.canAccessStudio()) {
|
||||
return <StudioNotAvailable />;
|
||||
}
|
||||
}
|
||||
////Studio Access feature flag
|
||||
//switch (weight?.weight_type) {
|
||||
// case WeightType.SD_15:
|
||||
// case WeightType.SDXL:
|
||||
// case WeightType.LORA:
|
||||
// if (!sessionWrapper.canAccessStudio()) {
|
||||
// return <StudioNotAvailable />;
|
||||
// }
|
||||
//}
|
||||
|
||||
//Image generation panel if it's a lora weight or sd weight
|
||||
let imageGenPanel = <></>;
|
||||
|
||||
+27
-27
@@ -82,7 +82,7 @@ function SdInferencePanel({
|
||||
const [aspectRatio, setAspectRatio] = useState("square");
|
||||
const [cfgScale, setCfgScale] = useState(7);
|
||||
const [samples, setSamples] = useState(8);
|
||||
const [batchCount, setBatchCount] = useState(1);
|
||||
const [batchCount, setBatchCount] = useState(3);
|
||||
const [prompt, setPrompt] = useState("");
|
||||
const [negativePrompt, setNegativePrompt] = useState("");
|
||||
const onChange = onChanger({
|
||||
@@ -104,7 +104,7 @@ function SdInferencePanel({
|
||||
sampler: "DPM++ 2M Karras",
|
||||
cfgScale: 7,
|
||||
samples: 8,
|
||||
batchCount: 1,
|
||||
batchCount: 3,
|
||||
loraToken: null,
|
||||
};
|
||||
|
||||
@@ -377,11 +377,36 @@ function SdInferencePanel({
|
||||
value: aspectRatio,
|
||||
}}
|
||||
/>
|
||||
<div>
|
||||
<Label label="Number of Generations" />
|
||||
<PremiumLock
|
||||
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
|
||||
requiredPlan="pro"
|
||||
>
|
||||
<SegmentButtons
|
||||
{...{
|
||||
name: "batchCount",
|
||||
onChange,
|
||||
options: batchCountOpts,
|
||||
value: batchCount,
|
||||
}}
|
||||
/>
|
||||
</PremiumLock>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Accordion>
|
||||
<Accordion.Item title="Advanced">
|
||||
<div className="p-3 d-flex flex-column gap-3">
|
||||
<TempSelect
|
||||
{...{
|
||||
label: "Sampler",
|
||||
name: "sampler",
|
||||
onChange,
|
||||
options: samplerOpts,
|
||||
value: sampler,
|
||||
}}
|
||||
/>
|
||||
<div>
|
||||
<label className="sub-title">Seed</label>
|
||||
<div className="d-flex gap-2 align-items-center">
|
||||
@@ -402,15 +427,6 @@ function SdInferencePanel({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<TempSelect
|
||||
{...{
|
||||
label: "Sampler",
|
||||
name: "sampler",
|
||||
onChange,
|
||||
options: samplerOpts,
|
||||
value: sampler,
|
||||
}}
|
||||
/>
|
||||
<NumberSlider
|
||||
{...{
|
||||
min: 1,
|
||||
@@ -458,22 +474,6 @@ function SdInferencePanel({
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
<div>
|
||||
<Label label="Number of Generations" />
|
||||
<PremiumLock
|
||||
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
|
||||
requiredPlan="pro"
|
||||
>
|
||||
<SegmentButtons
|
||||
{...{
|
||||
name: "batchCount",
|
||||
onChange,
|
||||
options: batchCountOpts,
|
||||
value: batchCount,
|
||||
}}
|
||||
/>
|
||||
</PremiumLock>
|
||||
</div>{" "}
|
||||
</div>
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
|
||||
Reference in new issue
Block a user