feat(gui): load and merge server params with config
This commit is contained in:
parent
03fd728ab0
commit
37efd51341
|
@ -2,10 +2,18 @@
|
||||||
"api": {
|
"api": {
|
||||||
"root": "http://127.0.0.1:5000"
|
"root": "http://127.0.0.1:5000"
|
||||||
},
|
},
|
||||||
"default": {
|
"params": {
|
||||||
"model": "stable-diffusion-onnx-v1-5",
|
"model": {
|
||||||
"platform": "amd",
|
"default": "stable-diffusion-onnx-v1-5"
|
||||||
"scheduler": "euler-a",
|
},
|
||||||
"prompt": "an astronaut eating a hamburger"
|
"platform": {
|
||||||
|
"default": "amd"
|
||||||
|
},
|
||||||
|
"scheduler": {
|
||||||
|
"default": "euler-a"
|
||||||
|
},
|
||||||
|
"prompt": {
|
||||||
|
"default": "an astronaut eating a hamburger"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,7 +13,9 @@
|
||||||
"@mui/icons-material": "^5.11.0",
|
"@mui/icons-material": "^5.11.0",
|
||||||
"@mui/lab": "^5.0.0-alpha.114",
|
"@mui/lab": "^5.0.0-alpha.114",
|
||||||
"@mui/material": "^5.11.3",
|
"@mui/material": "^5.11.3",
|
||||||
|
"@types/lodash": "^4.14.191",
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"noicejs": "^5.0.0-3",
|
"noicejs": "^5.0.0-3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { doesExist, NotImplementedError } from '@apextoaster/js-utils';
|
import { doesExist, NotImplementedError } from '@apextoaster/js-utils';
|
||||||
|
import { ConfigParams } from '../config';
|
||||||
|
|
||||||
export interface BaseImgParams {
|
export interface BaseImgParams {
|
||||||
/**
|
/**
|
||||||
|
@ -57,6 +58,7 @@ export interface ApiResponse {
|
||||||
|
|
||||||
export interface ApiClient {
|
export interface ApiClient {
|
||||||
models(): Promise<Array<string>>;
|
models(): Promise<Array<string>>;
|
||||||
|
params(): Promise<ConfigParams>;
|
||||||
platforms(): Promise<Array<string>>;
|
platforms(): Promise<Array<string>>;
|
||||||
schedulers(): Promise<Array<string>>;
|
schedulers(): Promise<Array<string>>;
|
||||||
|
|
||||||
|
@ -136,6 +138,11 @@ export function makeClient(root: string, f = fetch): ApiClient {
|
||||||
const res = await f(path);
|
const res = await f(path);
|
||||||
return await res.json() as Array<string>;
|
return await res.json() as Array<string>;
|
||||||
},
|
},
|
||||||
|
async params(): Promise<ConfigParams> {
|
||||||
|
const path = new URL(joinPath('settings', 'params'), root);
|
||||||
|
const res = await f(path);
|
||||||
|
return await res.json() as ConfigParams;
|
||||||
|
},
|
||||||
async schedulers(): Promise<Array<string>> {
|
async schedulers(): Promise<Array<string>> {
|
||||||
const path = new URL(joinPath('settings', 'schedulers'), root);
|
const path = new URL(joinPath('settings', 'schedulers'), root);
|
||||||
const res = await f(path);
|
const res = await f(path);
|
||||||
|
|
|
@ -1,28 +1,30 @@
|
||||||
import { doesExist } from '@apextoaster/js-utils';
|
import { doesExist } from '@apextoaster/js-utils';
|
||||||
import { Casino } from '@mui/icons-material';
|
import { Casino } from '@mui/icons-material';
|
||||||
import { IconButton, Stack, TextField } from '@mui/material';
|
import { Button, Stack, TextField } from '@mui/material';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { BaseImgParams } from '../api/client.js';
|
import { BaseImgParams } from '../api/client.js';
|
||||||
import { CONFIG_DEFAULTS } from '../config.js';
|
import { ConfigParams } from '../config.js';
|
||||||
import { NumericField } from './NumericField.js';
|
import { NumericField } from './NumericField.js';
|
||||||
|
|
||||||
export interface ImageControlProps {
|
export interface ImageControlProps {
|
||||||
|
config: ConfigParams;
|
||||||
params: BaseImgParams;
|
params: BaseImgParams;
|
||||||
|
|
||||||
onChange?: (params: BaseImgParams) => void;
|
onChange?: (params: BaseImgParams) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ImageControl(props: ImageControlProps) {
|
export function ImageControl(props: ImageControlProps) {
|
||||||
const { params } = props;
|
const { config, params } = props;
|
||||||
|
|
||||||
return <Stack spacing={2}>
|
return <Stack spacing={2}>
|
||||||
<Stack direction='row' spacing={4}>
|
<Stack direction='row' spacing={4}>
|
||||||
<NumericField
|
<NumericField
|
||||||
decimal
|
decimal
|
||||||
label='CFG'
|
label='CFG'
|
||||||
min={CONFIG_DEFAULTS.cfg.min}
|
min={config.cfg.min}
|
||||||
max={CONFIG_DEFAULTS.cfg.max}
|
max={config.cfg.max}
|
||||||
step={CONFIG_DEFAULTS.cfg.step}
|
step={config.cfg.step}
|
||||||
value={params.cfg}
|
value={params.cfg}
|
||||||
onChange={(cfg) => {
|
onChange={(cfg) => {
|
||||||
if (doesExist(props.onChange)) {
|
if (doesExist(props.onChange)) {
|
||||||
|
@ -35,9 +37,9 @@ export function ImageControl(props: ImageControlProps) {
|
||||||
/>
|
/>
|
||||||
<NumericField
|
<NumericField
|
||||||
label='Steps'
|
label='Steps'
|
||||||
min={CONFIG_DEFAULTS.steps.min}
|
min={config.steps.min}
|
||||||
max={CONFIG_DEFAULTS.steps.max}
|
max={config.steps.max}
|
||||||
step={CONFIG_DEFAULTS.steps.step}
|
step={config.steps.step}
|
||||||
value={params.steps}
|
value={params.steps}
|
||||||
onChange={(steps) => {
|
onChange={(steps) => {
|
||||||
if (doesExist(props.onChange)) {
|
if (doesExist(props.onChange)) {
|
||||||
|
@ -50,9 +52,9 @@ export function ImageControl(props: ImageControlProps) {
|
||||||
/>
|
/>
|
||||||
<NumericField
|
<NumericField
|
||||||
label='Seed'
|
label='Seed'
|
||||||
min={CONFIG_DEFAULTS.seed.min}
|
min={config.seed.min}
|
||||||
max={CONFIG_DEFAULTS.seed.max}
|
max={config.seed.max}
|
||||||
step={CONFIG_DEFAULTS.seed.step}
|
step={config.seed.step}
|
||||||
value={params.seed}
|
value={params.seed}
|
||||||
onChange={(seed) => {
|
onChange={(seed) => {
|
||||||
if (doesExist(props.onChange)) {
|
if (doesExist(props.onChange)) {
|
||||||
|
@ -63,17 +65,21 @@ export function ImageControl(props: ImageControlProps) {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<IconButton onClick={() => {
|
<Button
|
||||||
const seed = Math.floor(Math.random() * CONFIG_DEFAULTS.seed.max);
|
variant='outlined'
|
||||||
|
startIcon={<Casino />}
|
||||||
|
onClick={() => {
|
||||||
|
const seed = Math.floor(Math.random() * config.seed.max);
|
||||||
if (doesExist(props.onChange)) {
|
if (doesExist(props.onChange)) {
|
||||||
props.onChange({
|
props.onChange({
|
||||||
...params,
|
...params,
|
||||||
seed,
|
seed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}}>
|
}}
|
||||||
<Casino />
|
>
|
||||||
</IconButton>
|
New Seed
|
||||||
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
<TextField label='Prompt' variant='outlined' value={params.prompt} onChange={(event) => {
|
<TextField label='Prompt' variant='outlined' value={params.prompt} onChange={(event) => {
|
||||||
if (doesExist(props.onChange)) {
|
if (doesExist(props.onChange)) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as React from 'react';
|
||||||
import { useMutation, useQuery } from 'react-query';
|
import { useMutation, useQuery } from 'react-query';
|
||||||
|
|
||||||
import { ApiClient, BaseImgParams } from '../api/client.js';
|
import { ApiClient, BaseImgParams } from '../api/client.js';
|
||||||
import { Config, CONFIG_DEFAULTS, IMAGE_FILTER, STALE_TIME } from '../config.js';
|
import { ConfigParams, IMAGE_FILTER, STALE_TIME } from '../config.js';
|
||||||
import { SCHEDULER_LABELS } from '../strings.js';
|
import { SCHEDULER_LABELS } from '../strings.js';
|
||||||
import { ImageInput } from './ImageInput.js';
|
import { ImageInput } from './ImageInput.js';
|
||||||
import { ImageCard } from './ImageCard.js';
|
import { ImageCard } from './ImageCard.js';
|
||||||
|
@ -17,7 +17,7 @@ const { useState } = React;
|
||||||
|
|
||||||
export interface Img2ImgProps {
|
export interface Img2ImgProps {
|
||||||
client: ApiClient;
|
client: ApiClient;
|
||||||
config: Config;
|
config: ConfigParams;
|
||||||
|
|
||||||
model: string;
|
model: string;
|
||||||
platform: string;
|
platform: string;
|
||||||
|
@ -43,14 +43,14 @@ export function Img2Img(props: Img2ImgProps) {
|
||||||
});
|
});
|
||||||
|
|
||||||
const [source, setSource] = useState<File>();
|
const [source, setSource] = useState<File>();
|
||||||
const [strength, setStrength] = useState(CONFIG_DEFAULTS.strength.default);
|
const [strength, setStrength] = useState(config.strength.default);
|
||||||
const [params, setParams] = useState<BaseImgParams>({
|
const [params, setParams] = useState<BaseImgParams>({
|
||||||
cfg: CONFIG_DEFAULTS.cfg.default,
|
cfg: config.cfg.default,
|
||||||
seed: CONFIG_DEFAULTS.seed.default,
|
seed: config.seed.default,
|
||||||
steps: CONFIG_DEFAULTS.steps.default,
|
steps: config.steps.default,
|
||||||
prompt: config.default.prompt,
|
prompt: config.prompt.default,
|
||||||
});
|
});
|
||||||
const [scheduler, setScheduler] = useState(config.default.scheduler);
|
const [scheduler, setScheduler] = useState(config.scheduler.default);
|
||||||
|
|
||||||
return <Box>
|
return <Box>
|
||||||
<Stack spacing={2}>
|
<Stack spacing={2}>
|
||||||
|
@ -67,15 +67,15 @@ export function Img2Img(props: Img2ImgProps) {
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<ImageInput filter={IMAGE_FILTER} label='Source' onChange={setSource} />
|
<ImageInput filter={IMAGE_FILTER} label='Source' onChange={setSource} />
|
||||||
<ImageControl params={params} onChange={(newParams) => {
|
<ImageControl config={config} params={params} onChange={(newParams) => {
|
||||||
setParams(newParams);
|
setParams(newParams);
|
||||||
}} />
|
}} />
|
||||||
<NumericField
|
<NumericField
|
||||||
decimal
|
decimal
|
||||||
label='Strength'
|
label='Strength'
|
||||||
min={CONFIG_DEFAULTS.strength.min}
|
min={config.strength.min}
|
||||||
max={CONFIG_DEFAULTS.strength.max}
|
max={config.strength.max}
|
||||||
step={CONFIG_DEFAULTS.strength.step}
|
step={config.strength.step}
|
||||||
value={strength}
|
value={strength}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setStrength(value);
|
setStrength(value);
|
||||||
|
|
|
@ -5,7 +5,7 @@ import * as React from 'react';
|
||||||
import { useMutation, useQuery } from 'react-query';
|
import { useMutation, useQuery } from 'react-query';
|
||||||
|
|
||||||
import { ApiClient, ApiResponse, BaseImgParams, equalResponse } from '../api/client.js';
|
import { ApiClient, ApiResponse, BaseImgParams, equalResponse } from '../api/client.js';
|
||||||
import { Config, CONFIG_DEFAULTS, DEFAULT_BRUSH, IMAGE_FILTER, STALE_TIME } from '../config.js';
|
import { Config, ConfigParams, DEFAULT_BRUSH, IMAGE_FILTER, STALE_TIME } from '../config.js';
|
||||||
import { SCHEDULER_LABELS } from '../strings.js';
|
import { SCHEDULER_LABELS } from '../strings.js';
|
||||||
import { ImageInput } from './ImageInput.js';
|
import { ImageInput } from './ImageInput.js';
|
||||||
import { ImageCard } from './ImageCard.js';
|
import { ImageCard } from './ImageCard.js';
|
||||||
|
@ -57,7 +57,7 @@ export interface Point {
|
||||||
|
|
||||||
export interface InpaintProps {
|
export interface InpaintProps {
|
||||||
client: ApiClient;
|
client: ApiClient;
|
||||||
config: Config;
|
config: ConfigParams;
|
||||||
|
|
||||||
model: string;
|
model: string;
|
||||||
platform: string;
|
platform: string;
|
||||||
|
@ -166,12 +166,12 @@ export function Inpaint(props: InpaintProps) {
|
||||||
const [mask, setMask] = useState<File>();
|
const [mask, setMask] = useState<File>();
|
||||||
const [source, setSource] = useState<File>();
|
const [source, setSource] = useState<File>();
|
||||||
const [params, setParams] = useState<BaseImgParams>({
|
const [params, setParams] = useState<BaseImgParams>({
|
||||||
cfg: CONFIG_DEFAULTS.cfg.default,
|
cfg: config.cfg.default,
|
||||||
seed: CONFIG_DEFAULTS.seed.default,
|
seed: config.seed.default,
|
||||||
steps: CONFIG_DEFAULTS.steps.default,
|
steps: config.steps.default,
|
||||||
prompt: config.default.prompt,
|
prompt: config.prompt.default,
|
||||||
});
|
});
|
||||||
const [scheduler, setScheduler] = useState(config.default.scheduler);
|
const [scheduler, setScheduler] = useState(config.scheduler.default);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const canvas = mustExist(canvasRef.current);
|
const canvas = mustExist(canvasRef.current);
|
||||||
|
@ -190,11 +190,11 @@ export function Inpaint(props: InpaintProps) {
|
||||||
function renderCanvas() {
|
function renderCanvas() {
|
||||||
return <canvas
|
return <canvas
|
||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
height={CONFIG_DEFAULTS.height.default}
|
height={config.height.default}
|
||||||
width={CONFIG_DEFAULTS.width.default}
|
width={config.width.default}
|
||||||
style={{
|
style={{
|
||||||
maxHeight: CONFIG_DEFAULTS.height.default,
|
maxHeight: config.height.default,
|
||||||
maxWidth: CONFIG_DEFAULTS.width.default,
|
maxWidth: config.width.default,
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
const canvas = mustExist(canvasRef.current);
|
const canvas = mustExist(canvasRef.current);
|
||||||
|
@ -271,22 +271,25 @@ export function Inpaint(props: InpaintProps) {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
variant='outlined'
|
||||||
startIcon={<FormatColorFill />}
|
startIcon={<FormatColorFill />}
|
||||||
onClick={() => floodMask(floodBelow)}>
|
onClick={() => floodMask(floodBelow)}>
|
||||||
Gray to black
|
Gray to black
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
variant='outlined'
|
||||||
startIcon={<Gradient />}
|
startIcon={<Gradient />}
|
||||||
onClick={() => grayscaleMask()}>
|
onClick={() => grayscaleMask()}>
|
||||||
Grayscale
|
Grayscale
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
variant='outlined'
|
||||||
startIcon={<FormatColorFill />}
|
startIcon={<FormatColorFill />}
|
||||||
onClick={() => floodMask(floodAbove)}>
|
onClick={() => floodMask(floodAbove)}>
|
||||||
Gray to white
|
Gray to white
|
||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
<ImageControl params={params} onChange={(newParams) => {
|
<ImageControl config={config} params={params} onChange={(newParams) => {
|
||||||
setParams(newParams);
|
setParams(newParams);
|
||||||
}} />
|
}} />
|
||||||
<Button onClick={() => upload.mutate()}>Generate</Button>
|
<Button onClick={() => upload.mutate()}>Generate</Button>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as React from 'react';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
import { ApiClient } from '../api/client.js';
|
import { ApiClient } from '../api/client.js';
|
||||||
import { Config, STALE_TIME } from '../config.js';
|
import { Config, ConfigParams, STALE_TIME } from '../config.js';
|
||||||
import { MODEL_LABELS, PLATFORM_LABELS } from '../strings.js';
|
import { MODEL_LABELS, PLATFORM_LABELS } from '../strings.js';
|
||||||
import { Img2Img } from './Img2Img.js';
|
import { Img2Img } from './Img2Img.js';
|
||||||
import { Inpaint } from './Inpaint.js';
|
import { Inpaint } from './Inpaint.js';
|
||||||
|
@ -15,15 +15,15 @@ const { useState } = React;
|
||||||
|
|
||||||
export interface OnnxWebProps {
|
export interface OnnxWebProps {
|
||||||
client: ApiClient;
|
client: ApiClient;
|
||||||
config: Config;
|
config: ConfigParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OnnxWeb(props: OnnxWebProps) {
|
export function OnnxWeb(props: OnnxWebProps) {
|
||||||
const { client, config } = props;
|
const { client, config } = props;
|
||||||
|
|
||||||
const [tab, setTab] = useState('txt2img');
|
const [tab, setTab] = useState('txt2img');
|
||||||
const [model, setModel] = useState(config.default.model);
|
const [model, setModel] = useState(config.model.default);
|
||||||
const [platform, setPlatform] = useState(config.default.platform);
|
const [platform, setPlatform] = useState(config.platform.default);
|
||||||
|
|
||||||
const models = useQuery('models', async () => client.models(), {
|
const models = useQuery('models', async () => client.models(), {
|
||||||
staleTime: STALE_TIME,
|
staleTime: STALE_TIME,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as React from 'react';
|
||||||
import { useMutation, useQuery } from 'react-query';
|
import { useMutation, useQuery } from 'react-query';
|
||||||
|
|
||||||
import { ApiClient, BaseImgParams } from '../api/client.js';
|
import { ApiClient, BaseImgParams } from '../api/client.js';
|
||||||
import { Config, CONFIG_DEFAULTS, STALE_TIME } from '../config.js';
|
import { ConfigParams, STALE_TIME } from '../config.js';
|
||||||
import { SCHEDULER_LABELS } from '../strings.js';
|
import { SCHEDULER_LABELS } from '../strings.js';
|
||||||
import { ImageCard } from './ImageCard.js';
|
import { ImageCard } from './ImageCard.js';
|
||||||
import { ImageControl } from './ImageControl.js';
|
import { ImageControl } from './ImageControl.js';
|
||||||
|
@ -15,7 +15,7 @@ const { useState } = React;
|
||||||
|
|
||||||
export interface Txt2ImgProps {
|
export interface Txt2ImgProps {
|
||||||
client: ApiClient;
|
client: ApiClient;
|
||||||
config: Config;
|
config: ConfigParams;
|
||||||
|
|
||||||
model: string;
|
model: string;
|
||||||
platform: string;
|
platform: string;
|
||||||
|
@ -40,15 +40,15 @@ export function Txt2Img(props: Txt2ImgProps) {
|
||||||
staleTime: STALE_TIME,
|
staleTime: STALE_TIME,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [height, setHeight] = useState(CONFIG_DEFAULTS.height.default);
|
const [height, setHeight] = useState(config.height.default);
|
||||||
const [width, setWidth] = useState(CONFIG_DEFAULTS.width.default);
|
const [width, setWidth] = useState(config.width.default);
|
||||||
const [params, setParams] = useState<BaseImgParams>({
|
const [params, setParams] = useState<BaseImgParams>({
|
||||||
cfg: CONFIG_DEFAULTS.cfg.default,
|
cfg: config.cfg.default,
|
||||||
seed: CONFIG_DEFAULTS.seed.default,
|
seed: config.seed.default,
|
||||||
steps: CONFIG_DEFAULTS.steps.default,
|
steps: config.steps.default,
|
||||||
prompt: config.default.prompt,
|
prompt: config.prompt.default,
|
||||||
});
|
});
|
||||||
const [scheduler, setScheduler] = useState(config.default.scheduler);
|
const [scheduler, setScheduler] = useState(config.scheduler.default);
|
||||||
|
|
||||||
return <Box>
|
return <Box>
|
||||||
<Stack spacing={2}>
|
<Stack spacing={2}>
|
||||||
|
@ -64,15 +64,15 @@ export function Txt2Img(props: Txt2ImgProps) {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<ImageControl params={params} onChange={(newParams) => {
|
<ImageControl config={config} params={params} onChange={(newParams) => {
|
||||||
setParams(newParams);
|
setParams(newParams);
|
||||||
}} />
|
}} />
|
||||||
<Stack direction='row' spacing={4}>
|
<Stack direction='row' spacing={4}>
|
||||||
<NumericField
|
<NumericField
|
||||||
label='Width'
|
label='Width'
|
||||||
min={CONFIG_DEFAULTS.width.min}
|
min={config.width.min}
|
||||||
max={CONFIG_DEFAULTS.width.max}
|
max={config.width.max}
|
||||||
step={CONFIG_DEFAULTS.width.step}
|
step={config.width.step}
|
||||||
value={width}
|
value={width}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setWidth(value);
|
setWidth(value);
|
||||||
|
@ -80,9 +80,9 @@ export function Txt2Img(props: Txt2ImgProps) {
|
||||||
/>
|
/>
|
||||||
<NumericField
|
<NumericField
|
||||||
label='Height'
|
label='Height'
|
||||||
min={CONFIG_DEFAULTS.height.min}
|
min={config.height.min}
|
||||||
max={CONFIG_DEFAULTS.height.max}
|
max={config.height.max}
|
||||||
step={CONFIG_DEFAULTS.height.step}
|
step={config.height.step}
|
||||||
value={height}
|
value={height}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setHeight(value);
|
setHeight(value);
|
||||||
|
|
|
@ -1,17 +1,45 @@
|
||||||
import { Img2ImgParams, STATUS_SUCCESS, Txt2ImgParams } from './api/client.js';
|
import { Img2ImgParams, STATUS_SUCCESS, Txt2ImgParams } from './api/client.js';
|
||||||
|
|
||||||
|
export interface ConfigNumber {
|
||||||
|
default: number;
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
step: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConfigString {
|
||||||
|
default: string;
|
||||||
|
keys: Array<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type KeyFilter<T extends object> = {
|
||||||
|
[K in keyof T]: T[K] extends number ? K : T[K] extends string ? K : never;
|
||||||
|
}[keyof T];
|
||||||
|
|
||||||
|
export type ConfigRanges<T extends object> = {
|
||||||
|
[K in KeyFilter<T>]: T[K] extends number ? ConfigNumber : T[K] extends string ? ConfigString : never;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ConfigParams = ConfigRanges<Required<Img2ImgParams & Txt2ImgParams>>;
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
api: {
|
api: {
|
||||||
root: string;
|
root: string;
|
||||||
};
|
};
|
||||||
default: {
|
params: {
|
||||||
model: string;
|
model: ConfigString;
|
||||||
platform: string;
|
platform: ConfigString;
|
||||||
scheduler: string;
|
scheduler: ConfigString;
|
||||||
prompt: string;
|
prompt: ConfigString;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_BRUSH = 8;
|
||||||
|
export const IMAGE_FILTER = '.bmp, .jpg, .jpeg, .png';
|
||||||
|
export const IMAGE_STEP = 8;
|
||||||
|
export const IMAGE_MAX = 512;
|
||||||
|
export const STALE_TIME = 3_000;
|
||||||
|
|
||||||
export async function loadConfig(): Promise<Config> {
|
export async function loadConfig(): Promise<Config> {
|
||||||
const configPath = new URL('./config.json', window.origin);
|
const configPath = new URL('./config.json', window.origin);
|
||||||
const configReq = await fetch(configPath);
|
const configReq = await fetch(configPath);
|
||||||
|
@ -21,70 +49,3 @@ export async function loadConfig(): Promise<Config> {
|
||||||
throw new Error('could not load config');
|
throw new Error('could not load config');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfigRange {
|
|
||||||
default: number;
|
|
||||||
min: number;
|
|
||||||
max: number;
|
|
||||||
step: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type KeyFilter<T extends object> = {
|
|
||||||
[K in keyof T]: T[K] extends number ? K : T[K] extends string ? K : never;
|
|
||||||
}[keyof T];
|
|
||||||
|
|
||||||
export type ConfigRanges<T extends object> = {
|
|
||||||
[K in KeyFilter<T>]: T[K] extends number ? ConfigRange : T[K] extends string ? string : never;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DEFAULT_BRUSH = 8;
|
|
||||||
export const IMAGE_FILTER = '.bmp, .jpg, .jpeg, .png';
|
|
||||||
export const IMAGE_STEP = 8;
|
|
||||||
export const IMAGE_MAX = 512;
|
|
||||||
|
|
||||||
export const CONFIG_DEFAULTS: ConfigRanges<Required<Img2ImgParams & Txt2ImgParams>> = {
|
|
||||||
cfg: {
|
|
||||||
default: 6,
|
|
||||||
min: 1,
|
|
||||||
max: 30,
|
|
||||||
step: 0.1,
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
default: IMAGE_MAX,
|
|
||||||
min: IMAGE_STEP,
|
|
||||||
max: IMAGE_MAX,
|
|
||||||
step: IMAGE_STEP,
|
|
||||||
},
|
|
||||||
model: '',
|
|
||||||
negativePrompt: '',
|
|
||||||
platform: '',
|
|
||||||
prompt: 'an astronaut eating a hamburger',
|
|
||||||
scheduler: '',
|
|
||||||
steps: {
|
|
||||||
default: 25,
|
|
||||||
min: 1,
|
|
||||||
max: 200,
|
|
||||||
step: 1,
|
|
||||||
},
|
|
||||||
seed: {
|
|
||||||
default: -1,
|
|
||||||
min: -1,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
|
|
||||||
max: (2 ** 32) - 1,
|
|
||||||
step: 1,
|
|
||||||
},
|
|
||||||
strength: {
|
|
||||||
default: 0.5,
|
|
||||||
min: 0,
|
|
||||||
max: 1,
|
|
||||||
step: 0.01,
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
default: IMAGE_MAX,
|
|
||||||
min: IMAGE_STEP,
|
|
||||||
max: IMAGE_MAX,
|
|
||||||
step: IMAGE_STEP,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const STALE_TIME = 3_000;
|
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
import { mustExist } from '@apextoaster/js-utils';
|
import { mustExist } from '@apextoaster/js-utils';
|
||||||
|
import { merge } from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||||
|
|
||||||
import { makeClient } from './api/client.js';
|
import { makeClient } from './api/client.js';
|
||||||
import { OnnxWeb } from './components/OnnxWeb.js';
|
import { OnnxWeb } from './components/OnnxWeb.js';
|
||||||
import { loadConfig } from './config.js';
|
import { ConfigParams, loadConfig } from './config.js';
|
||||||
|
|
||||||
export async function main() {
|
export async function main() {
|
||||||
const config = await loadConfig();
|
const config = await loadConfig();
|
||||||
const client = makeClient(config.api.root);
|
const client = makeClient(config.api.root);
|
||||||
|
const params = await client.params();
|
||||||
|
const merged = merge(params, config.params) as ConfigParams;
|
||||||
const query = new QueryClient();
|
const query = new QueryClient();
|
||||||
|
|
||||||
const appElement = mustExist(document.getElementById('app'));
|
const appElement = mustExist(document.getElementById('app'));
|
||||||
const app = ReactDOM.createRoot(appElement);
|
const app = ReactDOM.createRoot(appElement);
|
||||||
app.render(<QueryClientProvider client={query}>
|
app.render(<QueryClientProvider client={query}>
|
||||||
<OnnxWeb client={client} config={config} />
|
<OnnxWeb client={client} config={merged} />
|
||||||
</QueryClientProvider>);
|
</QueryClientProvider>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -541,6 +541,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||||
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
||||||
|
|
||||||
|
"@types/lodash@^4.14.191":
|
||||||
|
version "4.14.191"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa"
|
||||||
|
integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==
|
||||||
|
|
||||||
"@types/mocha@^10.0.1":
|
"@types/mocha@^10.0.1":
|
||||||
version "10.0.1"
|
version "10.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b"
|
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b"
|
||||||
|
@ -2028,6 +2033,11 @@ lodash.merge@^4.6.2:
|
||||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||||
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
||||||
|
|
||||||
|
lodash@^4.17.21:
|
||||||
|
version "4.17.21"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||||
|
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||||
|
|
||||||
log-symbols@4.1.0:
|
log-symbols@4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
|
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
|
||||||
|
|
Loading…
Reference in New Issue