1
0
Fork 0

feat(gui): add prompt to upscale tab (fixes #187)

This commit is contained in:
Sean Sube 2023-02-19 13:18:20 -06:00
parent 7ef63e14c4
commit 34832f0171
Signed by: ssube
GPG Key ID: 3EED7B957D362AF1
6 changed files with 90 additions and 38 deletions

View File

@ -22,7 +22,7 @@ You can start from a diffusers directory, HuggingFace Hub repository, or an SD c
1. LoRA weights from `kohya-ss/sd-scripts` to... 1. LoRA weights from `kohya-ss/sd-scripts` to...
2. SD or Dreambooth checkpoint to... 2. SD or Dreambooth checkpoint to...
3. diffusers or LoRA weights from `cloneofsimo/lora` to... 3. diffusers directory or LoRA weights from `cloneofsimo/lora` to...
4. ONNX models 4. ONNX models
One disadvantage of using ONNX is that LoRA weights must be merged with the base model before being converted, One disadvantage of using ONNX is that LoRA weights must be merged with the base model before being converted,

View File

@ -129,6 +129,8 @@ export interface UpscaleParams {
* Parameters for upscale requests. * Parameters for upscale requests.
*/ */
export interface UpscaleReqParams { export interface UpscaleReqParams {
prompt: string;
negativePrompt?: string;
source: Blob; source: Blob;
} }
@ -477,6 +479,12 @@ export function makeClient(root: string, f = fetch): ApiClient {
appendUpscaleToURL(url, upscale); appendUpscaleToURL(url, upscale);
} }
url.searchParams.append('prompt', params.prompt);
if (doesExist(params.negativePrompt)) {
url.searchParams.append('negativePrompt', params.negativePrompt);
}
const body = new FormData(); const body = new FormData();
body.append('source', params.source, 'source'); body.append('source', params.source, 'source');

View File

@ -1,6 +1,6 @@
import { doesExist, mustDefault, mustExist } from '@apextoaster/js-utils'; import { doesExist, mustDefault, mustExist } from '@apextoaster/js-utils';
import { Casino } from '@mui/icons-material'; import { Casino } from '@mui/icons-material';
import { Button, Stack, TextField } from '@mui/material'; import { Button, Stack } from '@mui/material';
import * as React from 'react'; import * as React from 'react';
import { useContext } from 'react'; import { useContext } from 'react';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
@ -11,10 +11,9 @@ import { STALE_TIME } from '../../config.js';
import { ClientContext, ConfigContext, OnnxState, StateContext } from '../../state.js'; import { ClientContext, ConfigContext, OnnxState, StateContext } from '../../state.js';
import { SCHEDULER_LABELS } from '../../strings.js'; import { SCHEDULER_LABELS } from '../../strings.js';
import { NumericField } from '../input/NumericField.js'; import { NumericField } from '../input/NumericField.js';
import { PromptInput } from '../input/PromptInput.js';
import { QueryList } from '../input/QueryList.js'; import { QueryList } from '../input/QueryList.js';
export const PROMPT_LIMIT = 70;
export interface ImageControlProps { export interface ImageControlProps {
selector: (state: OnnxState) => BaseImgParams; selector: (state: OnnxState) => BaseImgParams;
@ -34,17 +33,6 @@ export function ImageControl(props: ImageControlProps) {
staleTime: STALE_TIME, staleTime: STALE_TIME,
}); });
const promptLength = controlState.prompt.split(' ').length;
const error = promptLength > PROMPT_LIMIT;
function promptHelper() {
if (error) {
return `Too many tokens: ${promptLength}/${PROMPT_LIMIT}`;
} else {
return `Tokens: ${promptLength}/${PROMPT_LIMIT}`;
}
}
return <Stack spacing={2}> return <Stack spacing={2}>
<QueryList <QueryList
id='schedulers' id='schedulers'
@ -126,30 +114,14 @@ export function ImageControl(props: ImageControlProps) {
New Seed New Seed
</Button> </Button>
</Stack> </Stack>
<TextField <PromptInput
error={error} prompt={controlState.prompt}
label='Prompt' negativePrompt={controlState.negativePrompt}
helperText={promptHelper()} onChange={(value) => {
variant='outlined'
value={controlState.prompt}
onChange={(event) => {
if (doesExist(props.onChange)) { if (doesExist(props.onChange)) {
props.onChange({ props.onChange({
...controlState, ...controlState,
prompt: event.target.value, ...value,
});
}
}}
/>
<TextField
label='Negative Prompt'
variant='outlined'
value={controlState.negativePrompt}
onChange={(event) => {
if (doesExist(props.onChange)) {
props.onChange({
...controlState,
negativePrompt: event.target.value,
}); });
} }
}} }}

View File

@ -0,0 +1,60 @@
import { doesExist, Maybe } from '@apextoaster/js-utils';
import { TextField } from '@mui/material';
import { Stack } from '@mui/system';
import * as React from 'react';
export interface PromptValue {
prompt: string;
negativePrompt?: string;
}
export interface PromptInputProps extends PromptValue {
onChange?: Maybe<(value: PromptValue) => void>;
}
export const PROMPT_LIMIT = 77;
export function PromptInput(props: PromptInputProps) {
const { prompt = '', negativePrompt = '' } = props;
const promptLength = prompt.split(' ').length;
const error = promptLength > PROMPT_LIMIT;
function promptHelper() {
if (error) {
return `Too many tokens: ${promptLength}/${PROMPT_LIMIT}`;
} else {
return `Tokens: ${promptLength}/${PROMPT_LIMIT}`;
}
}
return <Stack>
<TextField
error={error}
label='Prompt'
helperText={promptHelper()}
variant='outlined'
value={prompt}
onChange={(event) => {
if (doesExist(props.onChange)) {
props.onChange({
prompt: event.target.value,
negativePrompt,
});
}
}}
/>
<TextField
label='Negative Prompt'
variant='outlined'
value={negativePrompt}
onChange={(event) => {
if (doesExist(props.onChange)) {
props.onChange({
prompt,
negativePrompt: event.target.value,
});
}
}}
/>
</Stack>;
}

View File

@ -9,6 +9,7 @@ import { IMAGE_FILTER } from '../../config.js';
import { ClientContext, StateContext } from '../../state.js'; import { ClientContext, StateContext } from '../../state.js';
import { UpscaleControl } from '../control/UpscaleControl.js'; import { UpscaleControl } from '../control/UpscaleControl.js';
import { ImageInput } from '../input/ImageInput.js'; import { ImageInput } from '../input/ImageInput.js';
import { PromptInput } from '../input/PromptInput.js';
export function Upscale() { export function Upscale() {
async function uploadSource() { async function uploadSource() {
@ -47,6 +48,13 @@ export function Upscale() {
}); });
}} }}
/> />
<PromptInput
prompt={params.prompt}
negativePrompt={params.negativePrompt}
onChange={(value) => {
setSource(value);
}}
/>
<UpscaleControl /> <UpscaleControl />
<Button <Button
disabled={doesExist(params.source) === false} disabled={doesExist(params.source) === false}

View File

@ -411,6 +411,8 @@ export function createStateSlices(server: ServerParams) {
upscaleOrder: server.upscaleOrder.default, upscaleOrder: server.upscaleOrder.default,
}, },
upscaleTab: { upscaleTab: {
negativePrompt: server.negativePrompt.default,
prompt: server.prompt.default,
source: null, source: null,
}, },
setUpscale(upscale) { setUpscale(upscale) {
@ -432,6 +434,8 @@ export function createStateSlices(server: ServerParams) {
resetUpscaleTab() { resetUpscaleTab() {
set({ set({
upscaleTab: { upscaleTab: {
negativePrompt: server.negativePrompt.default,
prompt: server.prompt.default,
source: null, source: null,
}, },
}); });
@ -452,12 +456,12 @@ export function createStateSlices(server: ServerParams) {
})); }));
}, },
resetBlend() { resetBlend() {
set((prev) => ({ set({
blend: { blend: {
mask: null, mask: null,
sources: [], sources: [],
}, },
})); });
}, },
}); });