1
0
Fork 0

include highres and upscale in params loading

This commit is contained in:
Sean Sube 2023-07-21 22:11:45 -05:00
parent 9e350f09df
commit 626ca18d7f
Signed by: ssube
GPG Key ID: 3EED7B957D362AF1
8 changed files with 164 additions and 72 deletions

View File

@ -60,8 +60,8 @@ export interface BaseImgParams {
* Parameters for txt2img requests. * Parameters for txt2img requests.
*/ */
export interface Txt2ImgParams extends BaseImgParams { export interface Txt2ImgParams extends BaseImgParams {
width?: number; width: number;
height?: number; height: number;
} }
/** /**
@ -71,7 +71,7 @@ export interface Img2ImgParams extends BaseImgParams {
source: Blob; source: Blob;
loopback: number; loopback: number;
sourceFilter?: string; sourceFilter: string;
strength: number; strength: number;
} }
@ -267,6 +267,16 @@ export interface ImageResponseWithRetry {
retry: RetryParams; retry: RetryParams;
} }
export interface ImageMetadata {
highres: HighresParams;
outputs: string | Array<string>;
params: Txt2ImgParams | Img2ImgParams | InpaintParams;
upscale: UpscaleParams;
input_size: ImageSize;
size: ImageSize;
}
export interface ApiClient { export interface ApiClient {
extras(): Promise<ExtrasFile>; extras(): Promise<ExtrasFile>;

View File

@ -1,4 +1,4 @@
import { InvalidArgumentError, Maybe, doesExist, mustExist } from '@apextoaster/js-utils'; import { doesExist, InvalidArgumentError, Maybe, mustExist } from '@apextoaster/js-utils';
import { Delete as DeleteIcon, Download, ImageSearch, Save as SaveIcon } from '@mui/icons-material'; import { Delete as DeleteIcon, Download, ImageSearch, Save as SaveIcon } from '@mui/icons-material';
import { import {
Autocomplete, Autocomplete,
@ -20,19 +20,20 @@ import { useContext } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useStore } from 'zustand'; import { useStore } from 'zustand';
import { BaseImgParams, HighresParams, Txt2ImgParams, UpscaleParams } from '../client/types.js'; import { BaseImgParams, HighresParams, ImageMetadata, Txt2ImgParams, UpscaleParams } from '../client/types.js';
import { StateContext } from '../state.js'; import { StateContext } from '../state.js';
import { DeepPartial } from '../types.js';
const { useState, Fragment } = React; const { useState } = React;
export interface ProfilesProps { export interface ProfilesProps {
highres: HighresParams; highres: HighresParams;
params: BaseImgParams; params: BaseImgParams;
upscale: UpscaleParams; upscale: UpscaleParams;
setHighres(params: HighresParams): void; setHighres(params: Partial<HighresParams>): void;
setParams(params: BaseImgParams): void; setParams(params: Partial<BaseImgParams>): void;
setUpscale(params: UpscaleParams): void; setUpscale(params: Partial<UpscaleParams>): void;
} }
export function Profiles(props: ProfilesProps) { export function Profiles(props: ProfilesProps) {
@ -50,7 +51,7 @@ export function Profiles(props: ProfilesProps) {
return <Stack direction='row' spacing={2}> return <Stack direction='row' spacing={2}>
<Autocomplete <Autocomplete
id="profile-select" id='profile-select'
options={profiles} options={profiles}
sx={{ width: '25em' }} sx={{ width: '25em' }}
getOptionLabel={(option) => option.name} getOptionLabel={(option) => option.name}
@ -59,7 +60,7 @@ export function Profiles(props: ProfilesProps) {
<ListItem <ListItem
{...optionProps} {...optionProps}
secondaryAction={ secondaryAction={
<IconButton edge="end" onClick={(event) => { <IconButton edge='end' onClick={(event) => {
event.preventDefault(); event.preventDefault();
removeProfile(option.name); removeProfile(option.name);
}}> }}>
@ -71,7 +72,7 @@ export function Profiles(props: ProfilesProps) {
</ListItem> </ListItem>
)} )}
renderInput={(params) => ( renderInput={(params) => (
<Stack direction="row"> <Stack direction='row'>
<TextField <TextField
{...params} {...params}
label={t('profile.load')} label={t('profile.load')}
@ -80,7 +81,7 @@ export function Profiles(props: ProfilesProps) {
autoComplete: 'new-password', // disable autocomplete and autofill autoComplete: 'new-password', // disable autocomplete and autofill
}} }}
/> />
<Button type="button" variant="contained" onClick={() => setDialogOpen(true)}> <Button type='button' variant='contained' onClick={() => setDialogOpen(true)}>
<SaveIcon /> <SaveIcon />
</Button> </Button>
</Stack> </Stack>
@ -100,7 +101,7 @@ export function Profiles(props: ProfilesProps) {
<DialogTitle>{t('profile.saveProfile')}</DialogTitle> <DialogTitle>{t('profile.saveProfile')}</DialogTitle>
<DialogContent> <DialogContent>
<TextField <TextField
variant="standard" variant='standard'
label={t('profile.name')} label={t('profile.name')}
value={profileName} value={profileName}
onChange={(event) => setProfileName(event.target.value)} onChange={(event) => setProfileName(event.target.value)}
@ -118,8 +119,8 @@ export function Profiles(props: ProfilesProps) {
saveProfile({ saveProfile({
params: props.params, params: props.params,
name: profileName, name: profileName,
highResParams: props.highres, highres: props.highres,
upscaleParams: props.upscale, upscale: props.upscale,
}); });
setDialogOpen(false); setDialogOpen(false);
setProfileName(''); setProfileName('');
@ -127,7 +128,7 @@ export function Profiles(props: ProfilesProps) {
>{t('profile.save')}</Button> >{t('profile.save')}</Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
<Button component='label' variant="contained"> <Button component='label' variant='contained'>
<ImageSearch /> <ImageSearch />
<input <input
hidden hidden
@ -139,11 +140,16 @@ export function Profiles(props: ProfilesProps) {
const file = mustExist(files[0]); const file = mustExist(files[0]);
// eslint-disable-next-line @typescript-eslint/no-floating-promises // eslint-disable-next-line @typescript-eslint/no-floating-promises
loadParamsFromFile(file).then((newParams) => { loadParamsFromFile(file).then((newParams) => {
if (doesExist(newParams)) { if (doesExist(newParams.params)) {
props.setParams({ props.setParams(newParams.params);
...props.params, }
...newParams,
}); if (doesExist(newParams.highres)) {
props.setHighres(newParams.highres);
}
if (doesExist(newParams.upscale)) {
props.setUpscale(newParams.upscale);
} }
}); });
} }
@ -154,14 +160,14 @@ export function Profiles(props: ProfilesProps) {
/> />
</Button> </Button>
<Button component='label' variant='contained' onClick={() => { <Button component='label' variant='contained' onClick={() => {
downloadParamsAsFile(props.params); downloadParamsAsFile(props);
}}> }}>
<Download /> <Download />
</Button> </Button>
</Stack>; </Stack>;
} }
export async function loadParamsFromFile(file: File): Promise<Partial<Txt2ImgParams>> { export async function loadParamsFromFile(file: File): Promise<DeepPartial<ImageMetadata>> {
const parts = file.name.toLocaleLowerCase().split('.'); const parts = file.name.toLocaleLowerCase().split('.');
const ext = parts[parts.length - 1]; const ext = parts[parts.length - 1];
@ -182,10 +188,8 @@ export async function loadParamsFromFile(file: File): Promise<Partial<Txt2ImgPar
/** /**
* from https://stackoverflow.com/a/30800715 * from https://stackoverflow.com/a/30800715
*/ */
export function downloadParamsAsFile(params: Txt2ImgParams): void { export function downloadParamsAsFile(data: DeepPartial<ImageMetadata>): void {
const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify({ const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(data));
params,
}));
const elem = document.createElement('a'); const elem = document.createElement('a');
elem.setAttribute('href', dataStr); elem.setAttribute('href', dataStr);
elem.setAttribute('download', 'parameters.json'); elem.setAttribute('download', 'parameters.json');
@ -194,7 +198,7 @@ export function downloadParamsAsFile(params: Txt2ImgParams): void {
elem.remove(); elem.remove();
} }
export async function parseImageParams(file: File): Promise<Partial<Txt2ImgParams>> { export async function parseImageParams(file: File): Promise<DeepPartial<ImageMetadata>> {
const tags = await ExifReader.load(file); const tags = await ExifReader.load(file);
// handle lowercase variation from my earlier mistakes // handle lowercase variation from my earlier mistakes
@ -234,8 +238,8 @@ export function decodeTag(tag: Maybe<ExifReader.XmpTag | (ExifReader.NumberTag &
throw new InvalidArgumentError('tag value cannot be decoded'); throw new InvalidArgumentError('tag value cannot be decoded');
} }
export async function parseJSONParams(json: string): Promise<Partial<Txt2ImgParams>> { export async function parseJSONParams(json: string): Promise<DeepPartial<ImageMetadata>> {
const data = JSON.parse(json); const data = JSON.parse(json) as DeepPartial<ImageMetadata>;
const params: Partial<Txt2ImgParams> = { const params: Partial<Txt2ImgParams> = {
...data.params, ...data.params,
}; };
@ -246,7 +250,11 @@ export async function parseJSONParams(json: string): Promise<Partial<Txt2ImgPara
params.width = size.width; params.width = size.width;
} }
return params; return {
params,
highres: data.highres,
upscale: data.upscale,
};
} }
export function isProbablyJSON(maybeJSON: unknown): boolean { export function isProbablyJSON(maybeJSON: unknown): boolean {
@ -255,7 +263,7 @@ export function isProbablyJSON(maybeJSON: unknown): boolean {
export const NEGATIVE_PROMPT_TAG = 'Negative prompt:'; export const NEGATIVE_PROMPT_TAG = 'Negative prompt:';
export async function parseAutoComment(comment: string): Promise<Partial<Txt2ImgParams>> { export async function parseAutoComment(comment: string): Promise<DeepPartial<ImageMetadata>> {
if (isProbablyJSON(comment)) { if (isProbablyJSON(comment)) {
return parseJSONParams(comment); return parseJSONParams(comment);
} }
@ -306,5 +314,7 @@ export async function parseAutoComment(comment: string): Promise<Partial<Txt2Img
} }
} }
return params; return {
params,
};
} }

