fix(gui): improve performance while using image controls
This commit is contained in:
parent
cff32102ce
commit
35e2e1dda6
|
@ -1,6 +1,9 @@
|
||||||
import { build } from 'esbuild';
|
import { build } from 'esbuild';
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
import alias from 'esbuild-plugin-alias';
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
const root = process.cwd();
|
const root = process.cwd();
|
||||||
|
|
||||||
build({
|
build({
|
||||||
|
@ -14,5 +17,11 @@ build({
|
||||||
keepNames: true,
|
keepNames: true,
|
||||||
outdir: 'out/bundle/',
|
outdir: 'out/bundle/',
|
||||||
platform: 'browser',
|
platform: 'browser',
|
||||||
|
plugins: [
|
||||||
|
alias({
|
||||||
|
'react-dom$': 'react-dom/profiling',
|
||||||
|
'scheduler/tracing': 'scheduler/tracing-profiling',
|
||||||
|
})
|
||||||
|
],
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
}).catch(() => process.exit(1));
|
}).catch(() => process.exit(1));
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
"chai-as-promised": "^7.1.1",
|
"chai-as-promised": "^7.1.1",
|
||||||
"esbuild": "^0.16.14",
|
"esbuild": "^0.16.14",
|
||||||
|
"esbuild-plugin-alias": "^0.2.1",
|
||||||
"eslint": "^8.31.0",
|
"eslint": "^8.31.0",
|
||||||
"eslint-plugin-chai": "^0.0.1",
|
"eslint-plugin-chai": "^0.0.1",
|
||||||
"eslint-plugin-chai-expect": "^3.0.0",
|
"eslint-plugin-chai-expect": "^3.0.0",
|
||||||
|
|
|
@ -10,28 +10,31 @@ import { ImageCard } from './ImageCard.js';
|
||||||
import { LoadingCard } from './LoadingCard.js';
|
import { LoadingCard } from './LoadingCard.js';
|
||||||
|
|
||||||
export function ImageHistory() {
|
export function ImageHistory() {
|
||||||
const state = useStore(mustExist(useContext(StateContext)));
|
const history = useStore(mustExist(useContext(StateContext)), (state) => state.history);
|
||||||
const { images } = state.history;
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const setHistory = useStore(mustExist(useContext(StateContext)), (state) => state.setHistory);
|
||||||
|
|
||||||
|
const { images } = history;
|
||||||
|
|
||||||
const children = [];
|
const children = [];
|
||||||
|
|
||||||
if (state.history.loading) {
|
if (history.loading) {
|
||||||
children.push(<LoadingCard key='loading' height={512} width={512} />); // TODO: get dimensions from config
|
children.push(<LoadingCard key='loading' height={512} width={512} />); // TODO: get dimensions from config
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeHistory(image: ApiResponse) {
|
function removeHistory(image: ApiResponse) {
|
||||||
state.setHistory(images.filter((item) => image.output !== item.output));
|
setHistory(images.filter((item) => image.output !== item.output));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (images.length > 0) {
|
if (images.length > 0) {
|
||||||
children.push(...images.map((item) => <ImageCard key={item.output} value={item} onDelete={removeHistory} />));
|
children.push(...images.map((item) => <ImageCard key={item.output} value={item} onDelete={removeHistory} />));
|
||||||
} else {
|
} else {
|
||||||
if (state.history.loading === false) {
|
if (history.loading === false) {
|
||||||
children.push(<div>No results. Press Generate.</div>);
|
children.push(<div>No results. Press Generate.</div>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const limited = children.slice(0, state.history.limit);
|
const limited = children.slice(0, history.limit);
|
||||||
|
|
||||||
return <Grid container spacing={2}>{limited.map((child, idx) => <Grid item key={idx} xs={6}>{child}</Grid>)}</Grid>;
|
return <Grid container spacing={2}>{limited.map((child, idx) => <Grid item key={idx} xs={6}>{child}</Grid>)}</Grid>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,30 +23,38 @@ export function Img2Img(props: Img2ImgProps) {
|
||||||
const { config, model, platform } = props;
|
const { config, model, platform } = props;
|
||||||
|
|
||||||
async function uploadSource() {
|
async function uploadSource() {
|
||||||
state.setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const output = await client.img2img({
|
const output = await client.img2img({
|
||||||
...state.img2img,
|
...params,
|
||||||
model,
|
model,
|
||||||
platform,
|
platform,
|
||||||
source: mustExist(source), // TODO: show an error if this doesn't exist
|
source: mustExist(source), // TODO: show an error if this doesn't exist
|
||||||
});
|
});
|
||||||
|
|
||||||
state.pushHistory(output);
|
pushHistory(output);
|
||||||
state.setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = mustExist(useContext(ClientContext));
|
const client = mustExist(useContext(ClientContext));
|
||||||
const upload = useMutation(uploadSource);
|
const upload = useMutation(uploadSource);
|
||||||
const state = useStore(mustExist(useContext(StateContext)));
|
|
||||||
|
const state = mustExist(useContext(StateContext));
|
||||||
|
const params = useStore(state, (s) => s.img2img);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const setImg2Img = useStore(state, (s) => s.setImg2Img);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const setLoading = useStore(state, (s) => s.setLoading);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const pushHistory = useStore(state, (s) => s.pushHistory);
|
||||||
|
|
||||||
const [source, setSource] = useState<File>();
|
const [source, setSource] = useState<File>();
|
||||||
|
|
||||||
return <Box>
|
return <Box>
|
||||||
<Stack spacing={2}>
|
<Stack spacing={2}>
|
||||||
<ImageInput filter={IMAGE_FILTER} label='Source' onChange={setSource} />
|
<ImageInput filter={IMAGE_FILTER} label='Source' onChange={setSource} />
|
||||||
<ImageControl config={config} params={state.img2img} onChange={(newParams) => {
|
<ImageControl config={config} params={params} onChange={(newParams) => {
|
||||||
state.setImg2Img(newParams);
|
setImg2Img(newParams);
|
||||||
}} />
|
}} />
|
||||||
<NumericField
|
<NumericField
|
||||||
decimal
|
decimal
|
||||||
|
@ -54,9 +62,9 @@ export function Img2Img(props: Img2ImgProps) {
|
||||||
min={config.strength.min}
|
min={config.strength.min}
|
||||||
max={config.strength.max}
|
max={config.strength.max}
|
||||||
step={config.strength.step}
|
step={config.strength.step}
|
||||||
value={state.img2img.strength}
|
value={params.strength}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
state.setImg2Img({
|
setImg2Img({
|
||||||
strength: value,
|
strength: value,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -70,18 +70,18 @@ export function Inpaint(props: InpaintProps) {
|
||||||
|
|
||||||
async function uploadSource() {
|
async function uploadSource() {
|
||||||
const canvas = mustExist(canvasRef.current);
|
const canvas = mustExist(canvasRef.current);
|
||||||
state.setLoading(true);
|
setLoading(true);
|
||||||
return new Promise<void>((res, rej) => {
|
return new Promise<void>((res, rej) => {
|
||||||
canvas.toBlob((blob) => {
|
canvas.toBlob((blob) => {
|
||||||
client.inpaint({
|
client.inpaint({
|
||||||
...state.inpaint,
|
...params,
|
||||||
model,
|
model,
|
||||||
platform,
|
platform,
|
||||||
mask: mustExist(blob),
|
mask: mustExist(blob),
|
||||||
source: mustExist(source),
|
source: mustExist(source),
|
||||||
}).then((output) => {
|
}).then((output) => {
|
||||||
state.pushHistory(output);
|
pushHistory(output);
|
||||||
state.setLoading(false);
|
setLoading(false);
|
||||||
res();
|
res();
|
||||||
}).catch((err) => rej(err));
|
}).catch((err) => rej(err));
|
||||||
});
|
});
|
||||||
|
@ -138,10 +138,18 @@ export function Inpaint(props: InpaintProps) {
|
||||||
ctx.putImageData(image, 0, 0);
|
ctx.putImageData(image, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const state = mustExist(useContext(StateContext));
|
||||||
|
const params = useStore(state, (s) => s.inpaint);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const setInpaint = useStore(state, (s) => s.setInpaint);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const setLoading = useStore(state, (s) => s.setLoading);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const pushHistory = useStore(state, (s) => s.pushHistory);
|
||||||
|
|
||||||
const upload = useMutation(uploadSource);
|
const upload = useMutation(uploadSource);
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
const state = useStore(mustExist(useContext(StateContext)));
|
|
||||||
|
|
||||||
// painting state
|
// painting state
|
||||||
const [clicks, setClicks] = useState<Array<Point>>([]);
|
const [clicks, setClicks] = useState<Array<Point>>([]);
|
||||||
|
@ -259,9 +267,9 @@ export function Inpaint(props: InpaintProps) {
|
||||||
</Stack>
|
</Stack>
|
||||||
<ImageControl
|
<ImageControl
|
||||||
config={config}
|
config={config}
|
||||||
params={state.inpaint}
|
params={params}
|
||||||
onChange={(newParams) => {
|
onChange={(newParams) => {
|
||||||
state.setInpaint(newParams);
|
setInpaint(newParams);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button onClick={() => upload.mutate()}>Generate</Button>
|
<Button onClick={() => upload.mutate()}>Generate</Button>
|
||||||
|
|
|
@ -22,26 +22,34 @@ export function Txt2Img(props: Txt2ImgProps) {
|
||||||
const { config, model, platform } = props;
|
const { config, model, platform } = props;
|
||||||
|
|
||||||
async function generateImage() {
|
async function generateImage() {
|
||||||
state.setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const output = await client.txt2img({
|
const output = await client.txt2img({
|
||||||
...state.txt2img,
|
...params,
|
||||||
model,
|
model,
|
||||||
platform,
|
platform,
|
||||||
});
|
});
|
||||||
|
|
||||||
state.pushHistory(output);
|
pushHistory(output);
|
||||||
state.setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = mustExist(useContext(ClientContext));
|
const client = mustExist(useContext(ClientContext));
|
||||||
const generate = useMutation(generateImage);
|
const generate = useMutation(generateImage);
|
||||||
const state = useStore(mustExist(useContext(StateContext)));
|
|
||||||
|
const state = mustExist(useContext(StateContext));
|
||||||
|
const params = useStore(state, (s) => s.txt2img);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const setTxt2Img = useStore(state, (s) => s.setTxt2Img);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const setLoading = useStore(state, (s) => s.setLoading);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const pushHistory = useStore(state, (s) => s.pushHistory);
|
||||||
|
|
||||||
return <Box>
|
return <Box>
|
||||||
<Stack spacing={2}>
|
<Stack spacing={2}>
|
||||||
<ImageControl config={config} params={state.txt2img} onChange={(newParams) => {
|
<ImageControl config={config} params={params} onChange={(newParams) => {
|
||||||
state.setTxt2Img(newParams);
|
setTxt2Img(newParams);
|
||||||
}} />
|
}} />
|
||||||
<Stack direction='row' spacing={4}>
|
<Stack direction='row' spacing={4}>
|
||||||
<NumericField
|
<NumericField
|
||||||
|
@ -49,9 +57,9 @@ export function Txt2Img(props: Txt2ImgProps) {
|
||||||
min={config.width.min}
|
min={config.width.min}
|
||||||
max={config.width.max}
|
max={config.width.max}
|
||||||
step={config.width.step}
|
step={config.width.step}
|
||||||
value={state.txt2img.width}
|
value={params.width}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
state.setTxt2Img({
|
setTxt2Img({
|
||||||
width: value,
|
width: value,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
@ -61,9 +69,9 @@ export function Txt2Img(props: Txt2ImgProps) {
|
||||||
min={config.height.min}
|
min={config.height.min}
|
||||||
max={config.height.max}
|
max={config.height.max}
|
||||||
step={config.height.step}
|
step={config.height.step}
|
||||||
value={state.txt2img.height}
|
value={params.height}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
state.setTxt2Img({
|
setTxt2Img({
|
||||||
height: value,
|
height: value,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -66,45 +66,6 @@ export async function main() {
|
||||||
inpaint: {
|
inpaint: {
|
||||||
...defaults,
|
...defaults,
|
||||||
},
|
},
|
||||||
setLimit(limit) {
|
|
||||||
set((oldState) => ({
|
|
||||||
...oldState,
|
|
||||||
history: {
|
|
||||||
...oldState.history,
|
|
||||||
limit,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
setLoading(loading) {
|
|
||||||
set((oldState) => ({
|
|
||||||
...oldState,
|
|
||||||
history: {
|
|
||||||
...oldState.history,
|
|
||||||
loading,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
pushHistory(newImage: ApiResponse) {
|
|
||||||
set((oldState) => ({
|
|
||||||
...oldState,
|
|
||||||
history: {
|
|
||||||
...oldState.history,
|
|
||||||
images: [
|
|
||||||
newImage,
|
|
||||||
...oldState.history.images,
|
|
||||||
].slice(0, oldState.history.limit),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
setHistory(newHistory: Array<ApiResponse>) {
|
|
||||||
set((oldState) => ({
|
|
||||||
...oldState,
|
|
||||||
history: {
|
|
||||||
...oldState.history,
|
|
||||||
images: newHistory,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
setDefaults(newParams) {
|
setDefaults(newParams) {
|
||||||
set((oldState) => ({
|
set((oldState) => ({
|
||||||
...oldState,
|
...oldState,
|
||||||
|
@ -168,6 +129,45 @@ export async function main() {
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
setLimit(limit) {
|
||||||
|
set((oldState) => ({
|
||||||
|
...oldState,
|
||||||
|
history: {
|
||||||
|
...oldState.history,
|
||||||
|
limit,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
setLoading(loading) {
|
||||||
|
set((oldState) => ({
|
||||||
|
...oldState,
|
||||||
|
history: {
|
||||||
|
...oldState.history,
|
||||||
|
loading,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
pushHistory(newImage: ApiResponse) {
|
||||||
|
set((oldState) => ({
|
||||||
|
...oldState,
|
||||||
|
history: {
|
||||||
|
...oldState.history,
|
||||||
|
images: [
|
||||||
|
newImage,
|
||||||
|
...oldState.history.images,
|
||||||
|
].slice(0, oldState.history.limit),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
setHistory(newHistory: Array<ApiResponse>) {
|
||||||
|
set((oldState) => ({
|
||||||
|
...oldState,
|
||||||
|
history: {
|
||||||
|
...oldState.history,
|
||||||
|
images: newHistory,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
},
|
||||||
}), {
|
}), {
|
||||||
name: 'onnx-web',
|
name: 'onnx-web',
|
||||||
partialize: (oldState) => ({
|
partialize: (oldState) => ({
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { ApiResponse, BaseImgParams, Img2ImgParams, InpaintParams, Txt2ImgParams } from './api/client.js';
|
||||||
|
import { ConfigState } from './config.js';
|
||||||
|
|
||||||
|
interface TabState<TabParams extends BaseImgParams> {
|
||||||
|
params: ConfigState<Required<TabParams>>;
|
||||||
|
|
||||||
|
reset(): void;
|
||||||
|
update(params: Partial<ConfigState<Required<TabParams>>>): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnnxState {
|
||||||
|
defaults: {
|
||||||
|
params: Required<BaseImgParams>;
|
||||||
|
update(newParams: Partial<BaseImgParams>): void;
|
||||||
|
};
|
||||||
|
txt2img: {
|
||||||
|
params: ConfigState<Required<Txt2ImgParams>>;
|
||||||
|
|
||||||
|
reset(): void;
|
||||||
|
update(newParams: Partial<ConfigState<Required<Txt2ImgParams>>>): void;
|
||||||
|
};
|
||||||
|
img2img: {
|
||||||
|
params: ConfigState<Required<Img2ImgParams>>;
|
||||||
|
|
||||||
|
reset(): void;
|
||||||
|
update(newParams: Partial<ConfigState<Required<Img2ImgParams>>>): void;
|
||||||
|
};
|
||||||
|
inpaint: {
|
||||||
|
params: ConfigState<Required<InpaintParams>>;
|
||||||
|
|
||||||
|
reset(): void;
|
||||||
|
update(newParams: Partial<ConfigState<Required<InpaintParams>>>): void;
|
||||||
|
};
|
||||||
|
history: {
|
||||||
|
images: Array<ApiResponse>;
|
||||||
|
limit: number;
|
||||||
|
loading: boolean;
|
||||||
|
|
||||||
|
setLimit(limit: number): void;
|
||||||
|
setLoading(loading: boolean): void;
|
||||||
|
setHistory(newHistory: Array<ApiResponse>): void;
|
||||||
|
pushHistory(newImage: ApiResponse): void;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1212,6 +1212,11 @@ es-to-primitive@^1.2.1:
|
||||||
is-date-object "^1.0.1"
|
is-date-object "^1.0.1"
|
||||||
is-symbol "^1.0.2"
|
is-symbol "^1.0.2"
|
||||||
|
|
||||||
|
esbuild-plugin-alias@^0.2.1:
|
||||||
|
version "0.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-plugin-alias/-/esbuild-plugin-alias-0.2.1.tgz#45a86cb941e20e7c2bc68a2bea53562172494fcb"
|
||||||
|
integrity sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==
|
||||||
|
|
||||||
esbuild@^0.16.14:
|
esbuild@^0.16.14:
|
||||||
version "0.16.14"
|
version "0.16.14"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.16.14.tgz#366249a0a0fd431d3ab706195721ef1014198919"
|
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.16.14.tgz#366249a0a0fd431d3ab706195721ef1014198919"
|
||||||
|
|
Loading…
Reference in New Issue