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
5efb004ad1
6 files changed
+225
-200
No files matched your search
@@ -19,7 +19,7 @@ interface ImageCardProps {
|
||||
source?: string;
|
||||
type: "media" | "weights";
|
||||
inSelectModal?: boolean;
|
||||
onResultSelect?: (data:{token: string, title:string}) => void;
|
||||
onResultSelect?: (data: { token: string; title: string }) => void;
|
||||
}
|
||||
|
||||
export default function ImageCard({
|
||||
@@ -34,16 +34,16 @@ export default function ImageCard({
|
||||
}: ImageCardProps) {
|
||||
const history = useHistory();
|
||||
// const { setToken, setWeightTitle } = useToken();
|
||||
const linkUrl = getCardUrl(data,source,type);
|
||||
const linkUrl = getCardUrl(data, source, type);
|
||||
|
||||
const handleSelectModalResultSelect = () => {
|
||||
console.log("handleSelectModalResultSelect")
|
||||
console.log("handleSelectModalResultSelect");
|
||||
if (inSelectModal) {
|
||||
|
||||
onResultSelect && onResultSelect({
|
||||
token: data.weight_token,
|
||||
title: data.title
|
||||
});
|
||||
onResultSelect &&
|
||||
onResultSelect({
|
||||
token: data.weight_token,
|
||||
title: data.title,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -111,14 +111,16 @@ export default function ImageCard({
|
||||
<div>
|
||||
<p className="fs-7 opacity-75 mb-0">{timeAgo}</p>
|
||||
</div>
|
||||
<CardFooter {...{
|
||||
creator: data?.maybe_creator,
|
||||
entityToken: data.token,
|
||||
entityType: "media_file",
|
||||
makeBookmarksProps: bookmarks.makeProps,
|
||||
makeRatingsProps: ratings.makeProps,
|
||||
showCreator
|
||||
}}/>
|
||||
<CardFooter
|
||||
{...{
|
||||
creator: data?.maybe_creator,
|
||||
entityToken: data.token,
|
||||
entityType: "media_file",
|
||||
makeBookmarksProps: bookmarks.makeProps,
|
||||
makeRatingsProps: ratings.makeProps,
|
||||
showCreator,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
@@ -169,14 +171,16 @@ export default function ImageCard({
|
||||
<p className="fs-7 opacity-75 mb-0">{timeAgo}</p>
|
||||
</div>
|
||||
</div>
|
||||
<CardFooter {...{
|
||||
creator: data?.maybe_creator,
|
||||
entityToken: data.weight_token,
|
||||
entityType: "model_weight",
|
||||
makeBookmarksProps: bookmarks.makeProps,
|
||||
makeRatingsProps: ratings.makeProps,
|
||||
showCreator
|
||||
}}/>
|
||||
<CardFooter
|
||||
{...{
|
||||
creator: data?.maybe_creator,
|
||||
entityToken: data.weight_token,
|
||||
entityType: "model_weight",
|
||||
makeBookmarksProps: bookmarks.makeProps,
|
||||
makeRatingsProps: ratings.makeProps,
|
||||
showCreator,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { TempInput as Input } from 'components/common';
|
||||
import { TempInput as Input } from "components/common";
|
||||
// import Input from "../Input";
|
||||
import { faSearch } from "@fortawesome/pro-solid-svg-icons";
|
||||
import MasonryGrid from "../MasonryGrid/MasonryGrid";
|
||||
import "./Searcher.scss";
|
||||
import { Weight } from "@storyteller/components/src/api/weights/GetWeight";
|
||||
import { useLazyLists } from "hooks";
|
||||
import { useBookmarks, useLazyLists, useRatings } from "hooks";
|
||||
import { SearchWeights } from "@storyteller/components/src/api/weights/SearchWeights";
|
||||
import debounce from "lodash.debounce";
|
||||
import WeightsCards from "../Card/WeightsCards";
|
||||
@@ -18,7 +18,7 @@ interface SearcherProps {
|
||||
type?: "page" | "modal";
|
||||
dataType?: "media" | "weights";
|
||||
weightType?: string;
|
||||
onResultSelect?: (data:{token:string, title:string}) => void;
|
||||
onResultSelect?: (data: { token: string; title: string }) => void;
|
||||
searcherKey: string;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ export default function Searcher({
|
||||
const [foundWeights, setFoundWeights] = useState<Weight[]>([]);
|
||||
const [isSearching, setIsSearching] = useState(false);
|
||||
const [searchCompleted, setSearchCompleted] = useState(0);
|
||||
// const bookmarks = useBookmarks();
|
||||
// const ratings = useRatings();
|
||||
const bookmarks = useBookmarks();
|
||||
const ratings = useRatings();
|
||||
const [list, listSet] = useState<Weight[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -127,7 +127,6 @@ export default function Searcher({
|
||||
foundWeights.map((data: any, key: number) => {
|
||||
let props = {
|
||||
data,
|
||||
showCreator: true,
|
||||
type: "weights",
|
||||
inSelectModal: true,
|
||||
onResultSelect,
|
||||
@@ -185,6 +184,8 @@ export default function Searcher({
|
||||
{weights.list.map((data: any, key: number) => {
|
||||
let props = {
|
||||
data,
|
||||
ratings,
|
||||
bookmarks,
|
||||
showCreator: true,
|
||||
type: "weights",
|
||||
inSelectModal: true,
|
||||
|
||||
@@ -7,7 +7,7 @@ interface HeaderProps {
|
||||
padding?: boolean;
|
||||
}
|
||||
const Header: React.FC<HeaderProps> = ({ children, padding }) => {
|
||||
const headerClassName = `${padding ? "p-3 py-4 p-md-4" : ""}`.trim();
|
||||
const headerClassName = `${padding ? "p-3 p-md-4 py-md-3" : ""}`.trim();
|
||||
return <div className={headerClassName}>{children}</div>;
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ interface BodyProps {
|
||||
padding?: boolean;
|
||||
}
|
||||
const Body: React.FC<BodyProps> = ({ children, padding }) => {
|
||||
const bodyClassName = `${padding ? "p-3 py-4 p-md-4" : ""}`.trim();
|
||||
const bodyClassName = `${padding ? "p-3 p-md-4" : ""}`.trim();
|
||||
return <div className={bodyClassName}>{children}</div>;
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@ interface FooterProps {
|
||||
padding?: boolean;
|
||||
}
|
||||
const Footer: React.FC<FooterProps> = ({ children, padding }) => {
|
||||
const footerClassName = `${padding ? "p-3 py-4 p-md-4" : ""}`.trim();
|
||||
const footerClassName = `${padding ? "p-3 p-md-4" : ""}`.trim();
|
||||
return <div className={footerClassName}>{children}</div>;
|
||||
};
|
||||
|
||||
@@ -74,7 +74,7 @@ const SplitPanel: React.FC<PanelProps> & {
|
||||
{body}
|
||||
{dividerFooter && <hr className="m-0" />}
|
||||
{footer}
|
||||
{ <TintSpinner {...{ busy }} /> }
|
||||
{<TintSpinner {...{ busy }} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ interface Props {
|
||||
title: React.ReactNode;
|
||||
subText: React.ReactNode;
|
||||
yOffset?: string;
|
||||
extension?: React.ReactNode;
|
||||
}
|
||||
|
||||
function PageHeaderWithImage(props: Props) {
|
||||
@@ -31,6 +32,12 @@ function PageHeaderWithImage(props: Props) {
|
||||
<p className="text-center text-md-start opacity-75">
|
||||
{props.subText}
|
||||
</p>
|
||||
|
||||
{props.extension && (
|
||||
<div className="d-flex justify-content-center justify-content-md-start mt-3">
|
||||
{props.extension}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-5 d-none d-md-block">
|
||||
|
||||
@@ -30,7 +30,7 @@ export default function TextToImagePage({
|
||||
const hasImageGenJobs = inferenceJobs && inferenceJobs.length > 0;
|
||||
|
||||
if (!sessionWrapper.canAccessStudio()) {
|
||||
return <StudioNotAvailable />
|
||||
return <StudioNotAvailable />;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -40,7 +40,7 @@ export default function TextToImagePage({
|
||||
titleIcon={faMessageImage}
|
||||
title="Text to Image"
|
||||
subText="Transform your thoughts into art."
|
||||
yOffset="76%"
|
||||
yOffset="68%"
|
||||
/>
|
||||
|
||||
{hasImageGenJobs && (
|
||||
|
||||
+177
-164
@@ -5,9 +5,9 @@ import {
|
||||
Input,
|
||||
Label,
|
||||
NumberSlider,
|
||||
Panel,
|
||||
SegmentButtons,
|
||||
SelectModal,
|
||||
SplitPanel,
|
||||
TempSelect,
|
||||
TempTextArea,
|
||||
} from "components/common";
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
faRectangleLandscape,
|
||||
faRectanglePortrait,
|
||||
faSquare,
|
||||
faUpload,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import {
|
||||
@@ -278,7 +279,7 @@ function SdInferencePanel({
|
||||
);
|
||||
}
|
||||
} else if (EnqueueImageGenIsError(response)) {
|
||||
console.log("error",response);
|
||||
console.log("error", response);
|
||||
}
|
||||
setIsEnqueuing(false);
|
||||
|
||||
@@ -293,186 +294,198 @@ function SdInferencePanel({
|
||||
};
|
||||
|
||||
return (
|
||||
<Panel padding={true}>
|
||||
<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",
|
||||
typeFilter: "sd_1.5",
|
||||
searcher: true,
|
||||
type: "weights",
|
||||
},
|
||||
{
|
||||
label: "Bookmarked",
|
||||
tabKey: "bookmarkedWeights",
|
||||
typeFilter: "sd_1.5",
|
||||
searcher: false,
|
||||
type: "weights",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
<TempTextArea
|
||||
{...{
|
||||
label: "Prompt",
|
||||
placeholder: "Enter a prompt",
|
||||
onChange: handlePromptChange,
|
||||
value: prompt,
|
||||
required: true,
|
||||
}}
|
||||
/>
|
||||
<TempTextArea
|
||||
{...{
|
||||
label: "Negative Prompt",
|
||||
name: "negativePrompt",
|
||||
placeholder: "Enter a negative prompt",
|
||||
onChange: handleNegativePromptChange,
|
||||
value: negativePrompt,
|
||||
}}
|
||||
/>
|
||||
<SegmentButtons
|
||||
{...{
|
||||
label: "Aspect Ratio",
|
||||
name: "aspectRatio",
|
||||
onChange,
|
||||
options: dimensionOpts,
|
||||
value: aspectRatio,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Accordion>
|
||||
<Accordion.Item title="Advanced">
|
||||
<div className="p-3 d-flex flex-column gap-3">
|
||||
<div>
|
||||
<label className="sub-title">Seed</label>
|
||||
<div className="d-flex gap-2 align-items-center">
|
||||
<SegmentButtons
|
||||
{...{
|
||||
name: "seed",
|
||||
onChange: handleSeedChange,
|
||||
options: seedOpts,
|
||||
value: seed,
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
placeholder="Random"
|
||||
value={seedNumber}
|
||||
onChange={handleSeedNumberChange}
|
||||
type="number"
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TempSelect
|
||||
{...{
|
||||
label: "Sampler",
|
||||
name: "sampler",
|
||||
onChange,
|
||||
options: samplerOpts,
|
||||
value: sampler,
|
||||
}}
|
||||
/>
|
||||
|
||||
<NumberSlider
|
||||
{...{
|
||||
min: 1,
|
||||
max: 30,
|
||||
name: "cfgScale",
|
||||
label: "CFG Scale",
|
||||
onChange,
|
||||
thumbTip: "CFG Scale",
|
||||
value: cfgScale,
|
||||
step: 0.5,
|
||||
}}
|
||||
/>
|
||||
|
||||
<NumberSlider
|
||||
{...{
|
||||
min: 8,
|
||||
max: 64,
|
||||
name: "samples",
|
||||
label: "Samples",
|
||||
onChange,
|
||||
thumbTip: "Samples",
|
||||
value: samples,
|
||||
}}
|
||||
<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>
|
||||
<div>
|
||||
<Button
|
||||
icon={faUpload}
|
||||
label="Upload a Weight"
|
||||
variant="secondary"
|
||||
small={true}
|
||||
to="/upload/sd"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</SplitPanel.Header>
|
||||
|
||||
<SplitPanel.Body padding={true}>
|
||||
<div className="d-flex flex-column gap-3 mb-4">
|
||||
{isStandalone && (
|
||||
<SelectModal
|
||||
label="Additional LoRA Weight"
|
||||
onSelect={handleOnSelect}
|
||||
required={true}
|
||||
modalTitle="Select a Weight"
|
||||
label="Select a Weight"
|
||||
onSelect={handleOnWeightSelect}
|
||||
tabs={[
|
||||
{
|
||||
label: "All LoRA Weights",
|
||||
tabKey: "allLoraWeights",
|
||||
typeFilter: "loRA",
|
||||
label: "All Weights",
|
||||
tabKey: "allWeights",
|
||||
typeFilter: "sd_1.5",
|
||||
searcher: true,
|
||||
type: "weights",
|
||||
},
|
||||
{
|
||||
label: "Bookmarked",
|
||||
tabKey: "bookmarkedLoraWeights",
|
||||
typeFilter: "loRA",
|
||||
tabKey: "bookmarkedWeights",
|
||||
typeFilter: "sd_1.5",
|
||||
searcher: false,
|
||||
type: "weights",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Label label="Number of Generations" />
|
||||
<PremiumLock
|
||||
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
|
||||
requiredPlan="pro"
|
||||
>
|
||||
<SegmentButtons
|
||||
{...{
|
||||
name: "batchCount",
|
||||
onChange,
|
||||
options: batchCountOpts,
|
||||
value: batchCount,
|
||||
}}
|
||||
/>
|
||||
</PremiumLock>
|
||||
<TempTextArea
|
||||
{...{
|
||||
label: "Prompt",
|
||||
placeholder: "Enter a prompt",
|
||||
onChange: handlePromptChange,
|
||||
value: prompt,
|
||||
required: true,
|
||||
}}
|
||||
/>
|
||||
<TempTextArea
|
||||
{...{
|
||||
label: "Negative Prompt",
|
||||
name: "negativePrompt",
|
||||
placeholder: "Enter a negative prompt",
|
||||
onChange: handleNegativePromptChange,
|
||||
value: negativePrompt,
|
||||
}}
|
||||
/>
|
||||
<SegmentButtons
|
||||
{...{
|
||||
label: "Aspect Ratio",
|
||||
name: "aspectRatio",
|
||||
onChange,
|
||||
options: dimensionOpts,
|
||||
value: aspectRatio,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Accordion>
|
||||
<Accordion.Item title="Advanced">
|
||||
<div className="p-3 d-flex flex-column gap-3">
|
||||
<div>
|
||||
<label className="sub-title">Seed</label>
|
||||
<div className="d-flex gap-2 align-items-center">
|
||||
<SegmentButtons
|
||||
{...{
|
||||
name: "seed",
|
||||
onChange: handleSeedChange,
|
||||
options: seedOpts,
|
||||
value: seed,
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
placeholder="Random"
|
||||
value={seedNumber}
|
||||
onChange={handleSeedNumberChange}
|
||||
type="number"
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<TempSelect
|
||||
{...{
|
||||
label: "Sampler",
|
||||
name: "sampler",
|
||||
onChange,
|
||||
options: samplerOpts,
|
||||
value: sampler,
|
||||
}}
|
||||
/>
|
||||
<NumberSlider
|
||||
{...{
|
||||
min: 1,
|
||||
max: 30,
|
||||
name: "cfgScale",
|
||||
label: "CFG Scale",
|
||||
onChange,
|
||||
thumbTip: "CFG Scale",
|
||||
value: cfgScale,
|
||||
step: 0.5,
|
||||
}}
|
||||
/>
|
||||
<NumberSlider
|
||||
{...{
|
||||
min: 8,
|
||||
max: 64,
|
||||
name: "samples",
|
||||
label: "Samples",
|
||||
onChange,
|
||||
thumbTip: "Samples",
|
||||
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",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<div>
|
||||
<Label label="Number of Generations" />
|
||||
<PremiumLock
|
||||
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
|
||||
requiredPlan="pro"
|
||||
>
|
||||
<SegmentButtons
|
||||
{...{
|
||||
name: "batchCount",
|
||||
onChange,
|
||||
options: batchCountOpts,
|
||||
value: batchCount,
|
||||
}}
|
||||
/>
|
||||
</PremiumLock>
|
||||
</div>{" "}
|
||||
</div>
|
||||
</div>
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
</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 === undefined,
|
||||
onClick: handleEnqueueImageGen,
|
||||
isLoading: isEnqueuing,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</SplitPanel.Body>
|
||||
|
||||
<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 === undefined,
|
||||
onClick: handleEnqueueImageGen,
|
||||
isLoading: isEnqueuing,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<InferenceJobsList {...{
|
||||
failures,
|
||||
jobType: FrontendInferenceJobType.ImageGeneration
|
||||
}} />
|
||||
</Panel>
|
||||
<InferenceJobsList
|
||||
{...{
|
||||
failures,
|
||||
jobType: FrontendInferenceJobType.ImageGeneration,
|
||||
}}
|
||||
/>
|
||||
</SplitPanel>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user