make pretty

This commit is contained in:
caranicas 2022-09-14 14:49:23 -04:00
parent 8158ead1a2
commit c1c4a2933e
36 changed files with 3936 additions and 3307 deletions

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"@types/uuid": "^8.3.4", "@types/uuid": "^8.3.4",
"@vitejs/plugin-react": "^2.0.1", "@vitejs/plugin-react": "^2.0.1",
"prettier": "^2.7.1",
"typescript": "^4.6.4", "typescript": "^4.6.4",
"vite": "^3.0.7" "vite": "^3.0.7"
} }
@ -1326,6 +1327,21 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/react": { "node_modules/react": {
"version": "18.2.0", "version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
@ -2418,6 +2434,12 @@
"source-map-js": "^1.0.2" "source-map-js": "^1.0.2"
} }
}, },
"prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true
},
"react": { "react": {
"version": "18.2.0", "version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",

View File

@ -4,6 +4,7 @@
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"pretty": "prettier --write .",
"dev": "vite", "dev": "vite",
"build": "tsc && vite build --emptyOutDir", "build": "tsc && vite build --emptyOutDir",
"preview": "vite preview" "preview": "vite preview"
@ -22,6 +23,7 @@
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"@types/uuid": "^8.3.4", "@types/uuid": "^8.3.4",
"@vitejs/plugin-react": "^2.0.1", "@vitejs/plugin-react": "^2.0.1",
"prettier": "^2.7.1",
"typescript": "^4.6.4", "typescript": "^4.6.4",
"vite": "^3.0.7" "vite": "^3.0.7"
} }

View File

