mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-06 02:00:46 +00:00
Merge branch 'feature/mvp' of https://github.com/storytold/storyteller-frontend into feature/mvp
This commit is contained in:
commit
ac7cbe5aca
18 files changed
+233
-72
No files matched your search
@@ -2,7 +2,7 @@ import { ApiConfig } from "../ApiConfig";
|
||||
|
||||
export interface EnqueueImageGenRequest {
|
||||
uuid_idempotency_token: string;
|
||||
maybe_sd_model_token: string;
|
||||
maybe_sd_model_token: string | undefined;
|
||||
maybe_lora_model_token: string | null;
|
||||
maybe_prompt: string;
|
||||
maybe_n_prompt: string;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 174 KiB |
@@ -204,6 +204,7 @@ function initInferenceJobsByCategoryMap(): Map<
|
||||
);
|
||||
inferenceJobsByCategory.set(FrontendInferenceJobType.VoiceDesignerTts, []);
|
||||
inferenceJobsByCategory.set(FrontendInferenceJobType.VideoMotionCapture, []);
|
||||
inferenceJobsByCategory.set(FrontendInferenceJobType.ImageGeneration, []);
|
||||
inferenceJobsByCategory.set(FrontendInferenceJobType.ConvertFbxtoGltf, []);
|
||||
return inferenceJobsByCategory;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
background-color: $panel-inner;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
box-shadow: none !important;
|
||||
|
||||
.overlay {
|
||||
position: absolute;
|
||||
@@ -20,7 +21,7 @@
|
||||
font-size: 16px;
|
||||
pointer-events: all;
|
||||
text-shadow: 0 0 10px rgba(0, 0, 0, 1);
|
||||
border: 1px solid rgba($primary, 0.75);
|
||||
border: 1px solid rgba($primary, 0.4);
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
@@ -43,13 +43,13 @@ export default function PremiumLock({
|
||||
{hasAccess() ? (
|
||||
children
|
||||
) : (
|
||||
<Panel padding={true} className="fy-premium-lock rounded">
|
||||
<Panel className="fy-premium-lock rounded px-3 py-4">
|
||||
{children}
|
||||
<div className="overlay">
|
||||
<div className="d-flex flex-column align-items-center gap-2">
|
||||
<div className="d-flex flex-column align-items-center gap-2 text-center">
|
||||
<FontAwesomeIcon icon={faLock} className="me-2 fs-5" />
|
||||
<div>
|
||||
Feature requires{" "}
|
||||
This feature requires a{" "}
|
||||
<Link to="/pricing">{requiredPlan} subscription</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,7 +21,9 @@ export default function Label({
|
||||
}}
|
||||
>
|
||||
{label ? (
|
||||
<label {...{ className: `${required ? " required" : ""}`.trim() }}>
|
||||
<label
|
||||
{...{ className: `fw-medium ${required ? " required" : ""}`.trim() }}
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
) : null}
|
||||
|
||||
@@ -12,7 +12,7 @@ import SelectWeightsList from "./SelectWeightsList";
|
||||
interface TabConfig {
|
||||
label: string;
|
||||
tabKey: string;
|
||||
type?: "media" | "weights";
|
||||
type: "media" | "weights";
|
||||
weightTypeFilter?: string;
|
||||
mediaTypeFilter?: string;
|
||||
searcher?: boolean;
|
||||
@@ -21,11 +21,18 @@ interface SelectModalProps {
|
||||
label?: string;
|
||||
tabs: TabConfig[];
|
||||
modalTitle?: string;
|
||||
onSelect?: (token: string)=>void;
|
||||
onSelect?: (token: string) => void;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
const SelectModal = memo(
|
||||
({ label, tabs, modalTitle = "Select", onSelect }: SelectModalProps) => {
|
||||
({
|
||||
label,
|
||||
tabs,
|
||||
modalTitle = "Select",
|
||||
onSelect,
|
||||
required,
|
||||
}: SelectModalProps) => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const { token, setToken, weightTitle, setWeightTitle } = useToken();
|
||||
const [selectedValue, setSelectedValue] = useState("");
|
||||
@@ -41,18 +48,21 @@ const SelectModal = memo(
|
||||
useEffect(() => {
|
||||
const currentTab = tabs.find(tab => tab.tabKey === activeTab);
|
||||
setMediaType(currentTab?.mediaTypeFilter || "all");
|
||||
setWeightType(currentTab?.mediaTypeFilter || "all");
|
||||
setWeightType(currentTab?.weightTypeFilter || "all");
|
||||
}, [activeTab, tabs]);
|
||||
|
||||
useEffect(()=>{
|
||||
if(token && token !== selectedValue && onSelect){
|
||||
useEffect(() => {
|
||||
if (token && token !== selectedValue && onSelect) {
|
||||
setSelectedValue(token);
|
||||
onSelect(token);
|
||||
}else if(weightTitle && weightTitle !== selectedValue && onSelect){
|
||||
} else if (weightTitle && weightTitle !== selectedValue && onSelect) {
|
||||
setSelectedValue(weightTitle);
|
||||
onSelect(weightTitle);
|
||||
}
|
||||
}, [token, weightTitle, selectedValue, onSelect]);
|
||||
|
||||
console.log("token", token, "weightTitle", weightTitle);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [token, weightTitle]);
|
||||
|
||||
const openModal = () => {
|
||||
setIsModalOpen(true);
|
||||
@@ -101,7 +111,11 @@ const SelectModal = memo(
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
{label && <label className="sub-title">{label}</label>}
|
||||
{label && (
|
||||
<label className={`sub-title ${required && "required"}`.trim()}>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
|
||||
<div className="d-flex gap-2">
|
||||
<Input
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
faSignOutAlt,
|
||||
faCameraMovie,
|
||||
faPersonRays,
|
||||
faMessageImage,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import React, { useEffect, useState } from "react";
|
||||
@@ -341,7 +342,7 @@ export default function SideNav({
|
||||
{"Voice Designer"}
|
||||
</NavLink>
|
||||
</li>
|
||||
<hr className="mb-4 mt-3" />
|
||||
<hr className="mb-3 mt-3" />
|
||||
<li className="sidebar-heading">{t("videoTitle")}</li>
|
||||
<li>
|
||||
<NavLink
|
||||
@@ -384,6 +385,22 @@ export default function SideNav({
|
||||
{/* {t("videoStorytellerStudio")} */}
|
||||
</NavLink>
|
||||
</li>
|
||||
<hr className="mb-3 mt-3" />
|
||||
<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" />
|
||||
<li className="sidebar-heading">{t("communityTitle")}</li>
|
||||
@@ -400,7 +417,7 @@ export default function SideNav({
|
||||
{t("communityUploadModels")}
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<li className="mb-3">
|
||||
<a
|
||||
href="https://discord.gg/fakeyou"
|
||||
target="_blank"
|
||||
|
||||
@@ -32,7 +32,8 @@ export default function useLazyLists({
|
||||
const { pathname, search: locSearch } = useLocation();
|
||||
const history = useHistory();
|
||||
const urlQueries = new URLSearchParams(locSearch);
|
||||
const [next, nextSet] = useState(urlQueries.get("cursor") || "");
|
||||
const urlCursor = urlQueries.get("cursor");
|
||||
const [next, nextSet] = useState(urlCursor || "");
|
||||
const [previous, previousSet] = useState(""); // I am not used for anything yet :)
|
||||
const [sort, sortSet] = useState(urlQueries.get("sort_ascending") === "true");
|
||||
const [status, statusSet] = useState(
|
||||
@@ -61,6 +62,13 @@ export default function useLazyLists({
|
||||
statusSet(FetchStatus.ready);
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
listSet([]); // Reset list on filter/sort change
|
||||
nextSet("");
|
||||
previousSet("");
|
||||
statusSet(FetchStatus.ready);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const queries = {
|
||||
...(next ? { cursor: next } : {}),
|
||||
@@ -98,7 +106,7 @@ export default function useLazyLists({
|
||||
}
|
||||
});
|
||||
nextSet(res.pagination.maybe_next || "");
|
||||
previousSet(res.pagination.maybe_next);
|
||||
previousSet(res.pagination.maybe_previous);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -127,10 +135,12 @@ export default function useLazyLists({
|
||||
next,
|
||||
onChange,
|
||||
previous,
|
||||
reset,
|
||||
sort,
|
||||
sortSet,
|
||||
status,
|
||||
statusSet,
|
||||
totalKeys,
|
||||
urlCursor
|
||||
};
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
type Setter = (x: any) => void
|
||||
type Setter = (x: any) => void;
|
||||
|
||||
export default function onChanger({ ...setters }: { [key: string]: Setter }) {
|
||||
return ({ target }: { target: { name: string; value: any } }) => {
|
||||
const targetName =
|
||||
target.name.charAt(0).toUpperCase() + target.name.slice(1);
|
||||
const todo: { [key: string]: Setter } = setters;
|
||||
todo[target.name + "Set"](target.value);
|
||||
todo["set" + targetName](target.value);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -330,7 +330,7 @@ styles with important tags:
|
||||
0 15px 15px rgb(0 0 0 / 5%),
|
||||
0 10px 8px rgb(0 0 0 / 3%),
|
||||
0 4px 4px rgb(0 0 0 / 2%),
|
||||
0 2px 2px rgb(0 0 0 / 1%) !important;
|
||||
0 2px 2px rgb(0 0 0 / 1%);
|
||||
|
||||
.video-bg {
|
||||
background-color: $black;
|
||||
|
||||
@@ -110,6 +110,7 @@ import FbxToGltfPage from "./pages/fbx_to_gltf/FbxToGltfPage";
|
||||
import UploadLoraWeightPage from "./pages/upload/UploadLoraWeightPage";
|
||||
import StorytellerFilterPage from "./pages/storyteller_filter/StorytellerFilter";
|
||||
import ScrollToTop from "./_common/ScrollToTop";
|
||||
import TextToImagePage from "./pages/text_to_image/TextToImagePage";
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper;
|
||||
@@ -834,6 +835,15 @@ class PageContainer extends React.Component<
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/text-to-image">
|
||||
<TextToImagePage
|
||||
sessionSubscriptionsWrapper={
|
||||
this.props.sessionSubscriptionsWrapper
|
||||
}
|
||||
enqueueInferenceJob={this.props.enqueueInferenceJob}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="/character/donald-trump">
|
||||
<TrumpTtsPage
|
||||
sessionWrapper={this.props.sessionWrapper}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useRef, useState } from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import MasonryGrid from "components/common/MasonryGrid/MasonryGrid";
|
||||
import MediaCards from "components/common/Card/MediaCards";
|
||||
import { TempSelect } from "components/common";
|
||||
import { Button, TempSelect } from "components/common";
|
||||
import {
|
||||
faArrowDownWideShort,
|
||||
faFilter,
|
||||
@@ -59,6 +59,8 @@ export default function MediaTab() {
|
||||
// { value: "mostliked", label: "Most Liked" },
|
||||
];
|
||||
|
||||
console.log("💎",media.urlCursor);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="d-flex flex-wrap gap-3 mb-3">
|
||||
@@ -82,6 +84,7 @@ export default function MediaTab() {
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{ media.urlCursor ? <Button {...{ label: "Back to top", onClick: () => media.reset() }}/> : null }
|
||||
</div>
|
||||
<AudioPlayerProvider>
|
||||
{media.isLoading && !media.list.length ? (
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useRef, useState } from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import MasonryGrid from "components/common/MasonryGrid/MasonryGrid";
|
||||
import WeightsCards from "components/common/Card/WeightsCards";
|
||||
import { TempSelect } from "components/common";
|
||||
import { Button, TempSelect } from "components/common";
|
||||
import {
|
||||
faArrowDownWideShort,
|
||||
faFilter,
|
||||
@@ -145,6 +145,7 @@ export default function WeightsTab() {
|
||||
/>
|
||||
)} */}
|
||||
</div>
|
||||
{ weights.urlCursor ? <Button {...{ label: "Back to top", onClick: () => weights.reset() }}/> : null }
|
||||
</div>
|
||||
<AudioPlayerProvider>
|
||||
{weights.isLoading && !weights.list.length ? (
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { Container } from "components/common";
|
||||
import PageHeaderWithImage from "components/layout/PageHeaderWithImage";
|
||||
import React from "react";
|
||||
import SdInferencePanel from "../weight/inference_panels/SdInferencePanel";
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { faMessageImage } from "@fortawesome/pro-solid-svg-icons";
|
||||
import TextToImageJobsList from "./components/TextToImageJobsList";
|
||||
import { useInferenceJobs } from "hooks";
|
||||
|
||||
interface TextToImagePageProps {
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
enqueueInferenceJob: (
|
||||
jobToken: string,
|
||||
frontendInferenceJobType: FrontendInferenceJobType
|
||||
) => void;
|
||||
}
|
||||
|
||||
export default function TextToImagePage({
|
||||
sessionSubscriptionsWrapper,
|
||||
enqueueInferenceJob,
|
||||
}: TextToImagePageProps) {
|
||||
const { inferenceJobs } = useInferenceJobs(
|
||||
FrontendInferenceJobType.ImageGeneration
|
||||
);
|
||||
const hasImageGenJobs = inferenceJobs && inferenceJobs.length > 0;
|
||||
|
||||
return (
|
||||
<Container type="panel">
|
||||
<PageHeaderWithImage
|
||||
headerImage="/mascot/text-to-image.webp"
|
||||
titleIcon={faMessageImage}
|
||||
title="Text to Image"
|
||||
subText="Transform your thoughts into art."
|
||||
yOffset="76%"
|
||||
/>
|
||||
|
||||
{hasImageGenJobs && (
|
||||
<div className="mb-4">
|
||||
<TextToImageJobsList />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<SdInferencePanel
|
||||
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
|
||||
enqueueInferenceJob={enqueueInferenceJob}
|
||||
isStandalone={true}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
import React from "react";
|
||||
|
||||
import { Analytics } from "common/Analytics";
|
||||
import InferenceJobsList from "components/layout/InferenceJobsList";
|
||||
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
|
||||
export default function TextToImageJobsList() {
|
||||
const failures = (fail = "") => {
|
||||
switch (fail) {
|
||||
case "sample case":
|
||||
return "Sample Case, this should not have been shown";
|
||||
default:
|
||||
return "Unknown failure";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<InferenceJobsList
|
||||
{...{
|
||||
failures,
|
||||
onSelect: () => Analytics.voiceConversionClickDownload(),
|
||||
jobType: FrontendInferenceJobType.ImageGeneration,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
+12
-15
@@ -1,24 +1,26 @@
|
||||
import SelectModal from "components/common/SelectModal/SelectModal";
|
||||
import React, {useState} from "react";
|
||||
import React, { useState } from "react";
|
||||
import { Action, State } from "../videoMocapReducer";
|
||||
import { Button } from "components/common";
|
||||
|
||||
export default function TabContentLibrary({
|
||||
t, pageState, dispatchPageState
|
||||
t,
|
||||
pageState,
|
||||
dispatchPageState,
|
||||
}: {
|
||||
t: Function;
|
||||
pageState: State;
|
||||
dispatchPageState: (action: Action) => void;
|
||||
}){
|
||||
const [token, setToken] = useState<string|undefined>();
|
||||
const handleProceed = ()=>{
|
||||
if(token)
|
||||
}) {
|
||||
const [token, setToken] = useState<string | undefined>();
|
||||
const handleProceed = () => {
|
||||
if (token)
|
||||
dispatchPageState({
|
||||
type: "selectedFile",
|
||||
payload: {mediaFileToken: token}
|
||||
payload: { mediaFileToken: token },
|
||||
});
|
||||
}
|
||||
const handleOnSelect = (token:string)=>{
|
||||
};
|
||||
const handleOnSelect = (token: string) => {
|
||||
setToken(token);
|
||||
};
|
||||
|
||||
@@ -38,12 +40,7 @@ export default function TabContentLibrary({
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{token &&
|
||||
<Button
|
||||
label={t("button.proceed")}
|
||||
onClick={handleProceed}
|
||||
/>
|
||||
}
|
||||
{token && <Button label={t("button.proceed")} onClick={handleProceed} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+58
-32
@@ -2,6 +2,7 @@ import React, { useRef, useState, memo } from "react";
|
||||
import {
|
||||
Button,
|
||||
Input,
|
||||
Label,
|
||||
NumberSlider,
|
||||
Panel,
|
||||
SegmentButtons,
|
||||
@@ -28,19 +29,26 @@ import PremiumLock from "components/PremiumLock";
|
||||
|
||||
interface SdInferencePanelProps {
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
sd_model_token: string;
|
||||
sd_model_token?: string;
|
||||
enqueueInferenceJob: (
|
||||
jobToken: string,
|
||||
frontendInferenceJobType: FrontendInferenceJobType
|
||||
) => void;
|
||||
isStandalone?: boolean;
|
||||
}
|
||||
|
||||
function SdInferencePanel({
|
||||
enqueueInferenceJob,
|
||||
sd_model_token,
|
||||
sessionSubscriptionsWrapper,
|
||||
isStandalone = false,
|
||||
}: SdInferencePanelProps) {
|
||||
const [loraToken, setLoraToken] = useState<string | null>(null);
|
||||
const [weightToken, setWeightToken] = useState(sd_model_token);
|
||||
|
||||
const handleOnWeightSelect = (token: string) => {
|
||||
setWeightToken(token);
|
||||
};
|
||||
|
||||
const handleOnSelect = (token: string) => {
|
||||
setLoraToken(token);
|
||||
@@ -226,7 +234,7 @@ function SdInferencePanel({
|
||||
) => {
|
||||
ev.preventDefault();
|
||||
|
||||
if (!prompt) {
|
||||
if (!prompt || weightToken === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -243,7 +251,7 @@ function SdInferencePanel({
|
||||
|
||||
const request = {
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
maybe_sd_model_token: sd_model_token,
|
||||
maybe_sd_model_token: isStandalone ? weightToken : sd_model_token,
|
||||
maybe_lora_model_token: loraToken,
|
||||
maybe_prompt: prompt,
|
||||
maybe_n_prompt: negativePrompt,
|
||||
@@ -282,6 +290,31 @@ function SdInferencePanel({
|
||||
<h4 className="fw-semibold mb-4">Generate an Image</h4>
|
||||
|
||||
<div className="d-flex flex-column gap-3 mb-4">
|
||||
{isStandalone && (
|
||||
<SelectModal
|
||||
required={true}
|
||||
modalTitle="Select a Weight"
|
||||
label="Select a Weight"
|
||||
onSelect={handleOnWeightSelect}
|
||||
tabs={[
|
||||
{
|
||||
label: "All Weights",
|
||||
tabKey: "allWeights",
|
||||
weightTypeFilter: "sdxl",
|
||||
searcher: true,
|
||||
type: "weights",
|
||||
},
|
||||
{
|
||||
label: "Bookmarked",
|
||||
tabKey: "bookmarkedWeights",
|
||||
weightTypeFilter: "sdxl",
|
||||
searcher: false,
|
||||
type: "weights",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
<TempTextArea
|
||||
{...{
|
||||
label: "Prompt",
|
||||
@@ -293,7 +326,7 @@ function SdInferencePanel({
|
||||
/>
|
||||
<TempTextArea
|
||||
{...{
|
||||
label: "Negative prompt",
|
||||
label: "Negative Prompt",
|
||||
name: "negativePrompt",
|
||||
placeholder: "Enter a negative prompt",
|
||||
onChange: handleNegativePromptChange,
|
||||
@@ -377,43 +410,36 @@ function SdInferencePanel({
|
||||
{
|
||||
label: "All LoRA Weights",
|
||||
tabKey: "allLoraWeights",
|
||||
weightTypeFilter: "lora",
|
||||
weightTypeFilter: "rvc_v2",
|
||||
searcher: true,
|
||||
type: "weights",
|
||||
},
|
||||
{
|
||||
label: "Bookmarked",
|
||||
tabKey: "bookmarkedLoraWeights",
|
||||
weightTypeFilter: "lora",
|
||||
weightTypeFilter: "rvc_v2",
|
||||
searcher: false,
|
||||
type: "weights",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
{/* Checkpoint Use weight token */}
|
||||
{/* <TempSelect
|
||||
{...{
|
||||
label: "Checkpoint",
|
||||
name: "checkPoint",
|
||||
onChange,
|
||||
options: tempDeleteMeOpts,
|
||||
value: checkPoint,
|
||||
}}
|
||||
/> */}
|
||||
|
||||
<PremiumLock
|
||||
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
|
||||
requiredPlan="pro"
|
||||
>
|
||||
<SegmentButtons
|
||||
{...{
|
||||
label: "Number of Generations",
|
||||
name: "batchCount",
|
||||
onChange,
|
||||
options: batchCountOpts,
|
||||
value: batchCount,
|
||||
}}
|
||||
/>
|
||||
</PremiumLock>
|
||||
<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>
|
||||
@@ -429,7 +455,7 @@ function SdInferencePanel({
|
||||
<Button
|
||||
{...{
|
||||
label: "Generate Image",
|
||||
disabled: prompt === "",
|
||||
disabled: prompt === "" || weightToken === undefined,
|
||||
onClick: handleEnqueueImageGen,
|
||||
isLoading: isEnqueuing,
|
||||
}}
|
||||
|
||||
Reference in new issue
Block a user