From e605c9f66b4bbcf76b8b7ff113792c62087c2716 Mon Sep 17 00:00:00 2001 From: Sean Sube Date: Fri, 6 Jan 2023 22:20:14 -0600 Subject: [PATCH] feat(gui): add download and delete buttons to image history --- README.md | 5 ++- api/onnx_web/serve.py | 12 ++++-- gui/src/components/ImageCard.tsx | 52 ++++++++++++++++---------- gui/src/components/MutationHistory.tsx | 18 +++++++-- gui/src/components/Txt2Img.tsx | 2 +- 5 files changed, 58 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 0057e6ff..a6509eb1 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/api/onnx_web/serve.py b/api/onnx_web/serve.py index 459f5a5d..6db9320e 100644 --- a/api/onnx_web/serve.py +++ b/api/onnx_web/serve.py @@ -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) diff --git a/gui/src/components/ImageCard.tsx b/gui/src/components/ImageCard.tsx index 1447fcb5..d6401d86 100644 --- a/gui/src/components/ImageCard.tsx +++ b/gui/src/components/ImageCard.tsx @@ -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 + {props.children} + ; } export function ImageCard(props: ImageCardProps) { const { value } = props; const { params, output } = value; - return + return - - CFG: {params.cfg} - - - Steps: {params.steps} - - - Size: {params.width}x{params.height} - - - Seed: {params.seed} - - - Scheduler: {params.scheduler} - - - {params.prompt} - + CFG: {params.cfg} + Steps: {params.steps} + Size: {params.width}x{params.height} + Seed: {params.seed} + Scheduler: {params.scheduler} + {params.prompt} + + + + + + diff --git a/gui/src/components/MutationHistory.tsx b/gui/src/components/MutationHistory.tsx index 35a8926a..54c5c85f 100644 --- a/gui/src/components/MutationHistory.tsx +++ b/gui/src/components/MutationHistory.tsx @@ -4,12 +4,18 @@ import * as React from 'react'; import { UseMutationResult } from 'react-query'; import { LoadingCard } from './LoadingCard'; +export interface MutationHistoryChildProps { + value: T; + + onDelete: (key: T) => void; +} + export interface MutationHistoryProps { - element: React.ComponentType<{value: T}>; + element: React.ComponentType>; limit: number; result: UseMutationResult; - isPresent: (list: Array, item: T) => boolean; + isEqual: (a: T, b: T) => boolean; } export function MutationHistory(props: MutationHistoryProps) { @@ -25,7 +31,7 @@ export function MutationHistory(props: MutationHistoryProps) { 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(props: MutationHistoryProps) { } } + function removeHistory(data: T) { + setHistory(history.filter((item) => props.isEqual(item, data) === false)); + } + if (history.length > 0) { - children.push(...history.map((item) => )); + children.push(...history.map((item) => )); } else { // only show the prompt when the button has not been pushed if (status !== 'loading') { diff --git a/gui/src/components/Txt2Img.tsx b/gui/src/components/Txt2Img.tsx index dd2da791..8d1dd2e4 100644 --- a/gui/src/components/Txt2Img.tsx +++ b/gui/src/components/Txt2Img.tsx @@ -71,7 +71,7 @@ export function Txt2Img(props: Txt2ImgProps) { }} /> list.some((other) => item.output === other.output)} + isEqual={(a, b) => a.output === b.output} /> ;