| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- import styles from "./sd-panel.module.scss";
- import React from "react";
- import { Select } from "@/app/components/ui-lib";
- import { IconButton } from "@/app/components/button";
- import Locale from "@/app/locales";
- import { useSdStore } from "@/app/store/sd";
- import clsx from "clsx";
- 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 params.filter((item) => {
- return !(item.support && !item.support.includes(model));
- });
- };
- export const models = [
- {
- name: "Stable Image Ultra",
- value: "ultra",
- params: (data: any) => sdCommonParams("ultra", data),
- },
- {
- name: "Stable Image Core",
- value: "core",
- params: (data: any) => sdCommonParams("core", data),
- },
- {
- name: "Stable Diffusion 3",
- value: "sd3",
- params: (data: any) => {
- return sdCommonParams("sd3", data).filter((item) => {
- return !(
- data.model === "sd3-large-turbo" && item.value == "negative_prompt"
- );
- });
- },
- },
- ];
- export function ControlParamItem(props: {
- title: string;
- subTitle?: string;
- required?: boolean;
- children?: JSX.Element | JSX.Element[];
- className?: string;
- }) {
- return (
- <div className={clsx(styles["ctrl-param-item"], props.className)}>
- <div className={styles["ctrl-param-item-header"]}>
- <div className={styles["ctrl-param-item-title"]}>
- <div>
- {props.title}
- {props.required && <span style={{ color: "red" }}>*</span>}
- </div>
- </div>
- </div>
- {props.children}
- {props.subTitle && (
- <div className={styles["ctrl-param-item-sub-title"]}>
- {props.subTitle}
- </div>
- )}
- </div>
- );
- }
- export function ControlParam(props: {
- columns: any[];
- data: any;
- onChange: (field: string, val: any) => void;
- }) {
- return (
- <>
- {props.columns?.map((item) => {
- let element: null | JSX.Element;
- switch (item.type) {
- case "textarea":
- element = (
- <ControlParamItem
- title={item.name}
- subTitle={item.sub}
- required={item.required}
- >
- <textarea
- rows={item.rows || 3}
- style={{ maxWidth: "100%", width: "100%", padding: "10px" }}
- placeholder={item.placeholder}
- onChange={(e) => {
- props.onChange(item.value, e.currentTarget.value);
- }}
- value={props.data[item.value]}
- ></textarea>
- </ControlParamItem>
- );
- break;
- case "select":
- element = (
- <ControlParamItem
- title={item.name}
- subTitle={item.sub}
- required={item.required}
- >
- <Select
- aria-label={item.name}
- value={props.data[item.value]}
- onChange={(e) => {
- props.onChange(item.value, e.currentTarget.value);
- }}
- >
- {item.options.map((opt: any) => {
- return (
- <option value={opt.value} key={opt.value}>
- {opt.name}
- </option>
- );
- })}
- </Select>
- </ControlParamItem>
- );
- break;
- case "number":
- element = (
- <ControlParamItem
- title={item.name}
- subTitle={item.sub}
- required={item.required}
- >
- <input
- aria-label={item.name}
- type="number"
- min={item.min}
- max={item.max}
- value={props.data[item.value] || 0}
- onChange={(e) => {
- props.onChange(item.value, parseInt(e.currentTarget.value));
- }}
- />
- </ControlParamItem>
- );
- break;
- default:
- element = (
- <ControlParamItem
- title={item.name}
- subTitle={item.sub}
- required={item.required}
- >
- <input
- aria-label={item.name}
- type="text"
- value={props.data[item.value]}
- style={{ maxWidth: "100%", width: "100%" }}
- onChange={(e) => {
- props.onChange(item.value, e.currentTarget.value);
- }}
- />
- </ControlParamItem>
- );
- }
- return <div key={item.value}>{element}</div>;
- })}
- </>
- );
- }
- export const getModelParamBasicData = (
- columns: any[],
- data: any,
- clearText?: boolean,
- ) => {
- const newParams: any = {};
- columns.forEach((item: any) => {
- if (clearText && ["text", "textarea", "number"].includes(item.type)) {
- newParams[item.value] = item.default || "";
- } else {
- // @ts-ignore
- newParams[item.value] = data[item.value] || item.default || "";
- }
- });
- return newParams;
- };
- export const getParams = (model: any, params: any) => {
- return models.find((m) => m.value === model.value)?.params(params) || [];
- };
- export function SdPanel() {
- 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({
- ...params,
- [field]: val,
- });
- };
- const handleModelChange = (model: any) => {
- setCurrentModel(model);
- setParams(getModelParamBasicData(model.params({}), params));
- };
- return (
- <>
- <ControlParamItem title={Locale.SdPanel.AIModel}>
- <div className={styles["ai-models"]}>
- {models.map((item) => {
- return (
- <IconButton
- text={item.name}
- key={item.value}
- type={currentModel.value == item.value ? "primary" : null}
- shadow
- onClick={() => handleModelChange(item)}
- />
- );
- })}
- </div>
- </ControlParamItem>
- <ControlParam
- columns={getParams?.(currentModel, params) as any[]}
- data={params}
- onChange={handleValueChange}
- ></ControlParam>
- </>
- );
- }
|