mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-06 02:00:46 +00:00
lock image generation
This commit is contained in:
1 parent
bf63bc2b6b
commit
e94da0ef4d
3 files changed
+263
-224
No files matched your search
@@ -9,6 +9,7 @@
|
||||
|
||||
.overlay {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
@@ -20,7 +21,6 @@
|
||||
color: rgba($white, 0.8);
|
||||
font-size: 16px;
|
||||
pointer-events: all;
|
||||
text-shadow: 0 0 10px rgba(0, 0, 0, 1);
|
||||
border: 1px solid rgba($primary, 0.4);
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
import { Panel } from "components/common";
|
||||
import { Button, Panel } from "components/common";
|
||||
import { Link } from "react-router-dom";
|
||||
import React from "react";
|
||||
import "./PremiumLock.scss";
|
||||
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faLock } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { faLock, faUp } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
interface PremiumLockProps {
|
||||
requiredPlan?: "plus" | "pro" | "elite";
|
||||
requiredPlan?: "any" | "plus" | "pro" | "elite";
|
||||
large?: boolean;
|
||||
children: React.ReactNode;
|
||||
session?: any;
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
showCtaButton?: boolean;
|
||||
}
|
||||
|
||||
export default function PremiumLock({
|
||||
requiredPlan = "plus",
|
||||
children,
|
||||
sessionSubscriptionsWrapper,
|
||||
showCtaButton = false,
|
||||
large = false,
|
||||
}: PremiumLockProps) {
|
||||
const hasAccess = () => {
|
||||
switch (requiredPlan) {
|
||||
case "any":
|
||||
return sessionSubscriptionsWrapper.hasPaidFeatures();
|
||||
case "plus":
|
||||
return (
|
||||
sessionSubscriptionsWrapper.hasActivePlusSubscription() ||
|
||||
@@ -34,7 +40,7 @@ export default function PremiumLock({
|
||||
case "elite":
|
||||
return sessionSubscriptionsWrapper.hasActiveEliteSubscription();
|
||||
default:
|
||||
return false;
|
||||
return sessionSubscriptionsWrapper.hasPaidFeatures();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -47,11 +53,33 @@ export default function PremiumLock({
|
||||
{children}
|
||||
<div className="overlay">
|
||||
<div className="d-flex flex-column align-items-center gap-2 text-center">
|
||||
<FontAwesomeIcon icon={faLock} className="me-2 fs-5" />
|
||||
<div>
|
||||
This feature requires a{" "}
|
||||
<Link to="/pricing">{requiredPlan} subscription</Link>
|
||||
</div>
|
||||
<FontAwesomeIcon
|
||||
icon={faLock}
|
||||
className={`me-2 ${large ? "fs-4" : "fs-5"}`}
|
||||
/>
|
||||
{requiredPlan === "any" ? (
|
||||
<span className="lead fw-medium">
|
||||
This feature requires a{" "}
|
||||
<Link to="/pricing" className="lead fw-medium">
|
||||
subscription plan.
|
||||
</Link>
|
||||
</span>
|
||||
) : (
|
||||
<span>
|
||||
This feature requires a{" "}
|
||||
<Link to="/pricing">{requiredPlan} subscription</Link>
|
||||
</span>
|
||||
)}
|
||||
|
||||
{showCtaButton && (
|
||||
<Button
|
||||
variant="primary"
|
||||
label="Upgrade your account"
|
||||
icon={faUp}
|
||||
to="/pricing"
|
||||
className="mt-2"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
+225
-214
@@ -259,6 +259,10 @@ function SdInferencePanel({
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sessionSubscriptionsWrapper.hasPaidFeatures()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sessionSubscriptionsWrapper.hasActiveProSubscription()) {
|
||||
batchCountSet(1);
|
||||
}
|
||||
@@ -310,234 +314,241 @@ function SdInferencePanel({
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SplitPanel dividerHeader={true}>
|
||||
<SplitPanel.Header padding={true}>
|
||||
<h4 className="fw-semibold mb-0 flex-grow-1">Generate an Image</h4>
|
||||
</SplitPanel.Header>
|
||||
<PremiumLock
|
||||
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
|
||||
requiredPlan="any"
|
||||
showCtaButton={true}
|
||||
large={true}
|
||||
>
|
||||
<div>
|
||||
<SplitPanel dividerHeader={true}>
|
||||
<SplitPanel.Header padding={true}>
|
||||
<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 || weightPageType === "lora") && (
|
||||
<SelectModal
|
||||
required={true}
|
||||
modalTitle="Select Stable Diffusion Weight"
|
||||
label="Select a Stable Diffusion 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",
|
||||
onlyBookmarked: true,
|
||||
},
|
||||
]}
|
||||
<SplitPanel.Body padding={true}>
|
||||
<div className="d-flex flex-column gap-3 mb-4">
|
||||
{(isStandalone || weightPageType === "lora") && (
|
||||
<SelectModal
|
||||
required={true}
|
||||
modalTitle="Select Stable Diffusion Weight"
|
||||
label="Select a Stable Diffusion 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",
|
||||
onlyBookmarked: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
<TempTextArea
|
||||
{...{
|
||||
label: "Prompt",
|
||||
placeholder: "Enter a prompt",
|
||||
onChange: handlePromptChange,
|
||||
value: prompt,
|
||||
required: true,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<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>
|
||||
<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">
|
||||
<SegmentButtons
|
||||
{...{
|
||||
name: "seed",
|
||||
onChange: handleSeedChange,
|
||||
options: seedOpts,
|
||||
value: seed,
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
placeholder="Random"
|
||||
value={seedNumber}
|
||||
onChange={handleSeedNumberChange}
|
||||
type="number"
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<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,
|
||||
}}
|
||||
/>
|
||||
{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,
|
||||
},
|
||||
]}
|
||||
<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>
|
||||
<Label label="Number of Generations" />
|
||||
<PremiumLock
|
||||
sessionSubscriptionsWrapper={sessionSubscriptionsWrapper}
|
||||
requiredPlan="pro"
|
||||
>
|
||||
<SegmentButtons
|
||||
{...{
|
||||
name: "batchCount",
|
||||
onChange,
|
||||
options: batchCountOpts,
|
||||
value: batchCount,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</PremiumLock>
|
||||
</div>
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
<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>
|
||||
|
||||
<InferenceJobsList
|
||||
{...{
|
||||
failures,
|
||||
jobType: FrontendInferenceJobType.ImageGeneration,
|
||||
}}
|
||||
/>
|
||||
</SplitPanel>
|
||||
<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">
|
||||
<SegmentButtons
|
||||
{...{
|
||||
name: "seed",
|
||||
onChange: handleSeedChange,
|
||||
options: seedOpts,
|
||||
value: seed,
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
placeholder="Random"
|
||||
value={seedNumber}
|
||||
onChange={handleSeedNumberChange}
|
||||
type="number"
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<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,
|
||||
}}
|
||||
/>
|
||||
{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>
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
<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>
|
||||
|
||||
{inferenceJobs[0] ? (
|
||||
<div className={isStandalone ? "mt-4" : "mt-3"}>
|
||||
<InferenceJobsList
|
||||
{...{
|
||||
failures,
|
||||
value: 0,
|
||||
jobType: FrontendInferenceJobType.ImageGeneration,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{isStandalone && (
|
||||
<Panel padding={true} className="mt-4">
|
||||
<div className="d-flex flex-column align-items-center justify-content-center gap-2 py-5 opacity-75">
|
||||
<h4 className="fw-semibold mb-0">
|
||||
<FontAwesomeIcon icon={faList} className="me-2 fs-5" />
|
||||
No jobs queued
|
||||
</h4>
|
||||
</SplitPanel>
|
||||
|
||||
<p>Your queued image jobs will appear here.</p>
|
||||
</div>
|
||||
</Panel>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{inferenceJobs[0] ? (
|
||||
<div className={isStandalone ? "mt-4" : "mt-3"}>
|
||||
<InferenceJobsList
|
||||
{...{
|
||||
failures,
|
||||
value: 0,
|
||||
jobType: FrontendInferenceJobType.ImageGeneration,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{isStandalone && (
|
||||
<Panel padding={true} className="mt-4">
|
||||
<div className="d-flex flex-column align-items-center justify-content-center gap-2 py-5 opacity-75">
|
||||
<h4 className="fw-semibold mb-0">
|
||||
<FontAwesomeIcon icon={faList} className="me-2 fs-5" />
|
||||
No jobs queued
|
||||
</h4>
|
||||
|
||||
<p>Your queued image jobs will appear here.</p>
|
||||
</div>
|
||||
</Panel>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</PremiumLock>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user