1
0
Fork 0

feat(gui): add download and delete buttons to image history

This commit is contained in:
Sean Sube 2023-01-06 22:20:14 -06:00
parent 4585792492
commit e605c9f66b
5 changed files with 58 additions and 31 deletions

View File

@ -299,7 +299,7 @@ If you have a good base or example prompt, you can set that in the config file:
}
```
When running the dev server, `node serve.js`, the config file at `out/config.json` will be loaded. If you want to load
When running the dev server, `node serve.js`, the config file will be loaded from `out/config.json`. If you want to load
a different config file, save it to your home directory named `onnx-web-config.json` and copy it into the output
directory after building the bundle:
@ -307,7 +307,8 @@ directory after building the bundle:
> make bundle && cp -v ~/onnx-web-config.json out/config.json
```
When running the container, you can mount the config at `/usr/share/nginx/html/config.json` using:
When running the container, the config will be loaded from `/usr/share/nginx/html/config.json` and you can mount a
custom config using:
```shell
> podman run -p 8000:80 --rm -v ~/onnx-web-config.json:/usr/share/nginx/html/config.json:ro docker.io/ssube/onnx-web-gui:main-nginx-bullseye

View File

@ -14,6 +14,9 @@ from os import environ, makedirs, path, scandir
import numpy as np
# defaults
default_model = "stable-diffusion-onnx-v1-5"
default_platform = "amd"
default_scheduler = "euler-a"
default_prompt = "a photo of an astronaut eating a hamburger"
default_cfg = 8
default_steps = 20
@ -97,7 +100,8 @@ def load_pipeline(model, provider, scheduler):
if last_pipeline_scheduler != scheduler:
print('changing pipeline scheduler')
pipe.scheduler = scheduler.from_pretrained(model, subfolder="scheduler")
pipe.scheduler = scheduler.from_pretrained(
model, subfolder="scheduler")
last_pipeline_scheduler = scheduler
return pipe
@ -176,11 +180,11 @@ def txt2img():
user = request.remote_addr
# pipeline stuff
model = safer_join(model_path, request.args.get('model', 'stable-diffusion-onnx-v1-5'))
model = safer_join(model_path, request.args.get('model', default_model))
provider = get_from_map(request.args, 'platform',
platform_providers, 'amd')
platform_providers, default_platform)
scheduler = get_from_map(request.args, 'scheduler',
pipeline_schedulers, 'euler-a')
pipeline_schedulers, default_scheduler)
# image params
prompt = request.args.get('prompt', default_prompt)

View File

@ -1,17 +1,27 @@
import { Box, Card, CardContent, CardMedia, Grid, Paper } from '@mui/material';
import { doesExist } from '@apextoaster/js-utils';
import { Delete, Download } from '@mui/icons-material';
import { Box, Button, Card, CardContent, CardMedia, Grid, Paper } from '@mui/material';
import * as React from 'react';
import { ApiResponse } from '../api/client.js';
export interface ImageCardProps {
value: ApiResponse;
onDelete?: (key: ApiResponse) => void;
}
export function GridItem(props: {xs: number; children: React.ReactNode}) {
return <Grid item xs={props.xs}>
<Paper elevation={0} sx={{ padding: 1 }}>{props.children}</Paper>
</Grid>;
}
export function ImageCard(props: ImageCardProps) {
const { value } = props;
const { params, output } = value;
return <Card sx={{ maxWidth: params.width }}>
return <Card sx={{ maxWidth: params.width }} elevation={2}>
<CardMedia sx={{ height: params.height }}
component='img'
image={output}
@ -20,24 +30,26 @@ export function ImageCard(props: ImageCardProps) {
<CardContent>
<Box>
<Grid container spacing={2}>
<Grid item xs={4}>
<Paper>CFG: {params.cfg}</Paper>
</Grid>
<Grid item xs={4}>
<Paper>Steps: {params.steps}</Paper>
</Grid>
<Grid item xs={4}>
<Paper>Size: {params.width}x{params.height}</Paper>
</Grid>
<Grid item xs={4}>
<Paper>Seed: {params.seed}</Paper>
</Grid>
<Grid item xs={8}>
<Paper>Scheduler: {params.scheduler}</Paper>
</Grid>
<Grid item xs={12}>
<Paper>{params.prompt}</Paper>
</Grid>
<GridItem xs={4}>CFG: {params.cfg}</GridItem>
<GridItem xs={4}>Steps: {params.steps}</GridItem>
<GridItem xs={4}>Size: {params.width}x{params.height}</GridItem>
<GridItem xs={4}>Seed: {params.seed}</GridItem>
<GridItem xs={8}>Scheduler: {params.scheduler}</GridItem>
<GridItem xs={12}>{params.prompt}</GridItem>
<GridItem xs={2}>
<Button onClick={() => window.open(output, '_blank')}>
<Download />
</Button>
</GridItem>
<GridItem xs={2}>
<Button onClick={() => {
if (doesExist(props.onDelete)) {
props.onDelete(value);
}
}}>
<Delete />
</Button>
</GridItem>
</Grid>
</Box>
</CardContent>

View File

@ -4,12 +4,18 @@ import * as React from 'react';
import { UseMutationResult } from 'react-query';
import { LoadingCard } from './LoadingCard';
export interface MutationHistoryChildProps<T> {
value: T;
onDelete: (key: T) => void;
}
export interface MutationHistoryProps<T> {
element: React.ComponentType<{value: T}>;
element: React.ComponentType<MutationHistoryChildProps<T>>;
limit: number;
result: UseMutationResult<T, unknown, void>;
isPresent: (list: Array<T>, item: T) => boolean;
isEqual: (a: T, b: T) => boolean;
}
export function MutationHistory<T>(props: MutationHistoryProps<T>) {
@ -25,7 +31,7 @@ export function MutationHistory<T>(props: MutationHistoryProps<T>) {
if (status === 'success') {
const { data } = result;
if (props.isPresent(history, data)) {
if (history.some((other) => props.isEqual(data, other))) {
// item already exists, skip it
} else {
setHistory([
@ -35,8 +41,12 @@ export function MutationHistory<T>(props: MutationHistoryProps<T>) {
}
}
function removeHistory(data: T) {
setHistory(history.filter((item) => props.isEqual(item, data) === false));
}
if (history.length > 0) {
children.push(...history.map((item) => <props.element value={item} />));
children.push(...history.map((item) => <props.element value={item} onDelete={removeHistory} />));
} else {
// only show the prompt when the button has not been pushed
if (status !== 'loading') {

View File

@ -71,7 +71,7 @@ export function Txt2Img(props: Txt2ImgProps) {
}} />
<Button onClick={() => generate.mutate()}>Generate</Button>
<MutationHistory result={generate} limit={4} element={ImageCard}
isPresent={(list, item) => list.some((other) => item.output === other.output)}
isEqual={(a, b) => a.output === b.output}
/>
</Stack>
</Box>;