diff --git a/gui/src/components/input/EditableList.tsx b/gui/src/components/input/EditableList.tsx index dce17295..a91da836 100644 --- a/gui/src/components/input/EditableList.tsx +++ b/gui/src/components/input/EditableList.tsx @@ -6,33 +6,40 @@ const { useState } = React; export interface EditableListProps { items: Array; - newItem: (s: string) => T; + newItem: (l: string, s: string) => T; renderItem: (t: T) => React.ReactElement; setItems: (ts: Array) => void; } export function EditableList(props: EditableListProps) { const { items, newItem, renderItem, setItems } = props; - const [nextItem, setNextItem] = useState(''); + const [nextLabel, setNextLabel] = useState(''); + const [nextSource, setNextSource] = useState(''); - return - {items.map((it, idx) => + return + {items.map((it, idx) => {renderItem(it)} )} - + + setNextLabel(event.target.value)} + /> setNextItem(event.target.value)} + value={nextSource} + onChange={(event) => setNextSource(event.target.value)} /> ; diff --git a/gui/src/components/input/model/CorrectionModel.tsx b/gui/src/components/input/model/CorrectionModel.tsx new file mode 100644 index 00000000..3af0ab7a --- /dev/null +++ b/gui/src/components/input/model/CorrectionModel.tsx @@ -0,0 +1,17 @@ +import { Stack, TextField } from '@mui/material'; +import * as React from 'react'; + +import { CorrectionModel } from '../../../types'; + +export interface CorrectionModelInputProps { + model: CorrectionModel; +} + +export function CorrectionModelInput(props: CorrectionModelInputProps) { + const { model } = props; + + return + + + ; +} diff --git a/gui/src/components/input/model/DiffusionModel.tsx b/gui/src/components/input/model/DiffusionModel.tsx new file mode 100644 index 00000000..bd1dcbc7 --- /dev/null +++ b/gui/src/components/input/model/DiffusionModel.tsx @@ -0,0 +1,21 @@ +import { MenuItem, Select, Stack, TextField } from '@mui/material'; +import * as React from 'react'; + +import { DiffusionModel } from '../../../types'; + +export interface DiffusionModelInputProps { + model: DiffusionModel; +} + +export function DiffusionModelInput(props: DiffusionModelInputProps) { + const { model } = props; + + return + + + + ; +} diff --git a/gui/src/components/input/model/ExtraNetwork.tsx b/gui/src/components/input/model/ExtraNetwork.tsx new file mode 100644 index 00000000..62be0d33 --- /dev/null +++ b/gui/src/components/input/model/ExtraNetwork.tsx @@ -0,0 +1,26 @@ +import { MenuItem, Select, Stack, TextField } from '@mui/material'; +import * as React from 'react'; + +import { ExtraNetwork } from '../../../types'; + +export interface ExtraNetworkInputProps { + model: ExtraNetwork; +} + +export function ExtraNetworkInput(props: ExtraNetworkInputProps) { + const { model } = props; + + return + + + + + ; +} diff --git a/gui/src/components/input/model/ExtraSource.tsx b/gui/src/components/input/model/ExtraSource.tsx new file mode 100644 index 00000000..88d6d950 --- /dev/null +++ b/gui/src/components/input/model/ExtraSource.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { Stack, TextField } from '@mui/material'; + +import { ExtraSource } from '../../../types'; + +export interface ExtraSourceInputProps { + model: ExtraSource; +} + +export function ExtraSourceInput(props: ExtraSourceInputProps) { + const { model } = props; + + return + + + ; +} diff --git a/gui/src/components/input/model/UpscalingModel.tsx b/gui/src/components/input/model/UpscalingModel.tsx new file mode 100644 index 00000000..39fe2556 --- /dev/null +++ b/gui/src/components/input/model/UpscalingModel.tsx @@ -0,0 +1,17 @@ +import { Stack, TextField } from '@mui/material'; +import * as React from 'react'; + +import { UpscalingModel } from '../../../types.js'; + +export interface UpscalingModelInputProps { + model: UpscalingModel; +} + +export function UpscalingModelInput(props: UpscalingModelInputProps) { + const { model } = props; + + return + + + ; +} diff --git a/gui/src/components/tab/Models.tsx b/gui/src/components/tab/Models.tsx index c855d2da..80ea688b 100644 --- a/gui/src/components/tab/Models.tsx +++ b/gui/src/components/tab/Models.tsx @@ -1,10 +1,19 @@ import { mustExist } from '@apextoaster/js-utils'; import { Accordion, AccordionDetails, AccordionSummary, Button, Stack } from '@mui/material'; import * as React from 'react'; +import _ from 'lodash'; import { useStore } from 'zustand'; import { StateContext } from '../../state.js'; import { EditableList } from '../input/EditableList'; +import { DiffusionModelInput } from '../input/model/DiffusionModel.js'; +import { SafetensorFormat } from '../../types.js'; +import { CorrectionModelInput } from '../input/model/CorrectionModel.js'; +import { UpscalingModelInput } from '../input/model/UpscalingModel.js'; +import { ExtraSourceInput } from '../input/model/ExtraSource.js'; +import { ExtraNetworkInput } from '../input/model/ExtraNetwork.js'; +// eslint-disable-next-line @typescript-eslint/unbound-method +const { kebabCase } = _; export function Models() { const state = mustExist(React.useContext(StateContext)); @@ -12,7 +21,7 @@ export function Models() { // eslint-disable-next-line @typescript-eslint/unbound-method const setExtras = useStore(state, (s) => s.setExtras); - return + return Diffusion Models @@ -20,8 +29,13 @@ export function Models() { s} - renderItem={(t) =>
{t}
} + newItem={(l, s) => ({ + format: 'safetensors' as SafetensorFormat, + label: l, + name: kebabCase(l), + source: s, + })} + renderItem={(t) => } setItems={(diffusion) => setExtras({ ...extras, diffusion, @@ -34,6 +48,20 @@ export function Models() { Correction Models
+ ({ + format: 'safetensors' as SafetensorFormat, + label: l, + name: kebabCase(l), + source: s, + })} + renderItem={(t) => } + setItems={(correction) => setExtras({ + ...extras, + correction, + })} + />
@@ -41,13 +69,44 @@ export function Models() { Upscaling Models + ({ + format: 'safetensors' as SafetensorFormat, + label: l, + name: kebabCase(l), + scale: 4, + source: s, + })} + renderItem={(t) => } + setItems={(upscaling) => setExtras({ + ...extras, + upscaling, + })} + /> - Additional Networks + Extra Networks + ({ + format: 'safetensors' as SafetensorFormat, + label: l, + model: 'embeddings' as const, + name: kebabCase(l), + source: s, + type: 'inversion' as const, + })} + renderItem={(t) => } + setItems={(networks) => setExtras({ + ...extras, + networks, + })} + /> @@ -55,6 +114,20 @@ export function Models() { Other Sources + ({ + format: 'safetensors' as SafetensorFormat, + label: l, + name: kebabCase(l), + source: s, + })} + renderItem={(t) => } + setItems={(sources) => setExtras({ + ...extras, + sources, + })} + /> diff --git a/gui/src/state.ts b/gui/src/state.ts index daa9c1b1..145dc83e 100644 --- a/gui/src/state.ts +++ b/gui/src/state.ts @@ -24,6 +24,7 @@ import { UpscaleReqParams, } from './client/api.js'; import { Config, ConfigFiles, ConfigState, ServerParams } from './config.js'; +import { ExtrasFile } from './types.js'; export type Theme = PaletteMode | ''; // tri-state, '' is unset @@ -38,10 +39,6 @@ interface HistoryItem { retry: RetryParams; } -interface ExtrasFile { - diffusion: Array; -} - interface BrushSlice { brush: BrushParams; @@ -556,7 +553,6 @@ export function createStateSlices(server: ServerParams) { next.resetTxt2Img(); next.resetUpscaleTab(); next.resetBlend(); - // TODO: reset more stuff return next; }); }, @@ -564,7 +560,11 @@ export function createStateSlices(server: ServerParams) { const createExtraSlice: Slice = (set) => ({ extras: { + correction: [], diffusion: [], + networks: [], + sources: [], + upscaling: [], }, setExtras(extras) { set((prev) => ({ diff --git a/gui/src/types.ts b/gui/src/types.ts new file mode 100644 index 00000000..d203bc9a --- /dev/null +++ b/gui/src/types.ts @@ -0,0 +1,64 @@ +export type TorchFormat = 'bin' | 'ckpt' | 'pt' | 'pth'; +export type OnnxFormat = 'onnx'; +export type SafetensorFormat = 'safetensors'; + +export interface BaseModel { + /** + * Format of the model, used when downloading files that may not have a format in their URL. + */ + format: OnnxFormat | SafetensorFormat | TorchFormat; + + /** + * Localized label of the model. + */ + label: string; + + /** + * Filename of the model. + */ + name: string; + + /** + * Source URL or local path. + */ + source: string; +} + +export interface DiffusionModel extends BaseModel { + config?: string; + image_size?: string; + inversions?: Array; + loras?: Array; + pipeline?: string; + vae?: string; + version?: string; +} + +export interface UpscalingModel extends BaseModel { + model?: 'bsrgan' | 'resrgan' | 'swinir'; + scale: number; +} + +export interface CorrectionModel extends BaseModel { + model?: 'codeformer' | 'gfpgan'; +} + +export interface ExtraNetwork extends BaseModel { + model: 'concept' | 'embeddings' | 'cloneofsimo' | 'sd-scripts'; + type: 'inversion' | 'lora'; +} + +export interface ExtraSource { + dest?: string; + format?: string; + name: string; + source: string; +} + +export interface ExtrasFile { + correction: Array; + diffusion: Array; + upscaling: Array; + networks: Array; + sources: Array; +}