Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
"use client" | |
import { useState } from "react" | |
import { useLocalStorage } from 'usehooks-ts' | |
import { Button } from "@/components/ui/button" | |
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog" | |
import { | |
Select, | |
SelectContent, | |
SelectItem, | |
SelectTrigger, | |
SelectValue, | |
} from "@/components/ui/select" | |
import { LLMVendor, RenderingModelVendor } from "@/types" | |
import { Input } from "@/components/ui/input" | |
import { Label } from "./label" | |
import { Field } from "./field" | |
import { localStorageKeys } from "./localStorageKeys" | |
import { defaultSettings } from "./defaultSettings" | |
import { useDynamicConfig } from "@/lib/useDynamicConfig" | |
import { Slider } from "@/components/ui/slider" | |
import { fonts } from "@/lib/fonts" | |
import { cn } from "@/lib/utils" | |
import { SectionTitle } from "./section-title" | |
export function SettingsDialog() { | |
const [isOpen, setOpen] = useState(false) | |
const [renderingModelVendor, setRenderingModelVendor] = useLocalStorage<RenderingModelVendor>( | |
localStorageKeys.renderingModelVendor, | |
defaultSettings.renderingModelVendor | |
) | |
const [renderingUseTurbo, setRenderingUseTurbo] = useLocalStorage<boolean>( | |
localStorageKeys.renderingUseTurbo, | |
defaultSettings.renderingUseTurbo | |
) | |
const [llmVendor, setLlmModelVendor] = useLocalStorage<LLMVendor>( | |
localStorageKeys.llmVendor, | |
defaultSettings.llmVendor | |
) | |
const [huggingfaceApiKey, setHuggingfaceApiKey] = useLocalStorage<string>( | |
localStorageKeys.huggingfaceApiKey, | |
defaultSettings.huggingfaceApiKey | |
) | |
const [huggingfaceInferenceApiModel, setHuggingfaceInferenceApiModel] = useLocalStorage<string>( | |
localStorageKeys.huggingfaceInferenceApiModel, | |
defaultSettings.huggingfaceInferenceApiModel | |
) | |
const [huggingfaceInferenceApiModelTrigger, setHuggingfaceInferenceApiModelTrigger] = useLocalStorage<string>( | |
localStorageKeys.huggingfaceInferenceApiModelTrigger, | |
defaultSettings.huggingfaceInferenceApiModelTrigger | |
) | |
const [huggingfaceInferenceApiFileType, setHuggingfaceInferenceApiFileType] = useLocalStorage<string>( | |
localStorageKeys.huggingfaceInferenceApiFileType, | |
defaultSettings.huggingfaceInferenceApiFileType | |
) | |
const [replicateApiKey, setReplicateApiKey] = useLocalStorage<string>( | |
localStorageKeys.replicateApiKey, | |
defaultSettings.replicateApiKey | |
) | |
const [replicateApiModel, setReplicateApiModel] = useLocalStorage<string>( | |
localStorageKeys.replicateApiModel, | |
defaultSettings.replicateApiModel | |
) | |
const [replicateApiModelVersion, setReplicateApiModelVersion] = useLocalStorage<string>( | |
localStorageKeys.replicateApiModelVersion, | |
defaultSettings.replicateApiModelVersion | |
) | |
const [replicateApiModelTrigger, setReplicateApiModelTrigger] = useLocalStorage<string>( | |
localStorageKeys.replicateApiModelTrigger, | |
defaultSettings.replicateApiModelTrigger | |
) | |
const [openaiApiKey, setOpenaiApiKey] = useLocalStorage<string>( | |
localStorageKeys.openaiApiKey, | |
defaultSettings.openaiApiKey | |
) | |
const [openaiApiModel, setOpenaiApiModel] = useLocalStorage<string>( | |
localStorageKeys.openaiApiModel, | |
defaultSettings.openaiApiModel | |
) | |
const [openaiApiLanguageModel, setOpenaiApiLanguageModel] = useLocalStorage<string>( | |
localStorageKeys.openaiApiLanguageModel, | |
defaultSettings.openaiApiLanguageModel | |
) | |
const [groqApiKey, setGroqApiKey] = useLocalStorage<string>( | |
localStorageKeys.groqApiKey, | |
defaultSettings.groqApiKey | |
) | |
const [groqApiLanguageModel, setGroqApiLanguageModel] = useLocalStorage<string>( | |
localStorageKeys.groqApiLanguageModel, | |
defaultSettings.groqApiLanguageModel | |
) | |
const [anthropicApiKey, setAnthropicApiKey] = useLocalStorage<string>( | |
localStorageKeys.anthropicApiKey, | |
defaultSettings.anthropicApiKey | |
) | |
const [anthropicApiLanguageModel, setAnthropicApiLanguageModel] = useLocalStorage<string>( | |
localStorageKeys.anthropicApiLanguageModel, | |
defaultSettings.anthropicApiLanguageModel | |
) | |
const [userDefinedMaxNumberOfPages, setUserDefinedMaxNumberOfPages] = useLocalStorage<number>( | |
localStorageKeys.userDefinedMaxNumberOfPages, | |
defaultSettings.userDefinedMaxNumberOfPages | |
) | |
const { config: { maxNbPages }, isConfigReady } = useDynamicConfig() | |
return ( | |
<Dialog open={isOpen} onOpenChange={setOpen}> | |
<DialogTrigger asChild> | |
<Button className="space-x-1 md:space-x-2"> | |
<div> | |
<span className="">Settings</span> | |
</div> | |
</Button> | |
</DialogTrigger> | |
<DialogContent className="w-full sm:max-w-[500px] md:max-w-[700px] bg-gray-100"> | |
<DialogHeader> | |
<DialogDescription className="w-full text-center text-2xl font-bold text-stone-800"> | |
AI Comic Factory Settings | |
</DialogDescription> | |
</DialogHeader> | |
<div className="overflow-y-scroll h-[75vh] md:h-[70vh]"> | |
<p className="text-base italic text-zinc-600 w-full text-center"> | |
βΉοΈ Some models can take time to cold-start, or be under heavy traffic.<br/> | |
π In case of trouble, try again after 5-10 minutes.<br/> | |
π Your settings are stored inside your browser, not on our servers. | |
</p> | |
<SectionTitle>π General options</SectionTitle> | |
{isConfigReady && <Field> | |
<Label className="pt-2">Move the slider to set the total expected number of pages: {userDefinedMaxNumberOfPages}</Label> | |
<Slider | |
min={1} | |
max={maxNbPages} | |
step={1} | |
onValueChange={(value: any) => { | |
let numericValue = Number(value[0]) | |
numericValue = !isNaN(value[0]) && isFinite(value[0]) ? numericValue : 0 | |
numericValue = Math.min(maxNbPages, Math.max(1, numericValue)) | |
setUserDefinedMaxNumberOfPages(numericValue) | |
}} | |
defaultValue={[userDefinedMaxNumberOfPages]} | |
value={[userDefinedMaxNumberOfPages]} | |
/> | |
</Field> | |
} | |
<div className={cn( | |
`grid gap-2 pt-3 pb-1`, | |
`text-stone-800` | |
)}> | |
{ | |
// renderingModelVendor === "SERVER" && <> | |
// <Field> | |
// <Label>Quality over performance ratio (beta, deprecated):</Label> | |
// <div className="flex flex-row space-x-2 text-zinc-500"> | |
// <Switch | |
// // checked={renderingUseTurbo} | |
// // onCheckedChange={setRenderingUseTurbo} | |
// checked={false} | |
// disabled | |
// className="opacity-30 pointer-events-none" | |
// /> | |
// {/* | |
// <span | |
// onClick={() => setRenderingUseTurbo(!renderingUseTurbo)} | |
// className={cn("cursor-pointer", { "text-zinc-800": renderingUseTurbo })}> | |
// Use a faster, but lower quality model (you are warned!) | |
// </span> | |
// */} | |
// <span className="text-zinc-500 italic"> | |
// Following feedbacks from users (low rendering quality on comics) the fast renderer has been disabled. | |
// </span> | |
// </div> | |
// </Field> | |
// </> | |
} | |
<SectionTitle>π Panel rendering options</SectionTitle> | |
<Field> | |
<Label className={cn( | |
)}>Image generation - please choose a stable diffusion provider:</Label> | |
<Select | |
onValueChange={(value: string) => { | |
setRenderingModelVendor(value as RenderingModelVendor) | |
}} | |
defaultValue={renderingModelVendor} | |
value={renderingModelVendor}> | |
<SelectTrigger className="bg-white"> | |
<SelectValue /> | |
</SelectTrigger> | |
<SelectContent> | |
<SelectItem value="SERVER">Default Hugging Face server (free but limited capacity, not always online)</SelectItem> | |
<SelectItem value="HUGGINGFACE">Custom Inference API model (pro hugging face account recommended)</SelectItem> | |
<SelectItem value="REPLICATE">Custom Replicate model (will bill your own account)</SelectItem> | |
<SelectItem value="OPENAI">DALLΒ·E 3 by OpenAI (partial support, will bill your own account)</SelectItem> | |
</SelectContent> | |
</Select> | |
</Field> | |
{renderingModelVendor === "HUGGINGFACE" && <> | |
<Field> | |
<Label>Hugging Face API Token (<a className="text-stone-600 underline" href="https://huggingface.co/subscribe/pro" target="_blank">PRO account</a> recommended for higher rate limit):</Label> | |
<Input | |
className={fonts.actionman.className} | |
type="password" | |
placeholder="Enter your private api token" | |
onChange={(x) => { | |
setHuggingfaceApiKey(x.target.value) | |
}} | |
value={huggingfaceApiKey} | |
/> | |
</Field> | |
<Field> | |
<Label>Inference API model (custom SDXL or SDXL LoRA):</Label> | |
<Input | |
className={fonts.actionman.className} | |
placeholder="Name of the Inference API model" | |
onChange={(x) => { | |
setHuggingfaceInferenceApiModel(x.target.value) | |
}} | |
value={huggingfaceInferenceApiModel} | |
/> | |
</Field> | |
<Field> | |
<Label>The file type supported by the model (jpg, webp..):</Label> | |
<Input | |
className={fonts.actionman.className} | |
placeholder="Inference API file type" | |
onChange={(x) => { | |
setHuggingfaceInferenceApiFileType(x.target.value) | |
}} | |
value={huggingfaceInferenceApiFileType} | |
/> | |
</Field> | |
<p className="text-sm text-zinc-700"> | |
Using a LoRA? Don't forget the trigger keyword! Also you will want to use the "Neutral" style. | |
</p> | |
<Field> | |
<Label>LoRA model trigger (optional):</Label> | |
<Input | |
className={fonts.actionman.className} | |
placeholder="Trigger keyword (if you use a LoRA)" | |
onChange={(x) => { | |
setHuggingfaceInferenceApiModelTrigger(x.target.value) | |
}} | |
value={huggingfaceInferenceApiModelTrigger} | |
/> | |
</Field> | |
</>} | |
{renderingModelVendor === "OPENAI" && <> | |
<Field> | |
<Label>OpenAI API Token (you will be billed based on OpenAI pricing):</Label> | |
<Input | |
className={fonts.actionman.className} | |
type="password" | |
placeholder="Enter your private api token" | |
onChange={(x) => { | |
setOpenaiApiKey(x.target.value) | |
}} | |
value={openaiApiKey} | |
/> | |
</Field> | |
<Field> | |
<Label>OpenAI image model:</Label> | |
<Input | |
className={fonts.actionman.className} | |
placeholder="OpenAI image model" | |
onChange={(x) => { | |
setOpenaiApiModel(x.target.value) | |
}} | |
value={openaiApiModel} | |
/> | |
</Field> | |
</>} | |
{renderingModelVendor === "REPLICATE" && <> | |
<Field> | |
<Label>Replicate API Token:</Label> | |
<Input | |
className={fonts.actionman.className} | |
type="password" | |
placeholder="Enter your private api token" | |
onChange={(x) => { | |
setReplicateApiKey(x.target.value) | |
}} | |
value={replicateApiKey} | |
/> | |
</Field> | |
<Field> | |
<Label>Replicate model name:</Label> | |
<Input | |
className={fonts.actionman.className} | |
placeholder="Name of the Replicate model" | |
onChange={(x) => { | |
setReplicateApiModel(x.target.value) | |
}} | |
value={replicateApiModel} | |
/> | |
</Field> | |
<Field> | |
<Label>Model version:</Label> | |
<Input | |
className={fonts.actionman.className} | |
placeholder="Version of the Replicate model" | |
onChange={(x) => { | |
setReplicateApiModelVersion(x.target.value) | |
}} | |
value={replicateApiModelVersion} | |
/> | |
</Field> | |
<p className="text-sm text-zinc-700"> | |
Using a LoRA? Don't forget the trigger keyword! Also you will want to use the "Neutral" style. | |
</p> | |
<Field> | |
<Label>LoRA model trigger (optional):</Label> | |
<Input | |
className={fonts.actionman.className} | |
placeholder={'Eg. "In the style of TOK" etc'} | |
onChange={(x) => { | |
setReplicateApiModelTrigger(x.target.value) | |
}} | |
value={replicateApiModelTrigger} | |
/> | |
</Field> | |
</>} | |
<SectionTitle>π Story generation options (π§ experimental feature π§)</SectionTitle> | |
<p>β οΈ Some vendors might be buggy or require tunning, please report issues to Discord.<br/> | |
β οΈ Billing and privacy depend on your preferred vendor, so please exercice caution.</p> | |
<Field> | |
<Label className={cn( | |
"mt-2" | |
)}>Story generation - please choose a LLM provider:</Label> | |
<Select | |
onValueChange={(value: string) => { | |
setLlmModelVendor(value as LLMVendor) | |
}} | |
defaultValue={llmVendor} | |
value={llmVendor}> | |
<SelectTrigger className="bg-white"> | |
<SelectValue /> | |
</SelectTrigger> | |
<SelectContent> | |
<SelectItem value="SERVER">Default Hugging Face server (free but limited capacity, not always online)</SelectItem> | |
<SelectItem value="GROQ">Open-source models on Groq (will bill your own account)</SelectItem> | |
<SelectItem value="ANTHROPIC">Claude by Anthropic (will bill your own account)</SelectItem> | |
<SelectItem value="OPENAI">ChatGPT by OpenAI (will bill your own account)</SelectItem> | |
</SelectContent> | |
</Select> | |
</Field> | |
{llmVendor === "GROQ" && <> | |
<Field> | |
<Label>Groq API Token:</Label> | |
<Input | |
className={fonts.actionman.className} | |
type="password" | |
placeholder="Enter your private api token" | |
onChange={(x) => { | |
setGroqApiKey(x.target.value) | |
}} | |
value={groqApiKey} | |
/> | |
</Field> | |
<Field> | |
<Label>Open-source Model ID:</Label> | |
<Input | |
className={fonts.actionman.className} | |
placeholder="Name of the LLM" | |
onChange={(x) => { | |
setGroqApiLanguageModel(x.target.value) | |
}} | |
value={groqApiLanguageModel} | |
/> | |
</Field> | |
</>} | |
{llmVendor === "ANTHROPIC" && <> | |
<Field> | |
<Label>Anthropic API Token:</Label> | |
<Input | |
className={fonts.actionman.className} | |
type="password" | |
placeholder="Enter your private api token" | |
onChange={(x) => { | |
setAnthropicApiKey(x.target.value) | |
}} | |
value={anthropicApiKey} | |
/> | |
</Field> | |
<Field> | |
<Label>Proprietary Model ID:</Label> | |
<Input | |
className={fonts.actionman.className} | |
placeholder="Name of the LLM" | |
onChange={(x) => { | |
setAnthropicApiLanguageModel(x.target.value) | |
}} | |
value={anthropicApiLanguageModel} | |
/> | |
</Field> | |
</>} | |
{llmVendor === "OPENAI" && <> | |
<Field> | |
<Label>OpenAI API Token:</Label> | |
<Input | |
className={fonts.actionman.className} | |
type="password" | |
placeholder="Enter your private api token" | |
onChange={(x) => { | |
setOpenaiApiKey(x.target.value) | |
}} | |
value={openaiApiKey} | |
/> | |
</Field> | |
<Field> | |
<Label>Proprietary Model ID:</Label> | |
<Input | |
className={fonts.actionman.className} | |
placeholder="Name of the LLM" | |
onChange={(x) => { | |
setOpenaiApiLanguageModel(x.target.value) | |
}} | |
value={openaiApiLanguageModel} | |
/> | |
</Field> | |
</>} | |
</div> | |
</div> | |
<DialogFooter> | |
<Button type="submit" onClick={() => setOpen(false)}>Close</Button> | |
</DialogFooter> | |
</DialogContent> | |
</Dialog> | |
) | |
} |