mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-11 20:32:12 +00:00
Merge branch 'feature/mvp' of https://github.com/storytold/storyteller-frontend into feature/mvp
This commit is contained in:
commit
7bd96db165
23 files changed
+190
-90
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 | undefined;
|
||||
maybe_sd_model_token: string | null;
|
||||
maybe_lora_model_token: string | null;
|
||||
maybe_prompt: string;
|
||||
maybe_n_prompt: string;
|
||||
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "আসল",
|
||||
"preview": "পূর্বরূপ",
|
||||
"upload": "আপলোড করুন"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "লাইব্রেরি থেকে একটি ভিডিও আপলোড করুন বা নির্বাচন করুন, তারপর আমাদের ওয়ার্কফ্লো কন্ট্রোল প্যানেলের সাথে ফিল্টারিং ওয়ার্কফ্লো সেটআপ করুন৷"
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "Original",
|
||||
"preview": "Vorschau",
|
||||
"upload": "Hochladen"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "Laden Sie ein Video hoch oder wählen Sie es aus der Bibliothek aus und richten Sie dann den Filter-Workflow mit unserem Workflow-Kontrollfeld ein."
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "Original",
|
||||
"preview": "Preview",
|
||||
"upload": "Upload"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "Upload or select a video from the library, then setup the filtering workflow with our workflow control panel."
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "Original",
|
||||
"preview": "Avance",
|
||||
"upload": "Subir"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "Cargue o seleccione un video de la biblioteca, luego configure el flujo de trabajo de filtrado con nuestro panel de control de flujo de trabajo."
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "Original",
|
||||
"preview": "Aperçu",
|
||||
"upload": "Télécharger"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "Téléchargez ou sélectionnez une vidéo dans la bibliothèque, puis configurez le flux de travail de filtrage avec notre panneau de contrôle de flux de travail."
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "मूल",
|
||||
"preview": "पूर्व दर्शन",
|
||||
"upload": "डालना"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "लाइब्रेरी से एक वीडियो अपलोड करें या चुनें, फिर हमारे वर्कफ़्लो नियंत्रण कक्ष के साथ फ़िल्टरिंग वर्कफ़्लो सेटअप करें।"
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "Asli",
|
||||
"preview": "Pratinjau",
|
||||
"upload": "Mengunggah"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "Unggah atau pilih video dari perpustakaan, lalu atur alur kerja pemfilteran dengan panel kontrol alur kerja kami."
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "Originale",
|
||||
"preview": "Anteprima",
|
||||
"upload": "Caricamento"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "Carica o seleziona un video dalla libreria, quindi imposta il flusso di lavoro di filtraggio con il nostro pannello di controllo del flusso di lavoro."
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "オリジナル",
|
||||
"preview": "プレビュー",
|
||||
"upload": "アップロード"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "ライブラリからビデオをアップロードまたは選択し、ワークフロー コントロール パネルでフィルタリング ワークフローをセットアップします。"
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "원래의",
|
||||
"preview": "시사",
|
||||
"upload": "업로드"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "라이브러리에서 비디오를 업로드하거나 선택한 다음 워크플로 제어판을 사용하여 필터링 워크플로를 설정하세요."
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "Original",
|
||||
"preview": "Visualização",
|
||||
"upload": "Carregar"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "Carregue ou selecione um vídeo da biblioteca e configure o fluxo de trabalho de filtragem com nosso painel de controle de fluxo de trabalho."
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "Оригинал",
|
||||
"preview": "Предварительный просмотр",
|
||||
"upload": "Загрузить"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "Загрузите или выберите видео из библиотеки, а затем настройте процесс фильтрации с помощью нашей панели управления рабочим процессом."
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "ต้นฉบับ",
|
||||
"preview": "ดูตัวอย่าง",
|
||||
"upload": "ที่อัพโหลด"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "อัปโหลดหรือเลือกวิดีโอจากไลบรารี จากนั้นตั้งค่าเวิร์กโฟลว์การกรองด้วยแผงควบคุมเวิร์กโฟลว์ของเรา"
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "Orijinal",
|
||||
"preview": "Ön izleme",
|
||||
"upload": "Yüklemek"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "Kitaplıktan bir video yükleyin veya seçin, ardından iş akışı kontrol panelimizle filtreleme iş akışını ayarlayın."
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "Nguyên bản",
|
||||
"preview": "Xem trước",
|
||||
"upload": "Tải lên"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "Tải lên hoặc chọn video từ thư viện, sau đó thiết lập quy trình lọc bằng bảng điều khiển quy trình làm việc của chúng tôi."
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,8 @@
|
||||
"original": "原来的",
|
||||
"preview": "预览",
|
||||
"upload": "上传"
|
||||
},
|
||||
"video": {
|
||||
"instruction": "从库中上传或选择视频,然后使用我们的工作流程控制面板设置过滤工作流程。"
|
||||
}
|
||||
}
|
||||
@@ -46,8 +46,6 @@ const SelectModal = memo(
|
||||
activeTab: tabs[0].tabKey,
|
||||
valueType: tabs[0].typeFilter || "all",
|
||||
});
|
||||
console.log("🔫", tabs, activeTab, valueType);
|
||||
|
||||
// Update mediaType when activeTab changes
|
||||
useEffect(() => {
|
||||
const currentTab = tabs.find(tab => tab.tabKey === activeTab);
|
||||
|
||||
@@ -15,7 +15,7 @@ import React, { useEffect, useState } from "react";
|
||||
import { Link, useHistory } from "react-router-dom";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { Logout } from "@storyteller/components/src/api/session/Logout";
|
||||
import { useModal } from "hooks";
|
||||
import { useModal, useSession } from "hooks";
|
||||
import { InferenceJobsModal } from "components/modals";
|
||||
import { useDomainConfig } from "context/DomainConfigContext";
|
||||
import NavItem from "../../common/NavItem/NavItem";
|
||||
@@ -112,12 +112,14 @@ export default function TopNav({
|
||||
|
||||
let profileDropdown = <></>;
|
||||
|
||||
const { user } = useSession();
|
||||
|
||||
if (sessionWrapper.isLoggedIn()) {
|
||||
let displayName = sessionWrapper.getDisplayName();
|
||||
let username = sessionWrapper.getUsername();
|
||||
let emailHash = sessionWrapper.getEmailGravatarHash();
|
||||
let avatarIndex = 0; //temporary
|
||||
let backgroundColorIndex = 0; //temporary
|
||||
let displayName = user.display_name;
|
||||
let username = user.username;
|
||||
let emailHash = user.email_gravatar_hash;
|
||||
let avatarIndex = user.core_info.default_avatar.image_index;
|
||||
let backgroundColorIndex = user.core_info.default_avatar.color_index;
|
||||
|
||||
profileDropdown = (
|
||||
<ProfileDropdown
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
faLink,
|
||||
faFileCircleXmark,
|
||||
faArrowRightArrowLeft,
|
||||
faVideoPlus
|
||||
faVideoPlus,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import Accordion from "components/common/Accordion";
|
||||
import DataTable from "components/common/DataTable";
|
||||
@@ -41,7 +41,11 @@ export default function MediaPage() {
|
||||
const { token } = useParams<{ token: string }>();
|
||||
const bookmarks = useBookmarks();
|
||||
const ratings = useRatings();
|
||||
const { media: mediaFile, remove, status } = useMedia({
|
||||
const {
|
||||
media: mediaFile,
|
||||
remove,
|
||||
status,
|
||||
} = useMedia({
|
||||
mediaToken: token,
|
||||
onSuccess: (res: any) => {
|
||||
ratings.gather({ res, key: "token" });
|
||||
@@ -52,8 +56,6 @@ export default function MediaPage() {
|
||||
const dateCreated = moment(mediaFile?.created_at || "").format("LLL");
|
||||
const [buttonLabel, setButtonLabel] = useState("Copy");
|
||||
|
||||
|
||||
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
|
||||
const closeDeleteModal = () => setIsDeleteModalOpen(false);
|
||||
@@ -296,7 +298,7 @@ export default function MediaPage() {
|
||||
break;
|
||||
default:
|
||||
mediaDetails = defaultDetails;
|
||||
break
|
||||
break;
|
||||
}
|
||||
|
||||
let modMediaDetails = undefined;
|
||||
@@ -370,7 +372,14 @@ export default function MediaPage() {
|
||||
<div className="d-flex gap-3 flex-wrap align-items-center">
|
||||
<div className="d-flex gap-2 align-items-center flex-wrap">
|
||||
<div>
|
||||
<Badge {...{ className: `fy-entity-type-${ mediaFile?.media_type || "" }`, label: mediaType, }}/>
|
||||
<Badge
|
||||
{...{
|
||||
className: `fy-entity-type-${
|
||||
mediaFile?.media_type || ""
|
||||
}`,
|
||||
label: mediaType,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{subtitleDivider}
|
||||
|
||||
@@ -424,7 +433,7 @@ export default function MediaPage() {
|
||||
<div className="col-12 col-xl-4">
|
||||
<div className="panel panel-clear d-flex flex-column gap-3">
|
||||
<div className="d-flex gap-2 flex-wrap">
|
||||
{ mediaFile?.media_type === MediaFileType.Audio ? (
|
||||
{mediaFile?.media_type === MediaFileType.Audio ? (
|
||||
<Button
|
||||
{...{
|
||||
icon: faFaceViewfinder,
|
||||
@@ -434,8 +443,8 @@ export default function MediaPage() {
|
||||
className: "flex-grow-1",
|
||||
}}
|
||||
/>
|
||||
) : null }
|
||||
{ mediaFile?.media_type === MediaFileType.BVH ? (
|
||||
) : null}
|
||||
{mediaFile?.media_type === MediaFileType.BVH ? (
|
||||
<Button
|
||||
{...{
|
||||
icon: faVideoPlus,
|
||||
@@ -445,7 +454,7 @@ export default function MediaPage() {
|
||||
className: "flex-grow-1",
|
||||
}}
|
||||
/>
|
||||
) : null }
|
||||
) : null}
|
||||
|
||||
{mediaFile?.media_type !== MediaFileType.Audio && (
|
||||
<Button
|
||||
@@ -455,6 +464,7 @@ export default function MediaPage() {
|
||||
href={audioLink}
|
||||
download={audioLink}
|
||||
variant="secondary"
|
||||
target="_blank"
|
||||
/>
|
||||
)}
|
||||
{mediaFile?.media_type === MediaFileType.Audio && (
|
||||
@@ -466,6 +476,7 @@ export default function MediaPage() {
|
||||
href={audioLink}
|
||||
download={audioLink}
|
||||
tooltip="Download"
|
||||
target="_blank"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -639,7 +650,7 @@ export default function MediaPage() {
|
||||
handleClose={closeDeleteModal}
|
||||
title="Delete Media"
|
||||
content={() => (
|
||||
<>{`Are you sure you want to delete this media file? This action cannot be undone.`}</> // replace w/ dynamic later -V
|
||||
<>{`Are you sure you want to delete this media file? This action cannot be undone.`}</> // replace w/ dynamic later -V
|
||||
// <>{`Are you sure you want to delete "${title}"? This action cannot be undone.`}</>
|
||||
)}
|
||||
onConfirm={deleteMedia}
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ export default function PageVideoProvision({
|
||||
<div className="col-12 col-md-6">
|
||||
<Panel padding={true} clear={true}>
|
||||
<BasicVideo
|
||||
title={t("video.sample")}
|
||||
title={t("video.instruction")}
|
||||
src="/videos/face-animator-instruction-en.mp4"
|
||||
/>
|
||||
</Panel>
|
||||
|
||||
@@ -110,6 +110,7 @@ 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:
|
||||
@@ -119,6 +120,34 @@ export default function WeightPage({
|
||||
}
|
||||
}
|
||||
|
||||
//Image generation panel if it's a lora weight or sd weight
|
||||
let imageGenPanel = <></>;
|
||||
switch (weight?.weight_type) {
|
||||
case WeightType.SD_15:
|
||||
case WeightType.SDXL:
|
||||
imageGenPanel = (
|
||||
<SdInferencePanel
|
||||
inferenceJobs={inferenceJobs}
|
||||
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
|
||||
weight_token={weight?.weight_token}
|
||||
enqueueInferenceJob={enqueueInferenceJob}
|
||||
weightPageType="sd"
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case WeightType.LORA:
|
||||
imageGenPanel = (
|
||||
<SdInferencePanel
|
||||
inferenceJobs={inferenceJobs}
|
||||
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
|
||||
weight_token={weight?.weight_token}
|
||||
enqueueInferenceJob={enqueueInferenceJob}
|
||||
weightPageType="lora"
|
||||
/>
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
function renderWeightComponent(weight: Weight) {
|
||||
switch (weight.weight_category) {
|
||||
case WeightCategory.TTS:
|
||||
@@ -168,12 +197,7 @@ export default function WeightPage({
|
||||
return (
|
||||
<div className="d-flex flex-column gap-3">
|
||||
<SdCoverImagePanel src={sdCoverImage} />
|
||||
<SdInferencePanel
|
||||
inferenceJobs={inferenceJobs}
|
||||
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
|
||||
sd_model_token={weight.weight_token}
|
||||
enqueueInferenceJob={enqueueInferenceJob}
|
||||
/>
|
||||
{imageGenPanel}
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
|
||||
+80
-63
@@ -1,4 +1,4 @@
|
||||
import React, { useRef, useState, memo } from "react";
|
||||
import React, { useRef, useState, memo, useEffect } from "react";
|
||||
import {
|
||||
Accordion,
|
||||
Button,
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
faRectangleLandscape,
|
||||
faRectanglePortrait,
|
||||
faSquare,
|
||||
faUpload,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import {
|
||||
@@ -34,30 +33,43 @@ import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session
|
||||
import PremiumLock from "components/PremiumLock";
|
||||
import InferenceJobsList from "components/layout/InferenceJobsList";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
interface SdInferencePanelProps {
|
||||
inferenceJobs: Array<InferenceJob>;
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
sd_model_token?: string;
|
||||
weight_token?: string;
|
||||
enqueueInferenceJob: (
|
||||
jobToken: string,
|
||||
frontendInferenceJobType: FrontendInferenceJobType
|
||||
) => void;
|
||||
isStandalone?: boolean;
|
||||
weightPageType?: "lora" | "sd";
|
||||
}
|
||||
|
||||
function SdInferencePanel({
|
||||
enqueueInferenceJob,
|
||||
sd_model_token,
|
||||
weight_token,
|
||||
sessionSubscriptionsWrapper,
|
||||
isStandalone = false,
|
||||
inferenceJobs,
|
||||
weightPageType = "sd",
|
||||
}: SdInferencePanelProps) {
|
||||
const [loraToken, setLoraToken] = useState<string | null>(null);
|
||||
const [weightToken, setWeightToken] = useState(sd_model_token);
|
||||
const [sdToken, setSdToken] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (weightPageType === "sd") {
|
||||
setSdToken(weight_token || null);
|
||||
setLoraToken(null);
|
||||
} else if (weightPageType === "lora") {
|
||||
setLoraToken(weight_token || null);
|
||||
setSdToken(null);
|
||||
}
|
||||
}, [weightPageType, weight_token]);
|
||||
|
||||
const handleOnWeightSelect = (data: { token: string; title: string }) => {
|
||||
setWeightToken(data.token);
|
||||
setSdToken(data.token);
|
||||
};
|
||||
const handleOnSelect = (data: { token: string; title: string }) => {
|
||||
setLoraToken(data.token);
|
||||
@@ -243,7 +255,7 @@ function SdInferencePanel({
|
||||
) => {
|
||||
ev.preventDefault();
|
||||
|
||||
if (!prompt || weightToken === undefined) {
|
||||
if (!prompt || sdToken === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -258,10 +270,12 @@ function SdInferencePanel({
|
||||
internalSeed.current = generateRandomSeed();
|
||||
}
|
||||
|
||||
console.log(sdToken);
|
||||
|
||||
const request = {
|
||||
uuid_idempotency_token: uuidv4(),
|
||||
maybe_sd_model_token: isStandalone ? weightToken : sd_model_token,
|
||||
maybe_lora_model_token: loraToken,
|
||||
maybe_sd_model_token: sdToken || null,
|
||||
maybe_lora_model_token: loraToken || null,
|
||||
maybe_prompt: prompt,
|
||||
maybe_n_prompt: negativePrompt,
|
||||
maybe_seed: internalSeed.current,
|
||||
@@ -305,29 +319,16 @@ function SdInferencePanel({
|
||||
<div>
|
||||
<SplitPanel dividerHeader={true}>
|
||||
<SplitPanel.Header padding={true}>
|
||||
<div className="d-flex flex-wrap gap-2 align-items-center">
|
||||
<h4 className="fw-semibold mb-0 flex-grow-1">Generate an Image</h4>
|
||||
{isStandalone && (
|
||||
<div>
|
||||
<Button
|
||||
icon={faUpload}
|
||||
label="Upload Weight"
|
||||
variant="secondary"
|
||||
small={true}
|
||||
to="/upload/sd"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<h4 className="fw-semibold mb-0 flex-grow-1">Generate an Image</h4>
|
||||
</SplitPanel.Header>
|
||||
|
||||
<SplitPanel.Body padding={true}>
|
||||
<div className="d-flex flex-column gap-3 mb-4">
|
||||
{isStandalone && (
|
||||
{(isStandalone || weightPageType === "lora") && (
|
||||
<SelectModal
|
||||
required={true}
|
||||
modalTitle="Select a Weight"
|
||||
label="Select a Weight"
|
||||
modalTitle="Select Stable Diffusion Weight"
|
||||
label="Select a Stable Diffusion Weight"
|
||||
onSelect={handleOnWeightSelect}
|
||||
tabs={[
|
||||
{
|
||||
@@ -433,27 +434,30 @@ function SdInferencePanel({
|
||||
value: samples,
|
||||
}}
|
||||
/>
|
||||
<SelectModal
|
||||
label="Additional LoRA Weight"
|
||||
onSelect={handleOnSelect}
|
||||
tabs={[
|
||||
{
|
||||
label: "All LoRA Weights",
|
||||
tabKey: "allLoraWeights",
|
||||
typeFilter: "loRA",
|
||||
searcher: true,
|
||||
type: "weights",
|
||||
},
|
||||
{
|
||||
label: "Bookmarked",
|
||||
tabKey: "bookmarkedLoraWeights",
|
||||
typeFilter: "loRA",
|
||||
searcher: false,
|
||||
type: "weights",
|
||||
onlyBookmarked: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{weightPageType === "sd" && (
|
||||
<SelectModal
|
||||
modalTitle="Select LoRA Weight"
|
||||
label="Additional LoRA Weight"
|
||||
onSelect={handleOnSelect}
|
||||
tabs={[
|
||||
{
|
||||
label: "All LoRA Weights",
|
||||
tabKey: "allLoraWeights",
|
||||
typeFilter: "loRA",
|
||||
searcher: true,
|
||||
type: "weights",
|
||||
},
|
||||
{
|
||||
label: "Bookmarked",
|
||||
tabKey: "bookmarkedLoraWeights",
|
||||
typeFilter: "loRA",
|
||||
searcher: false,
|
||||
type: "weights",
|
||||
onlyBookmarked: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
<div>
|
||||
<Label label="Number of Generations" />
|
||||
<PremiumLock
|
||||
@@ -473,22 +477,35 @@ function SdInferencePanel({
|
||||
</div>
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
<div className="d-flex gap-2 justify-content-end mt-4 mb-3">
|
||||
<Button
|
||||
{...{
|
||||
label: "Clear All",
|
||||
variant: "secondary",
|
||||
onClick: resetToInitialState,
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
{...{
|
||||
label: "Generate Image",
|
||||
disabled: prompt === "" || weightToken === "",
|
||||
onClick: handleEnqueueImageGen,
|
||||
isLoading: isEnqueuing,
|
||||
}}
|
||||
/>
|
||||
<div className="d-flex mt-4 align-items-center flex-wrap gap-4">
|
||||
{isStandalone && (
|
||||
<div className="flex-grow-1">
|
||||
<p className="fs-7">
|
||||
<span className="opacity-75">
|
||||
Can't find the model weights you're looking for?
|
||||
</span>{" "}
|
||||
<Link to="/upload/sd">Upload your own!</Link>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="d-flex gap-2 justify-content-end flex-grow-1">
|
||||
<Button
|
||||
{...{
|
||||
label: "Clear/Reset ",
|
||||
variant: "secondary",
|
||||
onClick: resetToInitialState,
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
{...{
|
||||
label: "Generate Image",
|
||||
disabled: prompt === "" || sdToken === "",
|
||||
onClick: handleEnqueueImageGen,
|
||||
isLoading: isEnqueuing,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</SplitPanel.Body>
|
||||
|
||||
|
||||
Reference in new issue
Block a user