@ -62,14 +62,7 @@
], ],
[ [
"Pen", "Pen",
[ ["Chalk", "Colored Pencil", "Graphite", "Ink", "Oil Paint", "Pastel Art"]
"Chalk",
"Colored Pencil",
"Graphite",
"Ink",
"Oil Paint",
"Pastel Art"
]
], ],
[ [
"Carving and Etching", "Carving and Etching",

View File

@ -7,7 +7,8 @@
background-color: rgb(32, 33, 36); background-color: rgb(32, 33, 36);
grid-template-columns: 360px 1fr; grid-template-columns: 360px 1fr;
grid-template-rows: 100px 1fr 300px; grid-template-rows: 100px 1fr 300px;
grid-template-areas: "header header header" grid-template-areas:
"header header header"
"create display display" "create display display"
"footer footer footer"; "footer footer footer";
} }
@ -17,7 +18,8 @@
.App { .App {
grid-template-columns: 1fr; grid-template-columns: 1fr;
grid-template-rows: 100px 1fr 1fr 300px; grid-template-rows: 100px 1fr 1fr 300px;
grid-template-areas: "header" grid-template-areas:
"header"
"create" "create"
"display" "display"
"footer"; "footer";
@ -38,11 +40,11 @@
.footer-layout { .footer-layout {
grid-area: footer; grid-area: footer;
} }
/* Copypasta from Bootstrap, makes content visually hidden but still accessible for screenreaders */ /* Copypasta from Bootstrap, makes content visually hidden but still accessible for screenreaders */
.visually-hidden, .visually-hidden-focusable:not(:focus):not(:focus-within) { .visually-hidden,
.visually-hidden-focusable:not(:focus):not(:focus-within) {
position: absolute !important; position: absolute !important;
width: 1px !important; width: 1px !important;
height: 1px !important; height: 1px !important;

View File

@ -1,30 +1,26 @@
import React, {useEffect, useState} from 'react' import React, { useEffect, useState } from "react";
import './App.css' import "./App.css";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { getSaveDirectory } from './api' import { getSaveDirectory } from "./api";
import { useImageCreate } from "./store/imageCreateStore"; import { useImageCreate } from "./store/imageCreateStore";
// Todo - import components here // Todo - import components here
import HeaderDisplay from './components/headerDisplay'; import HeaderDisplay from "./components/headerDisplay";
import CreationPanel from './components/creationPanel'; import CreationPanel from "./components/creationPanel";
import DisplayPanel from './components/displayPanel'; import DisplayPanel from "./components/displayPanel";
import FooterDisplay from './components/footerDisplay'; import FooterDisplay from "./components/footerDisplay";
function App() { function App() {
// Get the original save directory // Get the original save directory
const setRequestOption = useImageCreate((state) => state.setRequestOptions); const setRequestOption = useImageCreate((state) => state.setRequestOptions);
const { status, data } = useQuery( const { status, data } = useQuery(["SaveDir"], getSaveDirectory);
['SaveDir'], getSaveDirectory,
);
useEffect(() => { useEffect(() => {
if(status === 'success') { if (status === "success") {
setRequestOption("save_to_disk_path", data); setRequestOption("save_to_disk_path", data);
} }
}, [setRequestOption, status, data]); }, [setRequestOption, status, data]);
return ( return (
<div className="App"> <div className="App">
<header className="header-layout"> <header className="header-layout">
@ -40,7 +36,7 @@ function App() {
<FooterDisplay></FooterDisplay> <FooterDisplay></FooterDisplay>
</footer> </footer>
</div> </div>
) );
} }
export default App export default App;

View File

@ -2,21 +2,19 @@
* basic server health * basic server health
*/ */
import type {ImageRequest} from '../store/imageCreateStore'; import type { ImageRequest } from "../store/imageCreateStore";
// when we are on dev we want to specifiy 9000 as the port for the backend // when we are on dev we want to specifiy 9000 as the port for the backend
// when we are on prod we want be realtive to the current url // when we are on prod we want be realtive to the current url
const API_URL = import.meta.env.DEV ? 'http://localhost:9000' : ''; const API_URL = import.meta.env.DEV ? "http://localhost:9000" : "";
export const HEALTH_PING_INTERVAL = 5000; // 5 seconds export const HEALTH_PING_INTERVAL = 5000; // 5 seconds
export const healthPing = async () => { export const healthPing = async () => {
const pingUrl = `${API_URL}/ping`; const pingUrl = `${API_URL}/ping`;
let response = await fetch(pingUrl) let response = await fetch(pingUrl);
const data = await response.json(); const data = await response.json();
return data; return data;
} };
/** /**
* the local list of modifications * the local list of modifications
@ -25,7 +23,7 @@ export const loadModifications = async () => {
const response = await fetch(`${API_URL}/modifiers.json`); const response = await fetch(`${API_URL}/modifiers.json`);
const data = await response.json(); const data = await response.json();
return data; return data;
} };
export const getSaveDirectory = async () => { export const getSaveDirectory = async () => {
const response = await fetch(`${API_URL}/output_dir`); const response = await fetch(`${API_URL}/output_dir`);
@ -37,21 +35,18 @@ export const getSaveDirectory = async () => {
* post a new request for an image * post a new request for an image
*/ */
export const MakeImageKey = 'MakeImage'; export const MakeImageKey = "MakeImage";
export const doMakeImage = async (reqBody: ImageRequest) => { export const doMakeImage = async (reqBody: ImageRequest) => {
const { seed, num_outputs } = reqBody;
const {seed, num_outputs} = reqBody;
const res = await fetch(`${API_URL}/image`, { const res = await fetch(`${API_URL}/image`, {
method: 'POST', method: "POST",
headers: { headers: {
'Content-Type': 'application/json' "Content-Type": "application/json",
}, },
body: JSON.stringify(reqBody) body: JSON.stringify(reqBody),
}); });
const data = await res.json(); const data = await res.json();
return data; return data;
} };

View File

@ -1,4 +1,4 @@
import React, {useEffect} from "react"; import React, { useEffect } from "react";
import { useImageCreate } from "../../../store/imageCreateStore"; import { useImageCreate } from "../../../store/imageCreateStore";
import "./advancedSettings.css"; import "./advancedSettings.css";
@ -22,54 +22,78 @@ const IMAGE_DIMENSIONS = [
]; ];
function SettingsList() { function SettingsList() {
const parallelCount = useImageCreate((state) => state.parallelCount); const parallelCount = useImageCreate((state) => state.parallelCount);
const setParallelCount = useImageCreate((state) => state.setParallelCount); const setParallelCount = useImageCreate((state) => state.setParallelCount);
const setRequestOption = useImageCreate((state) => state.setRequestOptions); const setRequestOption = useImageCreate((state) => state.setRequestOptions);
const toggleUseFaceCorrection = useImageCreate(
(state) => state.toggleUseFaceCorrection
);
const isUsingFaceCorrection = useImageCreate((state) =>
state.isUsingFaceCorrection()
);
const toggleUseFaceCorrection = useImageCreate((state) => state.toggleUseFaceCorrection); const toggleUseUpscaling = useImageCreate(
const isUsingFaceCorrection = useImageCreate((state) => state.isUsingFaceCorrection()); (state) => state.toggleUseUpscaling
);
const toggleUseUpscaling = useImageCreate((state) => state.toggleUseUpscaling);
const isUsingUpscaling = useImageCreate((state) => state.isUsingUpscaling()); const isUsingUpscaling = useImageCreate((state) => state.isUsingUpscaling());
const toggleUseRandomSeed = useImageCreate(
const toggleUseRandomSeed = useImageCreate((state) => state.toggleUseRandomSeed); (state) => state.toggleUseRandomSeed
);
const isRandomSeed = useImageCreate((state) => state.isRandomSeed()); const isRandomSeed = useImageCreate((state) => state.isRandomSeed());
const toggleUseAutoSave = useImageCreate((state) => state.toggleUseAutoSave); const toggleUseAutoSave = useImageCreate((state) => state.toggleUseAutoSave);
const isUseAutoSave = useImageCreate((state) => state.isUseAutoSave()); const isUseAutoSave = useImageCreate((state) => state.isUseAutoSave());
const toggleSoundEnabled = useImageCreate((state) => state.toggleSoundEnabled); const toggleSoundEnabled = useImageCreate(
(state) => state.toggleSoundEnabled
);
const isSoundEnabled = useImageCreate((state) => state.isSoundEnabled()); const isSoundEnabled = useImageCreate((state) => state.isSoundEnabled());
const use_upscale = useImageCreate((state) => state.getValueForRequestKey(('use_upscale'))); const use_upscale = useImageCreate((state) =>
const show_only_filtered_image = useImageCreate((state) => state.getValueForRequestKey(('show_only_filtered_image'))); state.getValueForRequestKey("use_upscale")
const seed = useImageCreate((state) => state.getValueForRequestKey(('seed'))); );
const width = useImageCreate((state) => state.getValueForRequestKey(('width'))); const show_only_filtered_image = useImageCreate((state) =>
const num_outputs = useImageCreate((state) => state.getValueForRequestKey(('num_outputs'))); state.getValueForRequestKey("show_only_filtered_image")
const height = useImageCreate((state) => state.getValueForRequestKey(('height'))); );
const steps = useImageCreate((state) => state.getValueForRequestKey(('num_inference_steps'))); const seed = useImageCreate((state) => state.getValueForRequestKey("seed"));
const guidance_scale = useImageCreate((state) => state.getValueForRequestKey(('guidance_scale'))); const width = useImageCreate((state) => state.getValueForRequestKey("width"));
const prompt_strength = useImageCreate((state) => state.getValueForRequestKey(('prompt_strength'))); const num_outputs = useImageCreate((state) =>
const save_to_disk_path = useImageCreate((state) => state.getValueForRequestKey(('save_to_disk_path'))); state.getValueForRequestKey("num_outputs")
const turbo = useImageCreate((state) => state.getValueForRequestKey(('turbo'))); );
const use_cpu = useImageCreate((state) => state.getValueForRequestKey(('use_cpu'))); const height = useImageCreate((state) =>
const use_full_precision = useImageCreate((state) => state.getValueForRequestKey(('use_full_precision'))); state.getValueForRequestKey("height")
);
const steps = useImageCreate((state) =>
state.getValueForRequestKey("num_inference_steps")
);
const guidance_scale = useImageCreate((state) =>
state.getValueForRequestKey("guidance_scale")
);
const prompt_strength = useImageCreate((state) =>
state.getValueForRequestKey("prompt_strength")
);
const save_to_disk_path = useImageCreate((state) =>
state.getValueForRequestKey("save_to_disk_path")
);
const turbo = useImageCreate((state) => state.getValueForRequestKey("turbo"));
const use_cpu = useImageCreate((state) =>
state.getValueForRequestKey("use_cpu")
);
const use_full_precision = useImageCreate((state) =>
state.getValueForRequestKey("use_full_precision")
);
return ( return (
<ul id="editor-settings-entries"> <ul id="editor-settings-entries">
{/*IMAGE CORRECTION */} {/*IMAGE CORRECTION */}
<li> <li>
<label> <label>
<input <input
type="checkbox" type="checkbox"
checked={isUsingFaceCorrection} checked={isUsingFaceCorrection}
onChange={(e) => onChange={(e) => toggleUseFaceCorrection()}
toggleUseFaceCorrection()
}
/> />
Fix incorrect faces and eyes (uses GFPGAN) Fix incorrect faces and eyes (uses GFPGAN)
</label> </label>
@ -79,14 +103,19 @@ function SettingsList() {
<input <input
type="checkbox" type="checkbox"
checked={isUsingUpscaling} checked={isUsingUpscaling}
onChange={(e) => onChange={(e) => toggleUseUpscaling()}
toggleUseUpscaling()
}
/> />
Upscale the image to 4x resolution using Upscale the image to 4x resolution using
<select id="upscale_model" name="upscale_model" disabled={!isUsingUpscaling} value={use_upscale}> <select
id="upscale_model"
name="upscale_model"
disabled={!isUsingUpscaling}
value={use_upscale}
>
<option value="RealESRGAN_x4plus">RealESRGAN_x4plus</option> <option value="RealESRGAN_x4plus">RealESRGAN_x4plus</option>
<option value="RealESRGAN_x4plus_anime_6B">RealESRGAN_x4plus_anime_6B</option> <option value="RealESRGAN_x4plus_anime_6B">
RealESRGAN_x4plus_anime_6B
</option>
</select> </select>
</label> </label>
</li> </li>
@ -100,7 +129,6 @@ function SettingsList() {
} }
/> />
Show only filtered image Show only filtered image
</label> </label>
</li> </li>
{/* SEED */} {/* SEED */}
@ -110,9 +138,7 @@ function SettingsList() {
<input <input
size={10} size={10}
value={seed} value={seed}
onChange={(e) => onChange={(e) => setRequestOption("seed", e.target.value)}
setRequestOption("seed", e.target.value)
}
disabled={isRandomSeed} disabled={isRandomSeed}
placeholder="random" placeholder="random"
/> />
@ -121,9 +147,7 @@ function SettingsList() {
<input <input
type="checkbox" type="checkbox"
checked={isRandomSeed} checked={isRandomSeed}
onChange={(e) => onChange={(e) => toggleUseRandomSeed()}
toggleUseRandomSeed()
}
/>{" "} />{" "}
Random Image Random Image
</label> </label>
@ -146,9 +170,7 @@ function SettingsList() {
<input <input
type="number" type="number"
value={parallelCount} value={parallelCount}
onChange={(e) => onChange={(e) => setParallelCount(parseInt(e.target.value, 10))}
setParallelCount(parseInt(e.target.value, 10))
}
size={4} size={4}
/> />
</label> </label>
@ -159,9 +181,7 @@ function SettingsList() {
Width: Width:
<select <select
value={width} value={width}
onChange={(e) => onChange={(e) => setRequestOption("width", e.target.value)}
setRequestOption("width", e.target.value)
}
> >
{IMAGE_DIMENSIONS.map((dimension) => ( {IMAGE_DIMENSIONS.map((dimension) => (
<option <option
@ -179,9 +199,7 @@ function SettingsList() {
Height: Height:
<select <select
value={height} value={height}
onChange={(e) => onChange={(e) => setRequestOption("height", e.target.value)}
setRequestOption("height", e.target.value)
}
> >
{IMAGE_DIMENSIONS.map((dimension) => ( {IMAGE_DIMENSIONS.map((dimension) => (
<option <option
@ -201,7 +219,7 @@ function SettingsList() {
<input <input
value={steps} value={steps}
onChange={(e) => { onChange={(e) => {
setRequestOption("num_inference_steps", e.target.value) setRequestOption("num_inference_steps", e.target.value);
}} }}
size={4} size={4}
/> />
@ -213,9 +231,7 @@ function SettingsList() {
Guidance Scale: Guidance Scale:
<input <input
value={guidance_scale} value={guidance_scale}
onChange={(e) => onChange={(e) => setRequestOption("guidance_scale", e.target.value)}
setRequestOption("guidance_scale", e.target.value)
}
type="range" type="range"
min="0" min="0"
max="20" max="20"
@ -247,9 +263,7 @@ function SettingsList() {
<label> <label>
<input <input
checked={isUseAutoSave} checked={isUseAutoSave}
onChange={(e) => onChange={(e) => toggleUseAutoSave()}
toggleUseAutoSave()
}
type="checkbox" type="checkbox"
/> />
Automatically save to{" "} Automatically save to{" "}
@ -273,9 +287,7 @@ function SettingsList() {
<label> <label>
<input <input
checked={isSoundEnabled} checked={isSoundEnabled}
onChange={(e) => onChange={(e) => toggleSoundEnabled()}
toggleSoundEnabled()
}
type="checkbox" type="checkbox"
/> />
Play sound on task completion Play sound on task completion
@ -286,13 +298,11 @@ function SettingsList() {
<label> <label>
<input <input
checked={turbo} checked={turbo}
onChange={(e) => onChange={(e) => setRequestOption("turbo", e.target.checked)}
setRequestOption("turbo", e.target.checked)
}
type="checkbox" type="checkbox"
/> />
Turbo mode (generates images faster, but uses an additional 1 GB Turbo mode (generates images faster, but uses an additional 1 GB of
of GPU memory) GPU memory)
</label> </label>
</li> </li>
<li> <li>
@ -300,9 +310,7 @@ function SettingsList() {
<input <input
type="checkbox" type="checkbox"
checked={use_cpu} checked={use_cpu}
onChange={(e) => onChange={(e) => setRequestOption("use_cpu", e.target.checked)}
setRequestOption("use_cpu", e.target.checked)
}
/> />
Use CPU instead of GPU (warning: this will be *very* slow) Use CPU instead of GPU (warning: this will be *very* slow)
</label> </label>
@ -320,15 +328,13 @@ function SettingsList() {
VRAM) VRAM)
</label> </label>
</li> </li>
</ul> </ul>
) );
} }
// {/* <!-- <li><input id="allow_nsfw" name="allow_nsfw" type="checkbox"/> <label htmlFor="allow_nsfw">Allow NSFW Content (You confirm you are above 18 years of age)</label></li> --> */} // {/* <!-- <li><input id="allow_nsfw" name="allow_nsfw" type="checkbox"/> <label htmlFor="allow_nsfw">Allow NSFW Content (You confirm you are above 18 years of age)</label></li> --> */}
export default function AdvancedSettings() { export default function AdvancedSettings() {
const advancedSettingsIsOpen = useImageCreate( const advancedSettingsIsOpen = useImageCreate(
(state) => state.uiOptions.advancedSettingsIsOpen (state) => state.uiOptions.advancedSettingsIsOpen
); );
@ -346,7 +352,7 @@ export default function AdvancedSettings() {
> >
<h4>Advanced Settings</h4> <h4>Advanced Settings</h4>
</button> </button>
{advancedSettingsIsOpen && <SettingsList/>} {advancedSettingsIsOpen && <SettingsList />}
</div> </div>
); );
} }

View File

@ -23,7 +23,7 @@ li {
list-style: none; list-style: none;
} }
.modifier-list{ .modifier-list {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
margin: 0; margin: 0;

View File

@ -1,4 +1,4 @@
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { loadModifications } from "../../../api"; import { loadModifications } from "../../../api";
@ -7,23 +7,22 @@ import { useImageCreate } from "../../../store/imageCreateStore";
import ModifierTag from "../modierTag"; import ModifierTag from "../modierTag";
type ModifierListProps = { type ModifierListProps = {
tags: string[]; tags: string[];
} };
function ModifierList({tags}: ModifierListProps) { function ModifierList({ tags }: ModifierListProps) {
// const setImageOptions = useImageCreate((state) => state.setImageOptions); // const setImageOptions = useImageCreate((state) => state.setImageOptions);
// const imageOptions = useImageCreate((state) => state.imageOptions); // const imageOptions = useImageCreate((state) => state.imageOptions);
return( return (
<ul className="modifier-list"> <ul className="modifier-list">
{tags.map((tag) => ( {tags.map((tag) => (
<li key={tag} > <li key={tag}>
<ModifierTag name={tag} /> <ModifierTag name={tag} />
</li> </li>
))} ))}
</ul> </ul>
) );
} }
type ModifierGroupingProps = { type ModifierGroupingProps = {
@ -31,13 +30,11 @@ type ModifierGroupingProps = {
tags: string[]; tags: string[];
}; };
function ModifierGrouping({title, tags}: ModifierGroupingProps) { function ModifierGrouping({ title, tags }: ModifierGroupingProps) {
// doing this localy for now, but could move to a store // doing this localy for now, but could move to a store
// and persist if we wanted to // and persist if we wanted to
const [isExpanded, setIsExpanded] = useState(false); const [isExpanded, setIsExpanded] = useState(false);
const _toggleExpand = () => { const _toggleExpand = () => {
setIsExpanded(!isExpanded); setIsExpanded(!isExpanded);
}; };
@ -53,7 +50,7 @@ function ModifierGrouping({title, tags}: ModifierGroupingProps) {
} }
export default function ImageModifers() { export default function ImageModifers() {
const {status, data} = useQuery(["modifications"], loadModifications); const { status, data } = useQuery(["modifications"], loadModifications);
const imageModifierIsOpen = useImageCreate( const imageModifierIsOpen = useImageCreate(
(state) => state.uiOptions.imageModifierIsOpen (state) => state.uiOptions.imageModifierIsOpen
@ -62,7 +59,6 @@ export default function ImageModifers() {
(state) => state.toggleImageModifiersIsOpen (state) => state.toggleImageModifiersIsOpen
); );
const handleClick = () => { const handleClick = () => {
toggleImageModifiersIsOpen(); toggleImageModifiersIsOpen();
}; };
@ -79,10 +75,12 @@ export default function ImageModifers() {
</button> </button>
{/* @ts-ignore */} {/* @ts-ignore */}
{imageModifierIsOpen && data.map((item, index) => { {imageModifierIsOpen &&
// @ts-ignore
data.map((item, index) => {
return ( return (
<ModifierGrouping key={item[0]} title={item[0]} tags={item[1]}/> <ModifierGrouping key={item[0]} title={item[0]} tags={item[1]} />
) );
})} })}
</div> </div>
); );

View File

@ -8,12 +8,15 @@ import ModifierTag from "./modierTag";
import { useImageCreate } from "../../store/imageCreateStore"; import { useImageCreate } from "../../store/imageCreateStore";
import './creationPanel.css'; import "./creationPanel.css";
export default function CreationPanel() { export default function CreationPanel() {
const promptText = useImageCreate((state) =>
const promptText = useImageCreate((state) => state.getValueForRequestKey("prompt")); state.getValueForRequestKey("prompt")
const init_image = useImageCreate((state) => state.getValueForRequestKey("init_image")); );
const init_image = useImageCreate((state) =>
state.getValueForRequestKey("init_image")
);
const setRequestOption = useImageCreate((state) => state.setRequestOptions); const setRequestOption = useImageCreate((state) => state.setRequestOptions);
const selectedtags = useImageCreate((state) => state.selectedTags()); const selectedtags = useImageCreate((state) => state.selectedTags());
@ -49,15 +52,29 @@ export default function CreationPanel() {
<input type="file" accept="image/*" /> <input type="file" accept="image/*" />
</div> */} </div> */}
<div id="editor-inputs-init-image" className="row"> <div id="editor-inputs-init-image" className="row">
<label ><b>Initial Image:</b> (optional) </label> <label>
<input id="init_image" name="init_image" type="file" onChange={_handleFileSelect}/><br/> <b>Initial Image:</b> (optional){" "}
</label>
<input
id="init_image"
name="init_image"
type="file"
onChange={_handleFileSelect}
/>
<br />
<div id="init_image_preview" className="image_preview"> <div id="init_image_preview" className="image_preview">
{ init_image && {init_image && (
<img id="init_image_preview" src={init_image} width="100" height="100" /> <img
} id="init_image_preview"
<button id="init_image_clear" className="image_clear_btn">X</button> src={init_image}
width="100"
height="100"
/>
)}
<button id="init_image_clear" className="image_clear_btn">
X
</button>
</div> </div>
</div> </div>

View File

@ -1,19 +1,17 @@
import React, {useEffect, useState}from "react"; import React, { useEffect, useState } from "react";
import { useImageCreate } from "../../../store/imageCreateStore"; import { useImageCreate } from "../../../store/imageCreateStore";
import { useImageQueue } from "../../../store/imageQueueStore"; import { useImageQueue } from "../../../store/imageQueueStore";
import {v4 as uuidv4} from 'uuid'; import { v4 as uuidv4 } from "uuid";
import { useRandomSeed } from "../../../utils"; import { useRandomSeed } from "../../../utils";
export default function MakeButton() { export default function MakeButton() {
const parallelCount = useImageCreate((state) => state.parallelCount); const parallelCount = useImageCreate((state) => state.parallelCount);
const builtRequest = useImageCreate((state) => state.builtRequest); const builtRequest = useImageCreate((state) => state.builtRequest);
const addNewImage = useImageQueue((state) => state.addNewImage); const addNewImage = useImageQueue((state) => state.addNewImage);
const makeImages = () => { const makeImages = () => {
// the request that we have built // the request that we have built
const req = builtRequest(); const req = builtRequest();
// the actual number of request we will make // the actual number of request we will make
@ -23,33 +21,30 @@ export default function MakeButton() {
// if making fewer images than the parallel count // if making fewer images than the parallel count
// then it is only 1 request // then it is only 1 request
if( parallelCount > num_outputs ) { if (parallelCount > num_outputs) {
requests.push(num_outputs); requests.push(num_outputs);
} } else {
else {
// while we have at least 1 image to make // while we have at least 1 image to make
while (num_outputs >= 1) { while (num_outputs >= 1) {
// subtract the parallel count from the number of images to make // subtract the parallel count from the number of images to make
num_outputs -= parallelCount; num_outputs -= parallelCount;
// if we are still 0 or greater we can make the full parallel count // if we are still 0 or greater we can make the full parallel count
if(num_outputs <= 0) { if (num_outputs <= 0) {
requests.push(parallelCount) requests.push(parallelCount);
} }
// otherwise we can only make the remaining images // otherwise we can only make the remaining images
else { else {
requests.push(Math.abs(num_outputs)) requests.push(Math.abs(num_outputs));
} }
} }
} }
// make the requests // make the requests
requests.forEach((num, index) => { requests.forEach((num, index) => {
// get the seed we want to use // get the seed we want to use
let seed = req.seed; let seed = req.seed;
if(index !== 0) { if (index !== 0) {
// we want to use a random seed for subsequent requests // we want to use a random seed for subsequent requests
seed = useRandomSeed(); seed = useRandomSeed();
} }
@ -59,13 +54,10 @@ export default function MakeButton() {
// updated the number of images to make // updated the number of images to make
num_outputs: num, num_outputs: num,
// update the seed // update the seed
seed: seed seed: seed,
}) });
}); });
}; };
return ( return <button onClick={makeImages}>Make</button>;
<button onClick={makeImages}>Make</button>
);
} }

View File

@ -1,17 +1,16 @@
import React from "react"; import React from "react";
import { useImageCreate } from "../../../store/imageCreateStore"; import { useImageCreate } from "../../../store/imageCreateStore";
type ModifierTagProps = { type ModifierTagProps = {
name: string; name: string;
} };
export default function ModifierTag({name}: ModifierTagProps) { export default function ModifierTag({ name }: ModifierTagProps) {
const hasTag = useImageCreate((state) => state.hasTag(name))
const hasTag = useImageCreate((state) => state.hasTag(name)) ? "selected" : ""; ? "selected"
: "";
const toggleTag = useImageCreate((state) => state.toggleTag); const toggleTag = useImageCreate((state) => state.toggleTag);
const _toggleTag = () => { const _toggleTag = () => {
toggleTag(name); toggleTag(name);
}; };

View File

@ -15,4 +15,4 @@ export const CompletedImages = () => {
// </div> // </div>
// </div> // </div>
// ); // );
} };

View File

@ -8,10 +8,9 @@ import GeneratedImage from "../generatedImage";
// TODO move this logic to the display panel // TODO move this logic to the display panel
export default function CurrentImage() { export default function CurrentImage() {
const [imageData, setImageData] = useState(null); const [imageData, setImageData] = useState(null);
// @ts-ignore // @ts-ignore
const {id, options} = useImageQueue((state) => state.firstInQueue()); const { id, options } = useImageQueue((state) => state.firstInQueue());
const removeFirstInQueue = useImageQueue((state) => state.removeFirstInQueue); const removeFirstInQueue = useImageQueue((state) => state.removeFirstInQueue);
@ -25,19 +24,15 @@ export default function CurrentImage() {
useEffect(() => { useEffect(() => {
// query is done // query is done
if(status === 'success') { if (status === "success") {
// check to make sure that the image was created // check to make sure that the image was created
if(data.status === 'succeeded') { if (data.status === "succeeded") {
setImageData(data.output[0].data); setImageData(data.output[0].data);
removeFirstInQueue(); removeFirstInQueue();
} }
} }
}, [status, data, removeFirstInQueue]); }, [status, data, removeFirstInQueue]);
return ( return (
<></> <></>
// <div className="current-display"> // <div className="current-display">
@ -45,4 +40,4 @@ export default function CurrentImage() {
// {imageData && <GeneratedImage imageData={imageData} />} // {imageData && <GeneratedImage imageData={imageData} />}
// </div> // </div>
); );
}; }

View File

@ -1,20 +1,19 @@
import React, {useCallback} from "react"; import React, { useCallback } from "react";
import { ImageRequest, useImageCreate } from "../../../store/imageCreateStore"; import { ImageRequest, useImageCreate } from "../../../store/imageCreateStore";
type GeneretaedImageProps = { type GeneretaedImageProps = {
imageData: string; imageData: string;
metadata: ImageRequest; metadata: ImageRequest;
} };
export default function GeneratedImage({ imageData, metadata}: GeneretaedImageProps) {
export default function GeneratedImage({
imageData,
metadata,
}: GeneretaedImageProps) {
const setRequestOption = useImageCreate((state) => state.setRequestOptions); const setRequestOption = useImageCreate((state) => state.setRequestOptions);
const createFileName = () => { const createFileName = () => {
const { const {
prompt, prompt,
seed, seed,
@ -27,17 +26,17 @@ export default function GeneratedImage({ imageData, metadata}: GeneretaedImagePr
} = metadata; } = metadata;
//Most important information is the prompt //Most important information is the prompt
let underscoreName = prompt.replace(/[^a-zA-Z0-9]/g, '_') let underscoreName = prompt.replace(/[^a-zA-Z0-9]/g, "_");
underscoreName = underscoreName.substring(0, 100) underscoreName = underscoreName.substring(0, 100);
// name and the top level metadata // name and the top level metadata
let fileName = `${underscoreName}_Seed-${seed}_Steps-${num_inference_steps}_Guidance-${guidance_scale}`; let fileName = `${underscoreName}_Seed-${seed}_Steps-${num_inference_steps}_Guidance-${guidance_scale}`;
// Add the face correction and upscale // Add the face correction and upscale
if(use_face_correction) { if (use_face_correction) {
fileName += `_FaceCorrection-${use_face_correction}`; fileName += `_FaceCorrection-${use_face_correction}`;
} }
if(use_upscale) { if (use_upscale) {
fileName += `_Upscale-${use_upscale}`; fileName += `_Upscale-${use_upscale}`;
} }
@ -45,11 +44,11 @@ export default function GeneratedImage({ imageData, metadata}: GeneretaedImagePr
fileName += `_${width}x${height}`; fileName += `_${width}x${height}`;
// add the file extension // add the file extension
fileName += `.png` fileName += `.png`;
// return fileName // return fileName
return fileName; return fileName;
} };
const _handleSave = () => { const _handleSave = () => {
const link = document.createElement("a"); const link = document.createElement("a");
@ -61,12 +60,10 @@ export default function GeneratedImage({ imageData, metadata}: GeneretaedImagePr
const _handleUseAsInput = () => { const _handleUseAsInput = () => {
console.log(" TODO : use as input"); console.log(" TODO : use as input");
setRequestOption("init_image", imageData); setRequestOption("init_image", imageData);
// initImageSelector.value = null // initImageSelector.value = null
// initImagePreview.src = imgBody // initImagePreview.src = imgBody
// imgUseBtn.addEventListener('click', function() { // imgUseBtn.addEventListener('click', function() {
// initImageSelector.value = null // initImageSelector.value = null
// initImagePreview.src = imgBody // initImagePreview.src = imgBody
@ -80,18 +77,14 @@ export default function GeneratedImage({ imageData, metadata}: GeneretaedImagePr
// seedField.value = seed // seedField.value = seed
// seedField.disabled = false // seedField.disabled = false
// }) // })
} };
return ( return (
<div className="generated-image"> <div className="generated-image">
<p>Your image</p> <p>Your image</p>
<img src={imageData} alt="generated" /> <img src={imageData} alt="generated" />
<button onClick={_handleSave}> <button onClick={_handleSave}>Save</button>
Save <button onClick={_handleUseAsInput}>Use as Input</button>
</button>
<button onClick={_handleUseAsInput}>
Use as Input
</button>
</div> </div>
); );
} }

View File

@ -1,10 +1,9 @@
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
import { useImageQueue } from "../../store/imageQueueStore"; import { useImageQueue } from "../../store/imageQueueStore";
import { ImageRequest } from '../../store/imageCreateStore'; import { ImageRequest } from "../../store/imageCreateStore";
import { useQueryClient } from '@tanstack/react-query'
import { useQueryClient } from "@tanstack/react-query";
import { MakeImageKey } from "../../api"; import { MakeImageKey } from "../../api";
@ -12,47 +11,50 @@ import CurrentImage from "./currentImage";
import GeneratedImage from "./generatedImage"; import GeneratedImage from "./generatedImage";
type CompletedImagesType = { type CompletedImagesType = {
id: string; id: string;
data: string; data: string;
info: ImageRequest; info: ImageRequest;
} };
export default function DisplayPanel() { export default function DisplayPanel() {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [completedImages, setCompletedImages] = useState<CompletedImagesType[]>([]); const [completedImages, setCompletedImages] = useState<CompletedImagesType[]>(
[]
);
const completedIds = useImageQueue((state) => state.completedImageIds); const completedIds = useImageQueue((state) => state.completedImageIds);
useEffect(() => { useEffect(() => {
const testReq = {} as ImageRequest; const testReq = {} as ImageRequest;
const completedQueries = completedIds.map((id) => { const completedQueries = completedIds.map((id) => {
const imageData = queryClient.getQueryData([MakeImageKey,id]) const imageData = queryClient.getQueryData([MakeImageKey, id]);
return imageData; return imageData;
}); });
if (completedQueries.length > 0) { if (completedQueries.length > 0) {
// map the completedImagesto a new array // map the completedImagesto a new array
// and then set the state // and then set the state
const temp = completedQueries.map((query, index ) => { const temp = completedQueries
if(void 0 !== query) { .map((query, index) => {
if (void 0 !== query) {
//@ts-ignore //@ts-ignore
return query.output.map((data)=>{ return query.output.map((data) => {
// @ts-ignore // @ts-ignore
return {id: `${completedIds[index]}-${data.seed}`, data: data.data, info: {...query.request, seed:data.seed } } return {
id: `${completedIds[index]}-${data.seed}`,
data: data.data,
//@ts-ignore
info: { ...query.request, seed: data.seed },
};
});
}
}) })
} .flat()
.reverse();
}).flat().reverse();
setCompletedImages(temp); setCompletedImages(temp);
} } else {
else {
setCompletedImages([]); setCompletedImages([]);
} }
}, [setCompletedImages, queryClient, completedIds]);
},[setCompletedImages, queryClient, completedIds]);
return ( return (
<div className="display-panel"> <div className="display-panel">
@ -63,16 +65,20 @@ export default function DisplayPanel() {
// if(index == 0){ // if(index == 0){
// return null; // return null;
// } // }
if(void 0 !== image) { if (void 0 !== image) {
return <GeneratedImage key={image.id} imageData={image.data} metadata={image.info}/>; return (
} <GeneratedImage
else { key={image.id}
console.warn('image is undefined', image, index); imageData={image.data}
metadata={image.info}
/>
);
} else {
console.warn("image is undefined", image, index);
return null; return null;
} }
})} })}
</div> </div>
</div> </div>
); );
}; }

View File

@ -4,5 +4,4 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }

View File

@ -1,18 +1,56 @@
import React from "react"; import React from "react";
import './footerDisplay.css'; import "./footerDisplay.css";
export default function FooterDisplay() { export default function FooterDisplay() {
return ( return (
<div id="footer" className="panel-box"> <div id="footer" className="panel-box">
<p>If you found this project useful and want to help keep it alive, please <a href="https://ko-fi.com/cmdr2_stablediffusion_ui" target="_blank"><img src="./kofi.png" id="coffeeButton"/></a> to help cover the cost of development and maintenance! Thank you for your support!</p> <p>
<p>Please feel free to join the <a href="https://discord.com/invite/u9yhsFmEkB" target="_blank">discord community</a> or <a href="https://github.com/cmdr2/stable-diffusion-ui/issues" target="_blank">file an issue</a> if you have any problems or suggestions in using this interface.</p> If you found this project useful and want to help keep it alive, please{" "}
<a href="https://ko-fi.com/cmdr2_stablediffusion_ui" target="_blank">
<img src="./kofi.png" id="coffeeButton" />
</a>{" "}
to help cover the cost of development and maintenance! Thank you for
your support!
</p>
<p>
Please feel free to join the{" "}
<a href="https://discord.com/invite/u9yhsFmEkB" target="_blank">
discord community
</a>{" "}
or{" "}
<a
href="https://github.com/cmdr2/stable-diffusion-ui/issues"
target="_blank"
>
file an issue
</a>{" "}
if you have any problems or suggestions in using this interface.
</p>
<div id="footer-legal"> <div id="footer-legal">
<p><b>Disclaimer:</b> The authors of this project are not responsible for any content generated using this interface.</p> <p>
<p>This license of this software forbids you from sharing any content that violates any laws, produce any harm to a person, disseminate any personal information that would be meant for harm, <br/>spread misinformation and target vulnerable groups. For the full list of restrictions please read <a href="https://github.com/cmdr2/stable-diffusion-ui/blob/main/LICENSE" target="_blank">the license</a>.</p> <b>Disclaimer:</b> The authors of this project are not responsible for
<p>By using this software, you consent to the terms and conditions of the license.</p> any content generated using this interface.
</p>
<p>
This license of this software forbids you from sharing any content
that violates any laws, produce any harm to a person, disseminate any
personal information that would be meant for harm, <br />
spread misinformation and target vulnerable groups. For the full list
of restrictions please read{" "}
<a
href="https://github.com/cmdr2/stable-diffusion-ui/blob/main/LICENSE"
target="_blank"
>
the license
</a>
.
</p>
<p>
By using this software, you consent to the terms and conditions of the
license.
</p>
</div> </div>
</div> </div>
); );
} }

View File

@ -2,7 +2,7 @@ import React from "react";
import StatusDisplay from "./statusDisplay"; import StatusDisplay from "./statusDisplay";
import './headerDisplay.css'; import "./headerDisplay.css";
export default function HeaderDisplay() { export default function HeaderDisplay() {
return ( return (
@ -11,4 +11,4 @@ export default function HeaderDisplay() {
<StatusDisplay className="status-display"></StatusDisplay> <StatusDisplay className="status-display"></StatusDisplay>
</div> </div>
); );
}; }

View File

@ -1,45 +1,37 @@
import React, {useEffect, useState} from 'react' import React, { useEffect, useState } from "react";
import { useQuery } from '@tanstack/react-query'; import { useQuery } from "@tanstack/react-query";
import { healthPing, HEALTH_PING_INTERVAL } from '../../../api'; import { healthPing, HEALTH_PING_INTERVAL } from "../../../api";
const startingMessage = 'Stable Diffusion is starting...'; const startingMessage = "Stable Diffusion is starting...";
const successMessage = 'Stable Diffusion is ready to use!'; const successMessage = "Stable Diffusion is ready to use!";
const errorMessage = 'Stable Diffusion is not running!'; const errorMessage = "Stable Diffusion is not running!";
import './statusDisplay.css'; import "./statusDisplay.css";
export default function StatusDisplay({className}: {className?: string}) {
export default function StatusDisplay({ className }: { className?: string }) {
const [statusMessage, setStatusMessage] = useState(startingMessage); const [statusMessage, setStatusMessage] = useState(startingMessage);
const [statusClass, setStatusClass] = useState('starting'); const [statusClass, setStatusClass] = useState("starting");
// but this will be moved to the status display when it is created // but this will be moved to the status display when it is created
const {status, data} = useQuery(['health'], healthPing, {refetchInterval: HEALTH_PING_INTERVAL}); const { status, data } = useQuery(["health"], healthPing, {
refetchInterval: HEALTH_PING_INTERVAL,
});
useEffect(() => { useEffect(() => {
if (status === "loading") {
if (status === 'loading') {
setStatusMessage(startingMessage); setStatusMessage(startingMessage);
setStatusClass('starting'); setStatusClass("starting");
} } else if (status === "error") {
else if (status === 'error') {
setStatusMessage(errorMessage); setStatusMessage(errorMessage);
setStatusClass('error'); setStatusClass("error");
} } else if (status === "success") {
if (data[0] === "OK") {
else if (status === 'success') {
if(data[0] === 'OK') {
setStatusMessage(successMessage); setStatusMessage(successMessage);
setStatusClass('success'); setStatusClass("success");
} } else {
else {
setStatusMessage(errorMessage); setStatusMessage(errorMessage);
setStatusClass('error'); setStatusClass("error");
} }
} }
}, [status, data]); }, [status, data]);
@ -47,7 +39,7 @@ export default function StatusDisplay({className}: {className?: string}) {
return ( return (
<> <>
{/* alittle hacky but joins the class names, will probably need a better css in js solution or tailwinds*/} {/* alittle hacky but joins the class names, will probably need a better css in js solution or tailwinds*/}
<p className={[statusClass, className].join(' ')}>{statusMessage}</p> <p className={[statusClass, className].join(" ")}>{statusMessage}</p>
</> </>
); );
}; }

View File

@ -1,37 +1,32 @@
import React from 'react' import React from "react";
import ReactDOM from 'react-dom/client' import ReactDOM from "react-dom/client";
import { import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { enableMapSet } from 'immer'; import { enableMapSet } from "immer";
import App from './App' import App from "./App";
import './index.css' import "./index.css";
const queryClient = new QueryClient( const queryClient = new QueryClient({
{
defaultOptions: { defaultOptions: {
queries: { queries: {
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
refetchOnReconnect : false, refetchOnReconnect: false,
refetchOnMount : false, refetchOnMount: false,
staleTime: Infinity, staleTime: Infinity,
}, },
}, },
} });
);
enableMapSet(); enableMapSet();
// application entry point // application entry point
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode> <React.StrictMode>
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<App /> <App />
<ReactQueryDevtools initialIsOpen={true} /> <ReactQueryDevtools initialIsOpen={true} />
</QueryClientProvider> </QueryClientProvider>
</React.StrictMode> </React.StrictMode>
) );

View File

@ -43,14 +43,7 @@
], ],
[ [
"Pen", "Pen",
[ ["Chalk", "Colored Pencil", "Graphite", "Ink", "Oil Paint", "Pastel Art"]
"Chalk",
"Colored Pencil",
"Graphite",
"Ink",
"Oil Paint",
"Pastel Art"
]
], ],
[ [
"Carving and Etching", "Carving and Etching",

View File

@ -1,8 +1,8 @@
import create from 'zustand'; import create from "zustand";
import produce from 'immer'; import produce from "immer";
import { devtools } from 'zustand/middleware' import { devtools } from "zustand/middleware";
import { useRandomSeed } from '../utils'; import { useRandomSeed } from "../utils";
export type ImageCreationUiOptions = { export type ImageCreationUiOptions = {
advancedSettingsIsOpen: boolean; advancedSettingsIsOpen: boolean;
@ -12,27 +12,57 @@ export type ImageCreationUiOptions = {
isUseRandomSeed: boolean; isUseRandomSeed: boolean;
isUseAutoSave: boolean; isUseAutoSave: boolean;
isSoundEnabled: boolean; isSoundEnabled: boolean;
} };
export type ImageRequest = { export type ImageRequest = {
prompt: string; prompt: string;
seed: number; seed: number;
num_outputs: number; num_outputs: number;
num_inference_steps: number; num_inference_steps: number;
guidance_scale: number guidance_scale: number;
width: 128 | 192 | 256 | 320 | 384 | 448 | 512 | 576 | 640 | 704 | 768 | 832 | 896 | 960 | 1024; width:
height: 128 | 192 | 256 | 320 | 384 | 448 | 512 | 576 | 640 | 704 | 768 | 832 | 896 | 960 | 1024; | 128
| 192
| 256
| 320
| 384
| 448
| 512
| 576
| 640
| 704
| 768
| 832
| 896
| 960
| 1024;
height:
| 128
| 192
| 256
| 320
| 384
| 448
| 512
| 576
| 640
| 704
| 768
| 832
| 896
| 960
| 1024;
// allow_nsfw: boolean; // allow_nsfw: boolean;
turbo: boolean; turbo: boolean;
use_cpu: boolean; use_cpu: boolean;
use_full_precision: boolean; use_full_precision: boolean;
save_to_disk_path: null | string; save_to_disk_path: null | string;
use_face_correction: null | 'GFPGANv1.3'; use_face_correction: null | "GFPGANv1.3";
use_upscale: null| 'RealESRGAN_x4plus' | 'RealESRGAN_x4plus_anime_6B'; use_upscale: null | "RealESRGAN_x4plus" | "RealESRGAN_x4plus_anime_6B";
show_only_filtered_image: boolean; show_only_filtered_image: boolean;
init_image: undefined | string; init_image: undefined | string;
prompt_strength: undefined | number; prompt_strength: undefined | number;
}; };
interface ImageCreateState { interface ImageCreateState {
parallelCount: number; parallelCount: number;
@ -45,7 +75,7 @@ interface ImageCreateState {
toggleTag: (tag: string) => void; toggleTag: (tag: string) => void;
hasTag: (tag: string) => boolean; hasTag: (tag: string) => boolean;
selectedTags:() => string[] selectedTags: () => string[];
builtRequest: () => ImageRequest; builtRequest: () => ImageRequest;
uiOptions: ImageCreationUiOptions; uiOptions: ImageCreationUiOptions;
@ -64,13 +94,13 @@ interface ImageCreateState {
} }
// devtools breaks TS // devtools breaks TS
// @ts-ignore export const useImageCreate = create<ImageCreateState>(
export const useImageCreate = create<ImageCreateState>(devtools((set, get) => ({ // @ts-ignore
devtools((set, get) => ({
parallelCount: 1, parallelCount: 1,
requestOptions:{ requestOptions: {
prompt: 'a photograph of an astronaut riding a horse', prompt: "a photograph of an astronaut riding a horse",
seed: useRandomSeed(), seed: useRandomSeed(),
num_outputs: 1, num_outputs: 1,
num_inference_steps: 50, num_inference_steps: 50,
@ -82,22 +112,27 @@ export const useImageCreate = create<ImageCreateState>(devtools((set, get) => ({
turbo: true, turbo: true,
use_cpu: false, use_cpu: false,
use_full_precision: true, use_full_precision: true,
save_to_disk_path: 'null', save_to_disk_path: "null",
use_face_correction: null, use_face_correction: null,
use_upscale: 'RealESRGAN_x4plus', use_upscale: "RealESRGAN_x4plus",
show_only_filtered_image: false, show_only_filtered_image: false,
} as ImageRequest, } as ImageRequest,
tags: [] as string[], tags: [] as string[],
setParallelCount: (count: number) => set(produce((state) => { setParallelCount: (count: number) =>
set(
produce((state) => {
state.parallelCount = count; state.parallelCount = count;
})), })
),
setRequestOptions: (key: keyof ImageRequest, value: any) => { setRequestOptions: (key: keyof ImageRequest, value: any) => {
set( produce((state) => { set(
produce((state) => {
state.requestOptions[key] = value; state.requestOptions[key] = value;
})) })
);
}, },
getValueForRequestKey: (key: keyof ImageRequest) => { getValueForRequestKey: (key: keyof ImageRequest) => {
@ -105,17 +140,19 @@ export const useImageCreate = create<ImageCreateState>(devtools((set, get) => ({
}, },
toggleTag: (tag: string) => { toggleTag: (tag: string) => {
set( produce((state) => { set(
produce((state) => {
const index = state.tags.indexOf(tag); const index = state.tags.indexOf(tag);
if (index > -1) { if (index > -1) {
state.tags.splice(index, 1); state.tags.splice(index, 1);
} else { } else {
state.tags.push(tag); state.tags.push(tag);
} }
})) })
);
}, },
hasTag: (tag:string) => { hasTag: (tag: string) => {
return get().tags.indexOf(tag) > -1; return get().tags.indexOf(tag) > -1;
}, },
@ -126,30 +163,29 @@ export const useImageCreate = create<ImageCreateState>(devtools((set, get) => ({
// the request body to send to the server // the request body to send to the server
// this is a computed value, just adding the tags to the request // this is a computed value, just adding the tags to the request
builtRequest: () => { builtRequest: () => {
const state = get(); const state = get();
const requestOptions = state.requestOptions; const requestOptions = state.requestOptions;
const tags = state.tags; const tags = state.tags;
// join all the tags with a comma and add it to the prompt // join all the tags with a comma and add it to the prompt
const prompt = `${requestOptions.prompt} ${tags.join(',')}`; const prompt = `${requestOptions.prompt} ${tags.join(",")}`;
const request = { const request = {
...requestOptions, ...requestOptions,
prompt prompt,
} };
// if we arent using auto save clear the save path // if we arent using auto save clear the save path
if(!state.uiOptions.isUseAutoSave){ if (!state.uiOptions.isUseAutoSave) {
// maybe this is "None" ? // maybe this is "None" ?
// TODO check this // TODO check this
request.save_to_disk_path = null; request.save_to_disk_path = null;
} }
// if we arent using face correction clear the face correction // if we arent using face correction clear the face correction
if(!state.uiOptions.isCheckUseFaceCorrection){ if (!state.uiOptions.isCheckUseFaceCorrection) {
request.use_face_correction = null; request.use_face_correction = null;
} }
// if we arent using upscaling clear the upscaling // if we arent using upscaling clear the upscaling
if(!state.uiOptions.isCheckedUseUpscaling){ if (!state.uiOptions.isCheckedUseUpscaling) {
request.use_upscale = null; request.use_upscale = null;
} }
@ -159,7 +195,7 @@ export const useImageCreate = create<ImageCreateState>(devtools((set, get) => ({
uiOptions: { uiOptions: {
// TODO proper persistence of all UI / user settings centrally somewhere? // TODO proper persistence of all UI / user settings centrally somewhere?
// localStorage.getItem('ui:advancedSettingsIsOpen') === 'true', // localStorage.getItem('ui:advancedSettingsIsOpen') === 'true',
advancedSettingsIsOpen:false, advancedSettingsIsOpen: false,
imageModifierIsOpen: false, imageModifierIsOpen: false,
isCheckedUseUpscaling: false, isCheckedUseUpscaling: false,
isCheckUseFaceCorrection: true, isCheckUseFaceCorrection: true,
@ -169,25 +205,46 @@ export const useImageCreate = create<ImageCreateState>(devtools((set, get) => ({
}, },
toggleAdvancedSettingsIsOpen: () => { toggleAdvancedSettingsIsOpen: () => {
set( produce((state) => { set(
state.uiOptions.advancedSettingsIsOpen = !state.uiOptions.advancedSettingsIsOpen; produce((state) => {
localStorage.setItem('ui:advancedSettingsIsOpen', state.uiOptions.advancedSettingsIsOpen); state.uiOptions.advancedSettingsIsOpen =
})) !state.uiOptions.advancedSettingsIsOpen;
localStorage.setItem(
"ui:advancedSettingsIsOpen",
state.uiOptions.advancedSettingsIsOpen
);
})
);
}, },
toggleImageModifiersIsOpen: () => { toggleImageModifiersIsOpen: () => {
set( produce((state) => { set(
state.uiOptions.imageModifierIsOpen = !state.uiOptions.imageModifierIsOpen; produce((state) => {
localStorage.setItem('ui:imageModifierIsOpen', state.uiOptions.imageModifierIsOpen); state.uiOptions.imageModifierIsOpen =
})) !state.uiOptions.imageModifierIsOpen;
localStorage.setItem(
"ui:imageModifierIsOpen",
state.uiOptions.imageModifierIsOpen
);
})
);
}, },
toggleUseUpscaling: () => { toggleUseUpscaling: () => {
set( produce((state) => { set(
state.uiOptions.isCheckedUseUpscaling = !state.uiOptions.isCheckedUseUpscaling; produce((state) => {
state.requestOptions.use_upscale = state.uiOptions.isCheckedUseUpscaling ? 'RealESRGAN_x4plus' : null; state.uiOptions.isCheckedUseUpscaling =
localStorage.setItem('ui:isCheckedUseUpscaling', state.uiOptions.isCheckedUseUpscaling); !state.uiOptions.isCheckedUseUpscaling;
})) state.requestOptions.use_upscale = state.uiOptions
.isCheckedUseUpscaling
? "RealESRGAN_x4plus"
: null;
localStorage.setItem(
"ui:isCheckedUseUpscaling",
state.uiOptions.isCheckedUseUpscaling
);
})
);
}, },
isUsingUpscaling: () => { isUsingUpscaling: () => {
@ -195,24 +252,38 @@ export const useImageCreate = create<ImageCreateState>(devtools((set, get) => ({
}, },
toggleUseFaceCorrection: () => { toggleUseFaceCorrection: () => {
set( produce((state) => { set(
state.uiOptions.isCheckUseFaceCorrection = !state.uiOptions.isCheckUseFaceCorrection; produce((state) => {
state.use_face_correction = state.uiOptions.isCheckUseFaceCorrection ? 'GFPGANv1.3' : null; state.uiOptions.isCheckUseFaceCorrection =
localStorage.setItem('ui:isCheckUseFaceCorrection', state.uiOptions.isCheckUseFaceCorrection); !state.uiOptions.isCheckUseFaceCorrection;
})) state.use_face_correction = state.uiOptions.isCheckUseFaceCorrection
? "GFPGANv1.3"
: null;
localStorage.setItem(
"ui:isCheckUseFaceCorrection",
state.uiOptions.isCheckUseFaceCorrection
);
})
);
}, },
isUsingFaceCorrection: () => { isUsingFaceCorrection: () => {
return get().uiOptions.isCheckUseFaceCorrection; return get().uiOptions.isCheckUseFaceCorrection;
}, },
toggleUseRandomSeed: () => { toggleUseRandomSeed: () => {
set( produce((state) => { set(
produce((state) => {
state.uiOptions.isUseRandomSeed = !state.uiOptions.isUseRandomSeed; state.uiOptions.isUseRandomSeed = !state.uiOptions.isUseRandomSeed;
state.requestOptions.seed = state.uiOptions.isUseRandomSeed ? useRandomSeed() : state.requestOptions.seed; state.requestOptions.seed = state.uiOptions.isUseRandomSeed
localStorage.setItem('ui:isUseRandomSeed', state.uiOptions.isUseRandomSeed); ? useRandomSeed()
})) : state.requestOptions.seed;
localStorage.setItem(
"ui:isUseRandomSeed",
state.uiOptions.isUseRandomSeed
);
})
);
}, },
isRandomSeed: () => { isRandomSeed: () => {
@ -222,10 +293,15 @@ export const useImageCreate = create<ImageCreateState>(devtools((set, get) => ({
toggleUseAutoSave: () => { toggleUseAutoSave: () => {
//isUseAutoSave //isUseAutoSave
//save_to_disk_path //save_to_disk_path
set( produce((state) => { set(
produce((state) => {
state.uiOptions.isUseAutoSave = !state.uiOptions.isUseAutoSave; state.uiOptions.isUseAutoSave = !state.uiOptions.isUseAutoSave;
localStorage.setItem('ui:isUseAutoSave', state.uiOptions.isUseAutoSave); localStorage.setItem(
})) "ui:isUseAutoSave",
state.uiOptions.isUseAutoSave
);
})
);
}, },
isUseAutoSave: () => { isUseAutoSave: () => {
@ -233,16 +309,16 @@ export const useImageCreate = create<ImageCreateState>(devtools((set, get) => ({
}, },
toggleSoundEnabled: () => { toggleSoundEnabled: () => {
set( produce((state) => { set(
produce((state) => {
state.uiOptions.isSoundEnabled = !state.uiOptions.isSoundEnabled; state.uiOptions.isSoundEnabled = !state.uiOptions.isSoundEnabled;
//localStorage.setItem('ui:isSoundEnabled', state.uiOptions.isSoundEnabled); //localStorage.setItem('ui:isSoundEnabled', state.uiOptions.isSoundEnabled);
})) })
);
}, },
isSoundEnabled: () => { isSoundEnabled: () => {
return get().uiOptions.isSoundEnabled; return get().uiOptions.isSoundEnabled;
}, },
}))
}))); );

View File

@ -1,12 +1,12 @@
import create from 'zustand'; import create from "zustand";
import produce from 'immer'; import produce from "immer";
// import { devtools } from 'zustand/middleware' // import { devtools } from 'zustand/middleware'
interface ImageDisplayState { interface ImageDisplayState {
imageOptions: Map<string, any>; imageOptions: Map<string, any>;
currentImage: object | null; currentImage: object | null;
addNewImage: (ImageData: string, imageOptions: any) => void addNewImage: (ImageData: string, imageOptions: any) => void;
} }
export const useImageDisplay = create<ImageDisplayState>((set) => ({ export const useImageDisplay = create<ImageDisplayState>((set) => ({
@ -14,9 +14,11 @@ export const useImageDisplay = create<ImageDisplayState>((set) => ({
currentImage: null, currentImage: null,
// use produce to make sure we don't mutate state // use produce to make sure we don't mutate state
addNewImage: (ImageData: string, imageOptions: any) => { addNewImage: (ImageData: string, imageOptions: any) => {
set( produce((state) => { set(
produce((state) => {
state.currentImage = { display: ImageData, options: imageOptions }; state.currentImage = { display: ImageData, options: imageOptions };
state.images.set(ImageData, imageOptions) state.images.set(ImageData, imageOptions);
})); })
} );
},
})); }));

View File

@ -1,13 +1,13 @@
import create from 'zustand'; import create from "zustand";
import produce from 'immer'; import produce from "immer";
import { useRandomSeed } from '../utils'; import { useRandomSeed } from "../utils";
import { ImageRequest } from './imageCreateStore'; import { ImageRequest } from "./imageCreateStore";
interface ImageQueueState { interface ImageQueueState {
images : ImageRequest[]; images: ImageRequest[];
completedImageIds: string[]; completedImageIds: string[];
addNewImage: (id:string, imgRec: ImageRequest) => void addNewImage: (id: string, imgRec: ImageRequest) => void;
hasQueuedImages: () => boolean; hasQueuedImages: () => boolean;
firstInQueue: () => ImageRequest | []; firstInQueue: () => ImageRequest | [];
removeFirstInQueue: () => void; removeFirstInQueue: () => void;
@ -19,29 +19,31 @@ export const useImageQueue = create<ImageQueueState>((set, get) => ({
images: new Array(), images: new Array(),
completedImageIds: new Array(), completedImageIds: new Array(),
// use produce to make sure we don't mutate state // use produce to make sure we don't mutate state
addNewImage: (id: string, imgRec: ImageRequest, isRandom= false) => { addNewImage: (id: string, imgRec: ImageRequest, isRandom = false) => {
set( produce((state) => { set(
produce((state) => {
let { seed } = imgRec; let { seed } = imgRec;
if (isRandom) { if (isRandom) {
seed = useRandomSeed(); seed = useRandomSeed();
} }
state.images.push({ id, options: {...imgRec, seed} }); state.images.push({ id, options: { ...imgRec, seed } });
})); })
);
}, },
hasQueuedImages: () => { hasQueuedImages: () => {
return get().images.length > 0; return get().images.length > 0;
}, },
firstInQueue: () => { firstInQueue: () => {
return get().images[0] as ImageRequest || []; return (get().images[0] as ImageRequest) || [];
}, },
removeFirstInQueue: () => { removeFirstInQueue: () => {
set( produce((state) => { set(
produce((state) => {
const image = state.images.shift(); const image = state.images.shift();
state.completedImageIds.push(image.id); state.completedImageIds.push(image.id);
})); })
} );
},
})); }));

View File

@ -1,3 +1,3 @@
export function useRandomSeed(){ export function useRandomSeed() {
return Math.floor(Math.random() * 10000); return Math.floor(Math.random() * 10000);
}; }

View File

@ -1,5 +1,5 @@
import { defineConfig } from 'vite' import { defineConfig } from "vite";
import react from '@vitejs/plugin-react' import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
@ -9,16 +9,15 @@ export default defineConfig({
}, },
build: { build: {
// make sure everythign is in the same directory // make sure everythign is in the same directory
outDir: '../dist', outDir: "../dist",
rollupOptions: { rollupOptions: {
output: { output: {
// dont hash the file names // dont hash the file names
// maybe once we update the python server? // maybe once we update the python server?
entryFileNames: `[name].js`, entryFileNames: `[name].js`,
chunkFileNames: `[name].js`, chunkFileNames: `[name].js`,
assetFileNames: `[name].[ext]` assetFileNames: `[name].[ext]`,
}
}
}, },
},
}) },
});

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -62,14 +62,7 @@
], ],
[ [
"Pen", "Pen",
[ ["Chalk", "Colored Pencil", "Graphite", "Ink", "Oil Paint", "Pastel Art"]
"Chalk",
"Colored Pencil",
"Graphite",
"Ink",
"Oil Paint",
"Pastel Art"
]
], ],
[ [
"Carving and Etching", "Carving and Etching",

View File

@ -298,7 +298,7 @@
</div> </div>
<div id="editor-inputs-init-image" class="row"> <div id="editor-inputs-init-image" class="row">
<label for="init_image"><b>Initial Image:</b> (optional) </label> <input id="init_image" name="init_image" type="file" /> </button><br/> <label for="init_image"><b>Initial Image:</b> (optional) </label> <input id="init_image" name="init_image" type="file" /><br/>
<div id="init_image_preview_container" class="image_preview_container"> <div id="init_image_preview_container" class="image_preview_container">
<img id="init_image_preview" src="" width="100" height="100" /> <img id="init_image_preview" src="" width="100" height="100" />
<button id="init_image_clear" class="image_clear_btn">X</button> <button id="init_image_clear" class="image_clear_btn">X</button>