make image params a type, image controls a component
This commit is contained in:
parent
4548a44ca3
commit
6b4545b3bf
|
@ -1,3 +1,12 @@
|
||||||
# ONNX Web
|
# ONNX Web
|
||||||
|
|
||||||
This is a web GUI for ONNX models, providing a way to run AMD GPU-accelerated models on Windows with a remote web UI.
|
This is a web GUI for ONNX models, providing a way to run AMD GPU-accelerated models on Windows with a remote web UI.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Based on:
|
||||||
|
|
||||||
|
- https://gist.github.com/harishanand95/75f4515e6187a6aa3261af6ac6f61269
|
||||||
|
- https://gist.github.com/averad/256c507baa3dcc9464203dc14610d674A
|
||||||
|
- https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-AMD-GPUs
|
||||||
|
- https://www.travelneil.com/stable-diffusion-updates.html
|
||||||
|
|
|
@ -4,6 +4,8 @@ export interface Txt2ImgParams {
|
||||||
prompt: string;
|
prompt: string;
|
||||||
cfg: number;
|
cfg: number;
|
||||||
steps: number;
|
steps: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiClient {
|
export interface ApiClient {
|
||||||
|
@ -25,16 +27,16 @@ export function makeClient(root: string, f = fetch): ApiClient {
|
||||||
return {
|
return {
|
||||||
async txt2img(params: Txt2ImgParams): Promise<string> {
|
async txt2img(params: Txt2ImgParams): Promise<string> {
|
||||||
if (doesExist(pending)) {
|
if (doesExist(pending)) {
|
||||||
console.log('skipping duplicate request, one is already pending');
|
console.log('skipping request, one is already pending');
|
||||||
return pending;
|
return pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { prompt, cfg, steps } = params;
|
|
||||||
|
|
||||||
const url = new URL('/txt2img', root);
|
const url = new URL('/txt2img', root);
|
||||||
url.searchParams.append('cfg', cfg.toFixed(0));
|
url.searchParams.append('cfg', params.cfg.toFixed(0));
|
||||||
url.searchParams.append('prompt', prompt);
|
url.searchParams.append('steps', params.steps.toFixed(0));
|
||||||
url.searchParams.append('steps', steps.toFixed(0));
|
url.searchParams.append('width', params.width.toFixed(0));
|
||||||
|
url.searchParams.append('height', params.height.toFixed(0));
|
||||||
|
url.searchParams.append('prompt', params.prompt);
|
||||||
|
|
||||||
pending = f(url).then((res) => {
|
pending = f(url).then((res) => {
|
||||||
pending = undefined;
|
pending = undefined;
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
import { doesExist } from '@apextoaster/js-utils';
|
||||||
|
import { Container, Stack, TextField } from '@mui/material';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export interface ImageParams {
|
||||||
|
cfg: number;
|
||||||
|
steps: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageControlProps {
|
||||||
|
params: ImageParams;
|
||||||
|
onChange?: (params: ImageParams) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ImageControl(props: ImageControlProps) {
|
||||||
|
const { params } = props;
|
||||||
|
|
||||||
|
return <Stack spacing={2}>
|
||||||
|
<Stack direction="row" spacing={4}>
|
||||||
|
<TextField
|
||||||
|
label="CFG"
|
||||||
|
variant="outlined"
|
||||||
|
type="number"
|
||||||
|
inputProps={{ min: 0, max: 30, step: 1 }}
|
||||||
|
value={params.cfg}
|
||||||
|
onChange={(event) => {
|
||||||
|
if (doesExist(props.onChange)) {
|
||||||
|
props.onChange({
|
||||||
|
...params,
|
||||||
|
cfg: parseInt(event.target.value, 10),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label="Steps"
|
||||||
|
variant="outlined"
|
||||||
|
type="number"
|
||||||
|
inputProps={{ min: 1, max: 150, step: 1 }}
|
||||||
|
value={params.steps}
|
||||||
|
onChange={(event) => {
|
||||||
|
if (doesExist(props.onChange)) {
|
||||||
|
props.onChange({
|
||||||
|
...params,
|
||||||
|
steps: parseInt(event.target.value, 10),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
<Stack direction="row" spacing={4}>
|
||||||
|
<TextField
|
||||||
|
label="Width"
|
||||||
|
variant="outlined"
|
||||||
|
type="number"
|
||||||
|
inputProps={{ min: 1, max: 512, step: 16 }}
|
||||||
|
value={params.width}
|
||||||
|
onChange={(event) => {
|
||||||
|
if (doesExist(props.onChange)) {
|
||||||
|
props.onChange({
|
||||||
|
...params,
|
||||||
|
width: parseInt(event.target.value, 10),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label="Height"
|
||||||
|
variant="outlined"
|
||||||
|
type="number"
|
||||||
|
inputProps={{ min: 1, max: 512, step: 16 }}
|
||||||
|
value={params.height}
|
||||||
|
onChange={(event) => {
|
||||||
|
if (doesExist(props.onChange)) {
|
||||||
|
props.onChange({
|
||||||
|
...params,
|
||||||
|
height: parseInt(event.target.value, 10),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Stack>;
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import { Box, Button, Stack, TextField } from '@mui/material';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { ApiClient } from '../api/client.js';
|
import { ApiClient } from '../api/client.js';
|
||||||
|
import { ImageControl, ImageParams } from './ImageControl.js';
|
||||||
|
|
||||||
const { useState } = React;
|
const { useState } = React;
|
||||||
|
|
||||||
|
@ -13,12 +14,16 @@ export function Txt2Img(props: Txt2ImgProps) {
|
||||||
const { client } = props;
|
const { client } = props;
|
||||||
const [image, setImage] = useState('');
|
const [image, setImage] = useState('');
|
||||||
|
|
||||||
const [cfg, setCfg] = useState(5);
|
|
||||||
const [prompt, setPrompt] = useState('an astronaut eating a hamburger');
|
const [prompt, setPrompt] = useState('an astronaut eating a hamburger');
|
||||||
const [steps, setSteps] = useState(20);
|
const [params, setParams] = useState<ImageParams>({
|
||||||
|
cfg: 6,
|
||||||
|
steps: 25,
|
||||||
|
width: 512,
|
||||||
|
height: 512,
|
||||||
|
})
|
||||||
|
|
||||||
async function getImage() {
|
async function getImage() {
|
||||||
const image = await client.txt2img({ prompt, cfg, steps });
|
const image = await client.txt2img({ ...params, prompt });
|
||||||
console.log(prompt, image);
|
console.log(prompt, image);
|
||||||
setImage(image);
|
setImage(image);
|
||||||
}
|
}
|
||||||
|
@ -36,11 +41,8 @@ export function Txt2Img(props: Txt2ImgProps) {
|
||||||
<Box>
|
<Box>
|
||||||
txt2img mode
|
txt2img mode
|
||||||
</Box>
|
</Box>
|
||||||
<TextField label="CFG" variant="outlined" type="number" inputProps={{ min: 5, max: 30 }} value={cfg} onChange={(event) => {
|
<ImageControl params={params} onChange={(params) => {
|
||||||
setCfg(parseInt(event.target.value, 10));
|
setParams(params);
|
||||||
}} />
|
|
||||||
<TextField label="Steps" variant="outlined" type="number" inputProps={{ min: 15, max: 150 }} value={steps} onChange={(event) => {
|
|
||||||
setSteps(parseInt(event.target.value, 10));
|
|
||||||
}} />
|
}} />
|
||||||
<TextField label="Prompt" variant="outlined" value={prompt} onChange={(event) => {
|
<TextField label="Prompt" variant="outlined" value={prompt} onChange={(event) => {
|
||||||
setPrompt(event.target.value);
|
setPrompt(event.target.value);
|
||||||
|
|
Loading…
Reference in New Issue