View File

@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next';
import { ModelParams } from '../../client/types.js'; import { ModelParams } from '../../client/types.js';
import { STALE_TIME } from '../../config.js'; import { STALE_TIME } from '../../config.js';
import { ClientContext, StateContext } from '../../state.js'; import { ClientContext } from '../../state.js';
import { QueryList } from '../input/QueryList.js'; import { QueryList } from '../input/QueryList.js';
export interface ModelControlProps { export interface ModelControlProps {
@ -20,7 +20,6 @@ export function ModelControl(props: ModelControlProps) {
const { model, setModel } = props; const { model, setModel } = props;
const client = mustExist(useContext(ClientContext)); const client = mustExist(useContext(ClientContext));
const state = mustExist(useContext(StateContext));
const { t } = useTranslation(); const { t } = useTranslation();
const restart = useMutation(['restart'], async () => client.restart()); const restart = useMutation(['restart'], async () => client.restart());

View File

@ -1,20 +1,21 @@
import { doesExist, mustExist } from '@apextoaster/js-utils'; import { doesExist, mustExist } from '@apextoaster/js-utils';
import { Box, Button, Stack } from '@mui/material'; import { Box, Button, Stack } from '@mui/material';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import * as React from 'react'; import * as React from 'react';
import { useContext } from 'react'; import { useContext } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useStore } from 'zustand'; import { useStore } from 'zustand';
import { HighresParams, Img2ImgParams, ModelParams, UpscaleParams } from '../../client/types.js';
import { IMAGE_FILTER, STALE_TIME } from '../../config.js'; import { IMAGE_FILTER, STALE_TIME } from '../../config.js';
import { ClientContext, ConfigContext, StateContext } from '../../state.js'; import { ClientContext, ConfigContext, OnnxState, StateContext, TabState } from '../../state.js';
import { HighresControl } from '../control/HighresControl.js';
import { ImageControl } from '../control/ImageControl.js'; import { ImageControl } from '../control/ImageControl.js';
import { ModelControl } from '../control/ModelControl.js';
import { UpscaleControl } from '../control/UpscaleControl.js'; import { UpscaleControl } from '../control/UpscaleControl.js';
import { ImageInput } from '../input/ImageInput.js'; import { ImageInput } from '../input/ImageInput.js';
import { NumericField } from '../input/NumericField.js'; import { NumericField } from '../input/NumericField.js';
import { QueryList } from '../input/QueryList.js'; import { QueryList } from '../input/QueryList.js';
import { HighresControl } from '../control/HighresControl.js';
import { ModelControl } from '../control/ModelControl.js';
import { Profiles } from '../Profiles.js'; import { Profiles } from '../Profiles.js';
export function Img2Img() { export function Img2Img() {
@ -43,11 +44,11 @@ export function Img2Img() {
}); });
const state = mustExist(useContext(StateContext)); const state = mustExist(useContext(StateContext));
const model = useStore(state, (s) => s.img2imgModel); const model = useStore(state, selectModel);
const source = useStore(state, (s) => s.img2img.source); const source = useStore(state, (s) => s.img2img.source);
const img2img = useStore(state, (s) => s.img2img); const img2img = useStore(state, selectParams);
const highres = useStore(state, (s) => s.img2imgHighres); const highres = useStore(state, selectHighres);
const upscale = useStore(state, (s) => s.img2imgUpscale); const upscale = useStore(state, selectUpscale);
// eslint-disable-next-line @typescript-eslint/unbound-method // eslint-disable-next-line @typescript-eslint/unbound-method
const setImg2Img = useStore(state, (s) => s.setImg2Img); const setImg2Img = useStore(state, (s) => s.setImg2Img);
// eslint-disable-next-line @typescript-eslint/unbound-method // eslint-disable-next-line @typescript-eslint/unbound-method
@ -62,7 +63,14 @@ export function Img2Img() {
return <Box> return <Box>
<Stack spacing={2}> <Stack spacing={2}>
<Profiles params={img2img} setParams={setImg2Img} highres={highres} setHighres={setHighres} upscale={upscale} setUpscale={setUpscale} /> <Profiles
params={img2img}
setParams={setImg2Img}
highres={highres}
setHighres={setHighres}
upscale={upscale}
setUpscale={setUpscale}
/>
<ModelControl model={model} setModel={setModel} /> <ModelControl model={model} setModel={setModel} />
<ImageInput <ImageInput
filter={IMAGE_FILTER} filter={IMAGE_FILTER}
@ -143,3 +151,19 @@ export function Img2Img() {
</Stack> </Stack>
</Box>; </Box>;
} }
export function selectModel(state: OnnxState): ModelParams {
return state.img2imgModel;
}
export function selectParams(state: OnnxState): TabState<Img2ImgParams> {
return state.img2img;
}
export function selectHighres(state: OnnxState): HighresParams {
return state.img2imgHighres;
}
export function selectUpscale(state: OnnxState): UpscaleParams {
return state.img2imgUpscale;
}

View File

@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next';
import { useStore } from 'zustand'; import { useStore } from 'zustand';
import { IMAGE_FILTER, STALE_TIME } from '../../config.js'; import { IMAGE_FILTER, STALE_TIME } from '../../config.js';
import { ClientContext, ConfigContext, StateContext } from '../../state.js'; import { ClientContext, ConfigContext, OnnxState, StateContext, TabState } from '../../state.js';
import { HighresControl } from '../control/HighresControl.js'; import { HighresControl } from '../control/HighresControl.js';
import { ImageControl } from '../control/ImageControl.js'; import { ImageControl } from '../control/ImageControl.js';
import { ModelControl } from '../control/ModelControl.js'; import { ModelControl } from '../control/ModelControl.js';
@ -18,6 +18,7 @@ import { MaskCanvas } from '../input/MaskCanvas.js';
import { NumericField } from '../input/NumericField.js'; import { NumericField } from '../input/NumericField.js';
import { QueryList } from '../input/QueryList.js'; import { QueryList } from '../input/QueryList.js';
import { Profiles } from '../Profiles.js'; import { Profiles } from '../Profiles.js';
import { ModelParams, InpaintParams, HighresParams, UpscaleParams } from '../../client/types.js';
export function Inpaint() { export function Inpaint() {
const { params } = mustExist(useContext(ConfigContext)); const { params } = mustExist(useContext(ConfigContext));
@ -35,16 +36,16 @@ export function Inpaint() {
const { image, retry } = await client.outpaint(model, { const { image, retry } = await client.outpaint(model, {
...inpaint, ...inpaint,
...outpaint, ...outpaint,
mask: mustExist(mask), mask: mustExist(inpaint.mask),
source: mustExist(source), source: mustExist(inpaint.source),
}, upscale, highres); }, upscale, highres);
pushHistory(image, retry); pushHistory(image, retry);
} else { } else {
const { image, retry } = await client.inpaint(model, { const { image, retry } = await client.inpaint(model, {
...inpaint, ...inpaint,
mask: mustExist(mask), mask: mustExist(inpaint.mask),
source: mustExist(source), source: mustExist(inpaint.source),
}, upscale, highres); }, upscale, highres);
pushHistory(image, retry); pushHistory(image, retry);
@ -52,7 +53,7 @@ export function Inpaint() {
} }
function preventInpaint(): boolean { function preventInpaint(): boolean {
return doesExist(source) === false || doesExist(mask) === false; return doesExist(inpaint.source) === false || doesExist(inpaint.mask) === false;
} }
function supportsInpaint(): boolean { function supportsInpaint(): boolean {
@ -60,15 +61,12 @@ export function Inpaint() {
} }
const state = mustExist(useContext(StateContext)); const state = mustExist(useContext(StateContext));
const mask = useStore(state, (s) => s.inpaint.mask); const inpaint = useStore(state, selectParams);
const source = useStore(state, (s) => s.inpaint.source); const highres = useStore(state, selectHighres);
const inpaint = useStore(state, (s) => s.inpaint); const model = useStore(state, selectModel);
const upscale = useStore(state, selectUpscale);
const outpaint = useStore(state, (s) => s.outpaint); const outpaint = useStore(state, (s) => s.outpaint);
const brush = useStore(state, (s) => s.inpaintBrush); const brush = useStore(state, (s) => s.inpaintBrush);
const highres = useStore(state, (s) => s.inpaintHighres);
const model = useStore(state, (s) => s.inpaintModel);
const upscale = useStore(state, (s) => s.inpaintUpscale);
// eslint-disable-next-line @typescript-eslint/unbound-method // eslint-disable-next-line @typescript-eslint/unbound-method
const setInpaint = useStore(state, (s) => s.setInpaint); const setInpaint = useStore(state, (s) => s.setInpaint);
@ -100,12 +98,19 @@ export function Inpaint() {
return <Box> return <Box>
<Stack spacing={2}> <Stack spacing={2}>
<Profiles params={inpaint} setParams={setInpaint} highres={highres} setHighres={setHighres} upscale={upscale} setUpscale={setUpscale} /> <Profiles
params={inpaint}
setParams={setInpaint}
highres={highres}
setHighres={setHighres}
upscale={upscale}
setUpscale={setUpscale}
/>
<ModelControl model={model} setModel={setModel} /> <ModelControl model={model} setModel={setModel} />
{renderBanner()} {renderBanner()}
<ImageInput <ImageInput
filter={IMAGE_FILTER} filter={IMAGE_FILTER}
image={source} image={inpaint.source}
label={t('input.image.source')} label={t('input.image.source')}
hideSelection={true} hideSelection={true}
onChange={(file) => { onChange={(file) => {
@ -116,7 +121,7 @@ export function Inpaint() {
/> />
<ImageInput <ImageInput
filter={IMAGE_FILTER} filter={IMAGE_FILTER}
image={mask} image={inpaint.mask}
label={t('input.image.mask')} label={t('input.image.mask')}
hideSelection={true} hideSelection={true}
onChange={(file) => { onChange={(file) => {
@ -127,8 +132,8 @@ export function Inpaint() {
/> />
<MaskCanvas <MaskCanvas
brush={brush} brush={brush}
source={source} source={inpaint.source}
mask={mask} mask={inpaint.mask}
onSave={(file) => { onSave={(file) => {
setInpaint({ setInpaint({
mask: file, mask: file,
@ -232,3 +237,19 @@ export function Inpaint() {
</Stack> </Stack>
</Box>; </Box>;
} }
export function selectModel(state: OnnxState): ModelParams {
return state.inpaintModel;
}
export function selectParams(state: OnnxState): TabState<InpaintParams> {
return state.inpaint;
}
export function selectHighres(state: OnnxState): HighresParams {
return state.inpaintHighres;
}
export function selectUpscale(state: OnnxState): UpscaleParams {
return state.inpaintUpscale;
}

View File

@ -6,13 +6,14 @@ import { useTranslation } from 'react-i18next';
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useStore } from 'zustand'; import { useStore } from 'zustand';
import { ClientContext, ConfigContext, StateContext } from '../../state.js'; import { ClientContext, ConfigContext, OnnxState, StateContext, TabState } from '../../state.js';
import { HighresControl } from '../control/HighresControl.js'; import { HighresControl } from '../control/HighresControl.js';
import { ImageControl } from '../control/ImageControl.js'; import { ImageControl } from '../control/ImageControl.js';
import { UpscaleControl } from '../control/UpscaleControl.js'; import { UpscaleControl } from '../control/UpscaleControl.js';
import { NumericField } from '../input/NumericField.js'; import { NumericField } from '../input/NumericField.js';
import { ModelControl } from '../control/ModelControl.js'; import { ModelControl } from '../control/ModelControl.js';
import { Profiles } from '../Profiles.js'; import { Profiles } from '../Profiles.js';
import { HighresParams, ModelParams, Txt2ImgParams, UpscaleParams } from '../../client/types.js';
export function Txt2Img() { export function Txt2Img() {
const { params } = mustExist(useContext(ConfigContext)); const { params } = mustExist(useContext(ConfigContext));
@ -30,10 +31,10 @@ export function Txt2Img() {
}); });
const state = mustExist(useContext(StateContext)); const state = mustExist(useContext(StateContext));
const txt2img = useStore(state, (s) => s.txt2img); const txt2img = useStore(state, selectParams);
const model = useStore(state, (s) => s.txt2imgModel); const model = useStore(state, selectModel);
const highres = useStore(state, (s) => s.txt2imgHighres); const highres = useStore(state, selectHighres);
const upscale = useStore(state, (s) => s.txt2imgUpscale); const upscale = useStore(state, selectUpscale);
// eslint-disable-next-line @typescript-eslint/unbound-method // eslint-disable-next-line @typescript-eslint/unbound-method
const setParams = useStore(state, (s) => s.setTxt2Img); const setParams = useStore(state, (s) => s.setTxt2Img);
// eslint-disable-next-line @typescript-eslint/unbound-method // eslint-disable-next-line @typescript-eslint/unbound-method
@ -48,7 +49,14 @@ export function Txt2Img() {
return <Box> return <Box>
<Stack spacing={2}> <Stack spacing={2}>
<Profiles params={txt2img} setParams={setParams} highres={highres} setHighres={setHighres} upscale={upscale} setUpscale={setUpscale} /> <Profiles
params={txt2img}
setParams={setParams}
highres={highres}
setHighres={setHighres}
upscale={upscale}
setUpscale={setUpscale}
/>
<ModelControl model={model} setModel={setModel} /> <ModelControl model={model} setModel={setModel} />
<ImageControl selector={(s) => s.txt2img} onChange={setParams} /> <ImageControl selector={(s) => s.txt2img} onChange={setParams} />
<Stack direction='row' spacing={4}> <Stack direction='row' spacing={4}>
@ -86,3 +94,19 @@ export function Txt2Img() {
</Stack> </Stack>
</Box>; </Box>;
} }
export function selectModel(state: OnnxState): ModelParams {
return state.txt2imgModel;
}
export function selectParams(state: OnnxState): TabState<Txt2ImgParams> {
return state.txt2img;
}
export function selectHighres(state: OnnxState): HighresParams {
return state.txt2imgHighres;
}
export function selectUpscale(state: OnnxState): UpscaleParams {
return state.txt2imgUpscale;
}

View File

@ -43,9 +43,9 @@ interface HistoryItem {
interface ProfileItem { interface ProfileItem {
name: string; name: string;
params: Txt2ImgParams; params: BaseImgParams | Txt2ImgParams;
highResParams?: Maybe<HighresParams>; highres?: Maybe<HighresParams>;
upscaleParams?: Maybe<UpscaleParams>; upscale?: Maybe<UpscaleParams>;
} }
interface DefaultSlice { interface DefaultSlice {

View File

@ -72,3 +72,7 @@ export interface ExtrasFile {
networks: Array<ExtraNetwork>; networks: Array<ExtraNetwork>;
sources: Array<ExtraSource>; sources: Array<ExtraSource>;
} }
export type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
} : T;