mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 01:38:44 +00:00
added quality selector for image models, pricing page mobile padding fix
This commit is contained in:
1 parent
a1072b7eb7
commit
7e863ed872
6 files changed
+88
-1
No files matched your search
@@ -8,6 +8,7 @@ export interface ImageCostParams {
|
||||
model: string;
|
||||
aspectRatio?: string;
|
||||
resolution?: string;
|
||||
quality?: string;
|
||||
numImages: number;
|
||||
hasReferenceImages: boolean;
|
||||
imageMediaTokenCount?: number;
|
||||
@@ -29,6 +30,7 @@ export function useImageCostEstimate(params: ImageCostParams): number | null {
|
||||
model: params.model,
|
||||
aspect_ratio: params.aspectRatio ?? null,
|
||||
resolution: params.resolution ?? null,
|
||||
quality: params.quality ?? null,
|
||||
image_batch_count: params.numImages,
|
||||
image_media_tokens: params.hasReferenceImages
|
||||
? new Array(params.imageMediaTokenCount ?? 1).fill("placeholder")
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faGem } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { PopoverItem, PopoverMenu } from "@storyteller/ui-popover";
|
||||
import { Tooltip } from "@storyteller/ui-tooltip";
|
||||
|
||||
interface QualityPickerProps {
|
||||
qualityOptions: string[];
|
||||
defaultQuality?: string;
|
||||
currentQuality?: string;
|
||||
handleQualitySelect: (selected: string) => void;
|
||||
}
|
||||
|
||||
const QUALITY_LABELS: Record<string, string> = {
|
||||
high: "High",
|
||||
medium: "Medium",
|
||||
low: "Low",
|
||||
};
|
||||
|
||||
const LABEL_TO_QUALITY: Record<string, string> = Object.fromEntries(
|
||||
Object.entries(QUALITY_LABELS).map(([k, v]) => [v, k]),
|
||||
);
|
||||
|
||||
export const QualityPicker = ({
|
||||
qualityOptions,
|
||||
defaultQuality,
|
||||
currentQuality,
|
||||
handleQualitySelect,
|
||||
}: QualityPickerProps) => {
|
||||
const activeQuality = currentQuality ?? defaultQuality ?? undefined;
|
||||
|
||||
const handleSelectAdapter = (item: PopoverItem) => {
|
||||
const quality = LABEL_TO_QUALITY[item.label];
|
||||
if (quality) handleQualitySelect(quality);
|
||||
};
|
||||
|
||||
const qualityList: PopoverItem[] = qualityOptions.map((q) => ({
|
||||
label: QUALITY_LABELS[q] ?? q,
|
||||
selected: activeQuality === q,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content="Quality"
|
||||
position="top"
|
||||
className="z-50"
|
||||
closeOnClick={true}
|
||||
>
|
||||
<PopoverMenu
|
||||
items={qualityList}
|
||||
onSelect={handleSelectAdapter}
|
||||
mode="toggle"
|
||||
panelTitle="Quality"
|
||||
triggerIcon={
|
||||
<FontAwesomeIcon icon={faGem} className="h-3.5 w-3.5" />
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
@@ -24,6 +24,7 @@ export type ImageUiState = {
|
||||
aspectRatio: string;
|
||||
numImages: number;
|
||||
resolution: string | undefined;
|
||||
quality: string | undefined;
|
||||
};
|
||||
|
||||
type CreateImageState = {
|
||||
@@ -49,6 +50,7 @@ const DEFAULT_UI: ImageUiState = {
|
||||
aspectRatio: "square",
|
||||
numImages: 1,
|
||||
resolution: undefined,
|
||||
quality: undefined,
|
||||
};
|
||||
|
||||
export const useCreateImageStore = create<CreateImageState>((set) => ({
|
||||
|
||||
@@ -23,6 +23,7 @@ import { enqueueImageGeneration, startPolling } from "./generate-image-api";
|
||||
import { AspectRatioPicker } from "./components/AspectRatioPicker";
|
||||
import { GenerationCountPicker } from "./components/GenerationCountPicker";
|
||||
import { ResolutionPicker } from "./components/ResolutionPicker";
|
||||
import { QualityPicker } from "./components/QualityPicker";
|
||||
import { useImageCostEstimate } from "../../lib/cost-estimate-api";
|
||||
import {
|
||||
useOmniGenImageModels,
|
||||
@@ -100,6 +101,11 @@ export default function CreateImage() {
|
||||
(v: string | undefined) => setUi({ resolution: v }),
|
||||
[setUi],
|
||||
);
|
||||
const quality = ui.quality;
|
||||
const setQuality = useCallback(
|
||||
(v: string | undefined) => setUi({ quality: v }),
|
||||
[setUi],
|
||||
);
|
||||
|
||||
const [isGenerating, setIsGenerating] = useState(false);
|
||||
const [referenceImages, setReferenceImages] = useState<RefImage[]>([]);
|
||||
@@ -138,11 +144,13 @@ export default function CreateImage() {
|
||||
const hasAspectRatios =
|
||||
(selectedModel?.aspect_ratio_options?.length ?? 0) > 0;
|
||||
const hasResolutions = (selectedModel?.resolution_options?.length ?? 0) > 0;
|
||||
const hasQualityOptions = (selectedModel?.quality_options?.length ?? 0) > 0;
|
||||
|
||||
const estimatedCredits = useImageCostEstimate({
|
||||
model: selectedModel?.model ?? "",
|
||||
aspectRatio: aspectRatio,
|
||||
resolution: hasResolutions ? resolution : undefined,
|
||||
quality: hasQualityOptions ? quality : undefined,
|
||||
numImages,
|
||||
hasReferenceImages: referenceImages.length > 0,
|
||||
});
|
||||
@@ -206,6 +214,7 @@ export default function CreateImage() {
|
||||
model.batch_size_default ?? 1,
|
||||
),
|
||||
resolution: model.resolution_default ?? undefined,
|
||||
quality: model.default_quality ?? undefined,
|
||||
});
|
||||
},
|
||||
[setUi],
|
||||
@@ -251,6 +260,7 @@ export default function CreateImage() {
|
||||
numImages,
|
||||
aspectRatio: aspectRatio,
|
||||
resolution: hasResolutions ? resolution : undefined,
|
||||
quality: hasQualityOptions ? quality : undefined,
|
||||
imageMediaTokens: imageMediaTokens?.length
|
||||
? imageMediaTokens
|
||||
: undefined,
|
||||
@@ -293,6 +303,8 @@ export default function CreateImage() {
|
||||
aspectRatio,
|
||||
resolution,
|
||||
hasResolutions,
|
||||
quality,
|
||||
hasQualityOptions,
|
||||
referenceImages,
|
||||
startBatch,
|
||||
setBatchJobToken,
|
||||
@@ -373,6 +385,16 @@ export default function CreateImage() {
|
||||
handleResolutionSelect={setResolution}
|
||||
/>
|
||||
)}
|
||||
{hasQualityOptions && selectedModel && (
|
||||
<QualityPicker
|
||||
qualityOptions={selectedModel.quality_options ?? []}
|
||||
defaultQuality={
|
||||
selectedModel.default_quality ?? undefined
|
||||
}
|
||||
currentQuality={quality}
|
||||
handleQualitySelect={setQuality}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
rightToolbar={
|
||||
|
||||
@@ -10,6 +10,7 @@ export interface GenerateImageParams {
|
||||
numImages?: number;
|
||||
aspectRatio?: string;
|
||||
resolution?: string;
|
||||
quality?: string;
|
||||
imageMediaTokens?: string[];
|
||||
}
|
||||
|
||||
@@ -24,6 +25,7 @@ export async function enqueueImageGeneration(
|
||||
idempotency_token: crypto.randomUUID(),
|
||||
aspect_ratio: params.aspectRatio ?? null,
|
||||
resolution: params.resolution ?? null,
|
||||
quality: params.quality ?? null,
|
||||
image_batch_count: params.numImages ?? 1,
|
||||
image_media_tokens: params.imageMediaTokens?.length
|
||||
? params.imageMediaTokens
|
||||
|
||||
@@ -92,7 +92,7 @@ const Pricing = () => {
|
||||
</div>
|
||||
</main>
|
||||
) : (
|
||||
<main className="relative z-10 pt-32 pb-20 px-4 sm:px-6 lg:px-8">
|
||||
<main className="relative z-10 pt-28 sm:pt-32 pb-20 px-4 sm:px-6 lg:px-8">
|
||||
<PricingTable
|
||||
title="Invest in Yourself"
|
||||
subtitle="You'll get a ton of generations and you'll be investing in a tool that you'll always own."
|
||||
|
||||
Reference in new issue
Block a user