Skip to content

Commit

Permalink
feat(gui): implement img2img tab
Browse files Browse the repository at this point in the history
  • Loading branch information
ssube committed Jan 7, 2023
1 parent 09ce654 commit 98a8db1
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 4 deletions.
49 changes: 49 additions & 0 deletions gui/src/api/client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { doesExist } from '@apextoaster/js-utils';

export interface Img2ImgParams {
model?: string;
platform?: string;
scheduler?: string;

prompt: string;
cfg: number;
steps: number;

source: File;
}

export interface Txt2ImgParams {
model?: string;
platform?: string;
Expand Down Expand Up @@ -34,6 +46,7 @@ export interface ApiClient {
platforms(): Promise<Array<string>>;
schedulers(): Promise<Array<string>>;

img2img(params: Img2ImgParams): Promise<ApiResponse>; // TODO: slightly different response type
txt2img(params: Txt2ImgParams): Promise<ApiResponse>;
}

Expand Down Expand Up @@ -75,6 +88,42 @@ export function makeClient(root: string, f = fetch): ApiClient {
const res = await f(path);
return await res.json() as Array<string>;
},
async img2img(params: Img2ImgParams): Promise<ApiResponse> {
if (doesExist(pending)) {
return pending;
}

const url = new URL('img2img', root);
url.searchParams.append('cfg', params.cfg.toFixed(0));
url.searchParams.append('steps', params.steps.toFixed(0));

if (doesExist(params.model)) {
url.searchParams.append('model', params.model);
}

if (doesExist(params.platform)) {
url.searchParams.append('platform', params.platform);
}

if (doesExist(params.scheduler)) {
url.searchParams.append('scheduler', params.scheduler);
}

url.searchParams.append('prompt', params.prompt);

const body = new FormData();
body.append('source', params.source, 'source');

pending = f(url, {
body,
method: 'POST',
}).then((res) => imageFromResponse(root, res)).finally(() => {
pending = undefined;
});

// eslint-disable-next-line no-return-await
return await pending;
},
async txt2img(params: Txt2ImgParams): Promise<ApiResponse> {
if (doesExist(pending)) {
return pending;
Expand Down
91 changes: 91 additions & 0 deletions gui/src/components/Img2Img.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { doesExist, mustExist } from '@apextoaster/js-utils';
import { Box, Button, Stack, TextField } from '@mui/material';
import * as React from 'react';
import { useMutation, useQuery } from 'react-query';

import { ApiClient } from '../api/client.js';
import { Config } from '../config.js';
import { SCHEDULER_LABELS } from '../strings.js';
import { ImageCard } from './ImageCard.js';
import { ImageControl, ImageParams } from './ImageControl.js';
import { MutationHistory } from './MutationHistory.js';
import { QueryList } from './QueryList.js';

const { useState } = React;

export const STALE_TIME = 3_000;
export interface Img2ImgProps {
client: ApiClient;
config: Config;

model: string;
platform: string;
}

export function Img2Img(props: Img2ImgProps) {
const { client, config, model, platform } = props;

async function uploadSource() {
return client.img2img({
...params,
model,
platform,
prompt,
scheduler,
source: mustExist(source), // TODO: show an error if this doesn't exist
});
}

function changeSource(event: React.ChangeEvent<HTMLInputElement>) {
if (doesExist(event.target.files)) {
const file = event.target.files[0];
if (doesExist(file)) {
setSource(file);
}
}
}

const upload = useMutation(uploadSource);
const schedulers = useQuery('schedulers', async () => client.schedulers(), {
staleTime: STALE_TIME,
});

const [source, setSource] = useState<File>();
const [params, setParams] = useState<ImageParams>({
cfg: 6,
seed: -1,
steps: 25,
width: 512,
height: 512,
});
const [prompt, setPrompt] = useState(config.default.prompt);
const [scheduler, setScheduler] = useState(config.default.scheduler);

return <Box>
<Stack spacing={2}>
<Stack direction='row' spacing={2}>
<QueryList
id='schedulers'
labels={SCHEDULER_LABELS}
name='Scheduler'
result={schedulers}
value={scheduler}
onChange={(value) => {
setScheduler(value);
}}
/>
</Stack>
<input type='file' onChange={changeSource} />
<ImageControl params={params} onChange={(newParams) => {
setParams(newParams);
}} />
<TextField label='Prompt' variant='outlined' value={prompt} onChange={(event) => {
setPrompt(event.target.value);
}} />
<Button onClick={() => upload.mutate()}>Generate</Button>
<MutationHistory result={upload} limit={4} element={ImageCard}
isEqual={(a, b) => a.output === b.output}
/>
</Stack>
</Box>;
}
7 changes: 3 additions & 4 deletions gui/src/components/OnnxWeb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useQuery } from 'react-query';
import { ApiClient } from '../api/client.js';
import { Config } from '../config.js';
import { MODEL_LABELS, PLATFORM_LABELS } from '../strings.js';
import { Img2Img } from './Img2Img.js';
import { QueryList } from './QueryList.js';
import { STALE_TIME, Txt2Img } from './Txt2Img.js';

Expand Down Expand Up @@ -68,17 +69,15 @@ export function OnnxWeb(props: OnnxWebProps) {
setTab(idx);
}}>
<Tab label='txt2img' value='txt2img' />
<Tab label='img2img' value='img2img' disabled />
<Tab label='img2img' value='img2img' />
<Tab label='settings' value='settings' />
</TabList>
</Box>
<TabPanel value='txt2img'>
<Txt2Img client={client} config={config} model={model} platform={platform} />
</TabPanel>
<TabPanel value='img2img'>
<Box>
img2img using {model}
</Box>
<Img2Img client={client} config={config} model={model} platform={platform} />
</TabPanel>
<TabPanel value='settings'>
<Box>
Expand Down

0 comments on commit 98a8db1

Please sign in to comment.