sd-panel.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. import styles from "./sd-panel.module.scss";
  2. import React, { useState } from "react";
  3. import { Select } from "@/app/components/ui-lib";
  4. import { IconButton } from "@/app/components/button";
  5. import locales from "@/app/locales";
  6. const sdCommonParams = (model: string, data: any) => {
  7. return [
  8. {
  9. name: locales.SdPanel.Prompt,
  10. value: "prompt",
  11. type: "textarea",
  12. placeholder: locales.SdPanel.PleaseInput(locales.SdPanel.Prompt),
  13. required: true,
  14. },
  15. {
  16. name: locales.SdPanel.NegativePrompt,
  17. value: "negative_prompt",
  18. type: "textarea",
  19. placeholder: locales.SdPanel.PleaseInput(locales.SdPanel.NegativePrompt),
  20. },
  21. {
  22. name: locales.SdPanel.AspectRatio,
  23. value: "aspect_ratio",
  24. type: "select",
  25. default: "1:1",
  26. options: [
  27. { name: "1:1", value: "1:1" },
  28. { name: "2:2", value: "2:2" },
  29. ],
  30. },
  31. {
  32. name: locales.SdPanel.ImageStyle,
  33. value: "style",
  34. type: "select",
  35. default: "3d",
  36. support: ["core"],
  37. options: [{ name: "3D", value: "3d" }],
  38. },
  39. { name: "Seed", value: "seed", type: "number", default: 0 },
  40. {
  41. name: locales.SdPanel.OutFormat,
  42. value: "output_format",
  43. type: "select",
  44. default: 0,
  45. options: [
  46. { name: "PNG", value: "png" },
  47. { name: "JPEG", value: "jpeg" },
  48. { name: "WebP", value: "webp" },
  49. ],
  50. },
  51. ].filter((item) => {
  52. return !(item.support && !item.support.includes(model));
  53. });
  54. };
  55. const models = [
  56. {
  57. name: "Stable Image Ultra",
  58. value: "ultra",
  59. params: (data: any) => sdCommonParams("ultra", data),
  60. },
  61. {
  62. name: "Stable Image Core",
  63. value: "core",
  64. params: (data: any) => sdCommonParams("core", data),
  65. },
  66. {
  67. name: "Stable Diffusion 3",
  68. value: "sd3",
  69. params: (data: any) => {
  70. return sdCommonParams("sd3", data);
  71. },
  72. },
  73. ];
  74. export function ControlParamItem(props: {
  75. title: string;
  76. subTitle?: string;
  77. children?: JSX.Element | JSX.Element[];
  78. className?: string;
  79. }) {
  80. return (
  81. <div className={styles["ctrl-param-item"] + ` ${props.className || ""}`}>
  82. <div className={styles["ctrl-param-item-header"]}>
  83. <div className={styles["ctrl-param-item-title"]}>
  84. <div>{props.title}</div>
  85. </div>
  86. </div>
  87. {props.children}
  88. {props.subTitle && (
  89. <div className={styles["ctrl-param-item-sub-title"]}>
  90. {props.subTitle}
  91. </div>
  92. )}
  93. </div>
  94. );
  95. }
  96. export function ControlParam(props: {
  97. columns: any[];
  98. data: any;
  99. set: React.Dispatch<React.SetStateAction<{}>>;
  100. }) {
  101. const handleValueChange = (field: string, val: any) => {
  102. props.set((prevParams) => ({
  103. ...prevParams,
  104. [field]: val,
  105. }));
  106. };
  107. return (
  108. <>
  109. {props.columns.map((item) => {
  110. let element: null | JSX.Element;
  111. switch (item.type) {
  112. case "textarea":
  113. element = (
  114. <ControlParamItem title={item.name} subTitle={item.sub}>
  115. <textarea
  116. rows={item.rows || 3}
  117. style={{ maxWidth: "100%", width: "100%", padding: "10px" }}
  118. placeholder={item.placeholder}
  119. onChange={(e) => {
  120. handleValueChange(item.value, e.currentTarget.value);
  121. }}
  122. value={props.data[item.value]}
  123. ></textarea>
  124. </ControlParamItem>
  125. );
  126. break;
  127. case "select":
  128. element = (
  129. <ControlParamItem title={item.name} subTitle={item.sub}>
  130. <Select
  131. value={props.data[item.value]}
  132. onChange={(e) => {
  133. handleValueChange(item.value, e.currentTarget.value);
  134. }}
  135. >
  136. {item.options.map((opt: any) => {
  137. return (
  138. <option value={opt.value} key={opt.value}>
  139. {opt.name}
  140. </option>
  141. );
  142. })}
  143. </Select>
  144. </ControlParamItem>
  145. );
  146. break;
  147. case "number":
  148. element = (
  149. <ControlParamItem title={item.name} subTitle={item.sub}>
  150. <input
  151. type="number"
  152. value={props.data[item.value]}
  153. onChange={(e) => {
  154. handleValueChange(item.value, e.currentTarget.value);
  155. }}
  156. />
  157. </ControlParamItem>
  158. );
  159. break;
  160. default:
  161. element = (
  162. <ControlParamItem title={item.name} subTitle={item.sub}>
  163. <input
  164. type="text"
  165. value={props.data[item.value]}
  166. style={{ maxWidth: "100%", width: "100%" }}
  167. onChange={(e) => {
  168. handleValueChange(item.value, e.currentTarget.value);
  169. }}
  170. />
  171. </ControlParamItem>
  172. );
  173. }
  174. return <div key={item.value}>{element}</div>;
  175. })}
  176. </>
  177. );
  178. }
  179. export function SdPanel() {
  180. const [currentModel, setCurrentModel] = useState(models[0]);
  181. const [params, setParams] = useState({});
  182. return (
  183. <>
  184. <ControlParamItem title={locales.SdPanel.AIModel}>
  185. <div className={styles["ai-models"]}>
  186. {models.map((item) => {
  187. return (
  188. <IconButton
  189. text={item.name}
  190. key={item.value}
  191. type={currentModel.value == item.value ? "primary" : null}
  192. shadow
  193. onClick={() => {
  194. setCurrentModel(item);
  195. }}
  196. />
  197. );
  198. })}
  199. </div>
  200. </ControlParamItem>
  201. <ControlParam
  202. columns={currentModel.params(params) as any[]}
  203. set={setParams}
  204. data={params}
  205. ></ControlParam>
  206. <IconButton
  207. text={locales.SdPanel.Submit}
  208. type="primary"
  209. style={{ marginTop: "20px" }}
  210. shadow
  211. ></IconButton>
  212. </>
  213. );
  214. }