From 82e6fd7bb5498e6bd758d927a30a9bfea6e6ba80 Mon Sep 17 00:00:00 2001 From: Dogtiti <499960698@qq.com> Date: Tue, 23 Jul 2024 21:43:55 +0800 Subject: [PATCH] feat: move sd config to store --- app/components/sd/sd-new.tsx | 42 +++++ app/components/sd/sd-panel.tsx | 254 ++++++++++++++----------------- app/components/sd/sd-sidebar.tsx | 42 +++++ app/components/sd/sd.tsx | 57 +++++-- app/store/sd.ts | 33 +++- 5 files changed, 274 insertions(+), 154 deletions(-) diff --git a/app/components/sd/sd-new.tsx b/app/components/sd/sd-new.tsx index 77e70d64f..682cbfb2f 100644 --- a/app/components/sd/sd-new.tsx +++ b/app/components/sd/sd-new.tsx @@ -17,6 +17,9 @@ import { useDragSideBar, useHotKey, } from "@/app/components/sidebar"; +import { getParams, getModelParamBasicData } from "./sd-panel"; +import { useSdStore } from "@/app/store/sd"; +import { showToast } from "@/app/components/ui-lib"; const SdPanel = dynamic( async () => (await import("@/app/components/sd")).SdPanel, @@ -29,6 +32,37 @@ export function SdNew() { useHotKey(); const { onDragStart, shouldNarrow } = useDragSideBar(); const navigate = useNavigate(); + const sdStore = useSdStore(); + const currentModel = sdStore.currentModel; + const params = sdStore.currentParams; + const setParams = sdStore.setCurrentParams; + + const handleSubmit = () => { + const columns = getParams?.(currentModel, params); + const reqParams: any = {}; + for (let i = 0; i < columns.length; i++) { + const item = columns[i]; + reqParams[item.value] = params[item.value] ?? null; + if (item.required) { + if (!reqParams[item.value]) { + showToast(Locale.SdPanel.ParamIsRequired(item.name)); + return; + } + } + } + let data: any = { + model: currentModel.value, + model_name: currentModel.name, + status: "wait", + params: reqParams, + created_at: new Date().toLocaleString(), + img_data: "", + }; + sdStore.sendTask(data, () => { + setParams(getModelParamBasicData(columns, params, true)); + navigate(Path.Sd); + }); + }; return ( } shadow /> } + secondaryAction={ + + } /> ); diff --git a/app/components/sd/sd-panel.tsx b/app/components/sd/sd-panel.tsx index 592aa0dad..c27fbd54e 100644 --- a/app/components/sd/sd-panel.tsx +++ b/app/components/sd/sd-panel.tsx @@ -1,110 +1,110 @@ import styles from "./sd-panel.module.scss"; -import React, { useState } from "react"; -import { Select, showToast } from "@/app/components/ui-lib"; +import React from "react"; +import { Select } from "@/app/components/ui-lib"; import { IconButton } from "@/app/components/button"; import Locale from "@/app/locales"; -import { nanoid } from "nanoid"; -import { StoreKey } from "@/app/constant"; import { useSdStore } from "@/app/store/sd"; +export const params = [ + { + name: Locale.SdPanel.Prompt, + value: "prompt", + type: "textarea", + placeholder: Locale.SdPanel.PleaseInput(Locale.SdPanel.Prompt), + required: true, + }, + { + name: Locale.SdPanel.ModelVersion, + value: "model", + type: "select", + default: "sd3-medium", + support: ["sd3"], + options: [ + { name: "SD3 Medium", value: "sd3-medium" }, + { name: "SD3 Large", value: "sd3-large" }, + { name: "SD3 Large Turbo", value: "sd3-large-turbo" }, + ], + }, + { + name: Locale.SdPanel.NegativePrompt, + value: "negative_prompt", + type: "textarea", + placeholder: Locale.SdPanel.PleaseInput(Locale.SdPanel.NegativePrompt), + }, + { + name: Locale.SdPanel.AspectRatio, + value: "aspect_ratio", + type: "select", + default: "1:1", + options: [ + { name: "1:1", value: "1:1" }, + { name: "16:9", value: "16:9" }, + { name: "21:9", value: "21:9" }, + { name: "2:3", value: "2:3" }, + { name: "3:2", value: "3:2" }, + { name: "4:5", value: "4:5" }, + { name: "5:4", value: "5:4" }, + { name: "9:16", value: "9:16" }, + { name: "9:21", value: "9:21" }, + ], + }, + { + name: Locale.SdPanel.ImageStyle, + value: "style", + type: "select", + default: "3d-model", + support: ["core"], + options: [ + { name: Locale.SdPanel.Styles.D3Model, value: "3d-model" }, + { name: Locale.SdPanel.Styles.AnalogFilm, value: "analog-film" }, + { name: Locale.SdPanel.Styles.Anime, value: "anime" }, + { name: Locale.SdPanel.Styles.Cinematic, value: "cinematic" }, + { name: Locale.SdPanel.Styles.ComicBook, value: "comic-book" }, + { name: Locale.SdPanel.Styles.DigitalArt, value: "digital-art" }, + { name: Locale.SdPanel.Styles.Enhance, value: "enhance" }, + { name: Locale.SdPanel.Styles.FantasyArt, value: "fantasy-art" }, + { name: Locale.SdPanel.Styles.Isometric, value: "isometric" }, + { name: Locale.SdPanel.Styles.LineArt, value: "line-art" }, + { name: Locale.SdPanel.Styles.LowPoly, value: "low-poly" }, + { + name: Locale.SdPanel.Styles.ModelingCompound, + value: "modeling-compound", + }, + { name: Locale.SdPanel.Styles.NeonPunk, value: "neon-punk" }, + { name: Locale.SdPanel.Styles.Origami, value: "origami" }, + { name: Locale.SdPanel.Styles.Photographic, value: "photographic" }, + { name: Locale.SdPanel.Styles.PixelArt, value: "pixel-art" }, + { name: Locale.SdPanel.Styles.TileTexture, value: "tile-texture" }, + ], + }, + { + name: "Seed", + value: "seed", + type: "number", + default: 0, + min: 0, + max: 4294967294, + }, + { + name: Locale.SdPanel.OutFormat, + value: "output_format", + type: "select", + default: "png", + options: [ + { name: "PNG", value: "png" }, + { name: "JPEG", value: "jpeg" }, + { name: "WebP", value: "webp" }, + ], + }, +]; + const sdCommonParams = (model: string, data: any) => { - return [ - { - name: Locale.SdPanel.Prompt, - value: "prompt", - type: "textarea", - placeholder: Locale.SdPanel.PleaseInput(Locale.SdPanel.Prompt), - required: true, - }, - { - name: Locale.SdPanel.ModelVersion, - value: "model", - type: "select", - default: "sd3-medium", - support: ["sd3"], - options: [ - { name: "SD3 Medium", value: "sd3-medium" }, - { name: "SD3 Large", value: "sd3-large" }, - { name: "SD3 Large Turbo", value: "sd3-large-turbo" }, - ], - }, - { - name: Locale.SdPanel.NegativePrompt, - value: "negative_prompt", - type: "textarea", - placeholder: Locale.SdPanel.PleaseInput(Locale.SdPanel.NegativePrompt), - }, - { - name: Locale.SdPanel.AspectRatio, - value: "aspect_ratio", - type: "select", - default: "1:1", - options: [ - { name: "1:1", value: "1:1" }, - { name: "16:9", value: "16:9" }, - { name: "21:9", value: "21:9" }, - { name: "2:3", value: "2:3" }, - { name: "3:2", value: "3:2" }, - { name: "4:5", value: "4:5" }, - { name: "5:4", value: "5:4" }, - { name: "9:16", value: "9:16" }, - { name: "9:21", value: "9:21" }, - ], - }, - { - name: Locale.SdPanel.ImageStyle, - value: "style", - type: "select", - default: "3d", - support: ["core"], - options: [ - { name: Locale.SdPanel.Styles.D3Model, value: "3d-model" }, - { name: Locale.SdPanel.Styles.AnalogFilm, value: "analog-film" }, - { name: Locale.SdPanel.Styles.Anime, value: "anime" }, - { name: Locale.SdPanel.Styles.Cinematic, value: "cinematic" }, - { name: Locale.SdPanel.Styles.ComicBook, value: "comic-book" }, - { name: Locale.SdPanel.Styles.DigitalArt, value: "digital-art" }, - { name: Locale.SdPanel.Styles.Enhance, value: "enhance" }, - { name: Locale.SdPanel.Styles.FantasyArt, value: "fantasy-art" }, - { name: Locale.SdPanel.Styles.Isometric, value: "isometric" }, - { name: Locale.SdPanel.Styles.LineArt, value: "line-art" }, - { name: Locale.SdPanel.Styles.LowPoly, value: "low-poly" }, - { - name: Locale.SdPanel.Styles.ModelingCompound, - value: "modeling-compound", - }, - { name: Locale.SdPanel.Styles.NeonPunk, value: "neon-punk" }, - { name: Locale.SdPanel.Styles.Origami, value: "origami" }, - { name: Locale.SdPanel.Styles.Photographic, value: "photographic" }, - { name: Locale.SdPanel.Styles.PixelArt, value: "pixel-art" }, - { name: Locale.SdPanel.Styles.TileTexture, value: "tile-texture" }, - ], - }, - { - name: "Seed", - value: "seed", - type: "number", - default: 0, - min: 0, - max: 4294967294, - }, - { - name: Locale.SdPanel.OutFormat, - value: "output_format", - type: "select", - default: "png", - options: [ - { name: "PNG", value: "png" }, - { name: "JPEG", value: "jpeg" }, - { name: "WebP", value: "webp" }, - ], - }, - ].filter((item) => { + return params.filter((item) => { return !(item.support && !item.support.includes(model)); }); }; -const models = [ +export const models = [ { name: "Stable Image Ultra", value: "ultra", @@ -162,7 +162,7 @@ export function ControlParam(props: { }) { return ( <> - {props.columns.map((item) => { + {props.columns?.map((item) => { let element: null | JSX.Element; switch (item.type) { case "textarea": @@ -251,7 +251,7 @@ export function ControlParam(props: { ); } -const getModelParamBasicData = ( +export const getModelParamBasicData = ( columns: any[], data: any, clearText?: boolean, @@ -268,47 +268,28 @@ const getModelParamBasicData = ( return newParams; }; +export const getParams = (model: any, params: any) => { + return models.find((m) => m.value === model.value)?.params(params) || []; +}; + export function SdPanel() { - const [currentModel, setCurrentModel] = useState(models[0]); - const [params, setParams] = useState( - getModelParamBasicData(currentModel.params({}), {}), - ); + const sdStore = useSdStore(); + const currentModel = sdStore.currentModel; + const setCurrentModel = sdStore.setCurrentModel; + const params = sdStore.currentParams; + const setParams = sdStore.setCurrentParams; + const handleValueChange = (field: string, val: any) => { - setParams((prevParams: any) => ({ - ...prevParams, + setParams({ + ...params, [field]: val, - })); + }); }; const handleModelChange = (model: any) => { setCurrentModel(model); setParams(getModelParamBasicData(model.params({}), params)); }; - const sdStore = useSdStore(); - const handleSubmit = () => { - const columns = currentModel.params(params); - const reqParams: any = {}; - for (let i = 0; i < columns.length; i++) { - const item = columns[i]; - reqParams[item.value] = params[item.value] ?? null; - if (item.required) { - if (!reqParams[item.value]) { - showToast(Locale.SdPanel.ParamIsRequired(item.name)); - return; - } - } - } - let data: any = { - model: currentModel.value, - model_name: currentModel.name, - status: "wait", - params: reqParams, - created_at: new Date().toLocaleString(), - img_data: "", - }; - sdStore.sendTask(data, () => { - setParams(getModelParamBasicData(columns, params, true)); - }); - }; + return ( <> @@ -327,17 +308,10 @@ export function SdPanel() { - ); } diff --git a/app/components/sd/sd-sidebar.tsx b/app/components/sd/sd-sidebar.tsx index 93909218f..fcb97d300 100644 --- a/app/components/sd/sd-sidebar.tsx +++ b/app/components/sd/sd-sidebar.tsx @@ -17,6 +17,10 @@ import { useHotKey, } from "@/app/components/sidebar"; +import { getParams, getModelParamBasicData } from "./sd-panel"; +import { useSdStore } from "@/app/store/sd"; +import { showToast } from "@/app/components/ui-lib"; + const SdPanel = dynamic( async () => (await import("@/app/components/sd")).SdPanel, { @@ -28,6 +32,36 @@ export function SideBar(props: { className?: string }) { useHotKey(); const { onDragStart, shouldNarrow } = useDragSideBar(); const navigate = useNavigate(); + const sdStore = useSdStore(); + const currentModel = sdStore.currentModel; + const params = sdStore.currentParams; + const setParams = sdStore.setCurrentParams; + + const handleSubmit = () => { + const columns = getParams?.(currentModel, params); + const reqParams: any = {}; + for (let i = 0; i < columns.length; i++) { + const item = columns[i]; + reqParams[item.value] = params[item.value] ?? null; + if (item.required) { + if (!reqParams[item.value]) { + showToast(Locale.SdPanel.ParamIsRequired(item.name)); + return; + } + } + } + let data: any = { + model: currentModel.value, + model_name: currentModel.name, + status: "wait", + params: reqParams, + created_at: new Date().toLocaleString(), + img_data: "", + }; + sdStore.sendTask(data, () => { + setParams(getModelParamBasicData(columns, params, true)); + }); + }; return ( } shadow /> } + secondaryAction={ + + } /> ); diff --git a/app/components/sd/sd.tsx b/app/components/sd/sd.tsx index 83326e5eb..9a1453046 100644 --- a/app/components/sd/sd.tsx +++ b/app/components/sd/sd.tsx @@ -33,6 +33,7 @@ import { import { removeImage } from "@/app/utils/chat"; import { SideBar } from "./sd-sidebar"; import { WindowContent } from "@/app/components/home"; +import { params } from "./sd-panel"; function getSdTaskStatus(item: any) { let s: string; @@ -216,15 +217,53 @@ export function Sd() { title: locales.Sd.GenerateParams, children: (
- {Object.keys(item.params).map((key) => ( -
- {key}: - {item.params[key]} -
- ))} + {Object.keys(item.params).map((key) => { + let label = key; + let value = item.params[key]; + switch (label) { + case "prompt": + label = Locale.SdPanel.Prompt; + break; + case "negative_prompt": + label = + Locale.SdPanel.NegativePrompt; + break; + case "aspect_ratio": + label = Locale.SdPanel.AspectRatio; + break; + case "seed": + label = "Seed"; + value = value || 0; + break; + case "output_format": + label = Locale.SdPanel.OutFormat; + value = value?.toUpperCase(); + break; + case "style": + label = Locale.SdPanel.ImageStyle; + value = params + .find( + (item) => + item.value === "style", + ) + ?.options?.find( + (item) => item.value === value, + )?.name; + break; + default: + break; + } + + return ( +
+ {label}: + {value} +
+ ); + })}
), }); diff --git a/app/store/sd.ts b/app/store/sd.ts index 0d8693f4e..4c8162b52 100644 --- a/app/store/sd.ts +++ b/app/store/sd.ts @@ -1,25 +1,40 @@ import { StabilityPath, StoreKey } from "@/app/constant"; -import { showToast } from "@/app/components/ui-lib"; import { getHeaders } from "@/app/client/api"; import { createPersistStore } from "@/app/utils/store"; import { nanoid } from "nanoid"; import { uploadImage, base64Image2Blob } from "@/app/utils/chat"; +import { models, getModelParamBasicData } from "@/app/components/sd/sd-panel"; + +const defaultModel = { + name: models[0].name, + value: models[0].value, +}; + +const defaultParams = getModelParamBasicData(models[0].params({}), {}); + +const DEFAULT_SD_STATE = { + currentId: 0, + draw: [], + currentModel: defaultModel, + currentParams: defaultParams, +}; export const useSdStore = createPersistStore< { currentId: number; draw: any[]; + currentModel: typeof defaultModel; + currentParams: any; }, { getNextId: () => number; sendTask: (data: any, okCall?: Function) => void; updateDraw: (draw: any) => void; + setCurrentModel: (model: any) => void; + setCurrentParams: (data: any) => void; } >( - { - currentId: 0, - draw: [], - }, + DEFAULT_SD_STATE, (set, _get) => { function get() { return { @@ -111,6 +126,14 @@ export const useSdStore = createPersistStore< } }); }, + setCurrentModel(model: any) { + set({ currentModel: model }); + }, + setCurrentParams(data: any) { + set({ + currentParams: data, + }); + }, }; return methods;