easydiffusion/ui/frontend/build_src/index.html
2022-09-14 14:49:23 -04:00

1530 lines
48 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Stable Diffusion UI</title>
</head>
<body>
<!-- The react app entry point. Currently no ui just poc importing and logging -->
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<!-- ORIGINAL CODE BELOW FOR REFENCE -->
<!-- KEEP FOR NOW -->
<!-- THE STYLES ARE BEING USED IN THE REACT APP -->
<!-- WE NEED TO PORT OVER THE STYLES OVER TO THE REACT COMPONENTS -->
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 11pt;
background-color: rgb(32, 33, 36);
color: #eee;
}
a {
color: rgb(0, 102, 204);
}
a:visited {
color: rgb(0, 102, 204);
}
label {
font-size: 10pt;
}
#prompt {
width: 100%;
height: 50pt;
}
@media screen and (max-width: 600px) {
#prompt {
width: 95%;
}
}
.image_preview_container {
display: none;
margin-top: 10pt;
}
.image_clear_btn {
position: absolute;
transform: translateX(-50%) translateY(-35%);
background: black;
color: white;
border: 2pt solid #ccc;
padding: 0;
cursor: pointer;
outline: inherit;
border-radius: 8pt;
width: 16pt;
height: 16pt;
font-family: Verdana;
font-size: 8pt;
}
#editor-settings-entries {
font-size: 9pt;
margin-bottom: 5px;
padding-left: 10px;
list-style-type: none;
}
#editor-settings-entries li {
padding-bottom: 3pt;
}
#guidance_scale {
transform: translateY(30%);
}
#outputMsg {
font-size: small;
}
#footer {
font-size: small;
padding-left: 10pt;
background: none;
}
#footer-legal {
font-size: 8pt;
}
.imgSeedLabel {
position: absolute;
transform: translateX(-100%);
margin-top: 5pt;
margin-left: -5pt;
font-size: 10pt;
background-color: #333;
opacity: 0.8;
color: #ddd;
border-radius: 3pt;
padding: 1pt 3pt;
}
.imgUseBtn {
position: absolute;
transform: translateX(-100%);
margin-top: 30pt;
margin-left: -5pt;
}
.imgSaveBtn {
position: absolute;
transform: translateX(-100%);
margin-top: 55pt;
margin-left: -5pt;
}
.imgItem {
display: inline;
padding-right: 10px;
}
.imgItemInfo {
opacity: 0.5;
}
#container {
width: 75%;
margin-left: auto;
margin-right: auto;
}
@media screen and (max-width: 1400px) {
#container {
width: 100%;
}
}
#meta small {
font-size: 11pt;
}
#editor {
padding: 5px;
}
#editor label {
font-weight: bold;
}
#preview {
padding: 5px;
}
#editor-inputs {
margin-bottom: 20px;
}
#editor-inputs-prompt {
flex: 1;
}
#editor-inputs .row {
padding-bottom: 10px;
}
#makeImage {
border-radius: 6px;
}
#editor-modifiers h5 {
padding: 5pt 0;
margin: 0;
}
#makeImage {
flex: 0 0 70px;
background: rgb(80, 0, 185);
border: 2px solid rgb(40, 0, 78);
color: rgb(255, 221, 255);
width: 100%;
height: 30pt;
}
#makeImage:hover {
background: rgb(93, 0, 214);
}
.flex-container {
display: flex;
}
.col-50 {
flex: 50%;
}
.col-free {
flex: 1;
}
.collapsible {
cursor: pointer;
}
.collapsible-content {
display: none;
padding-left: 15px;
}
.collapsible-content h5 {
padding: 5pt 0pt;
margin: 0;
font-size: 10pt;
}
.collapsible-handle {
color: white;
padding-right: 5px;
}
.panel-box {
background: rgb(44, 45, 48);
border: 1px solid rgb(47, 49, 53);
border-radius: 7px;
padding: 5px;
margin-bottom: 15px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.15),
0 6px 20px 0 rgba(0, 0, 0, 0.15);
}
.panel-box h4 {
margin: 0;
padding: 2px 0;
}
.prompt-modifier-tag {
border: 1px solid rgb(10, 0, 24);
border-radius: 4px;
padding: 0pt 3pt;
margin-right: 2pt;
cursor: pointer;
display: inline;
background: rgb(163, 163, 163);
color: black;
line-height: 25pt;
float: left;
font-size: 9pt;
}
.prompt-modifier-tag:hover {
background: black;
color: white;
}
#editor-modifiers-entries .prompt-modifier-tag {
background: #110f0f;
color: rgb(212, 212, 212);
margin-bottom: 4pt;
font-size: 10pt;
}
#editor-modifiers-entries .prompt-modifier-tag:hover {
background: rgb(163, 163, 163);
color: black;
}
#editor-modifiers .editor-modifiers-leaf {
padding-top: 10pt;
padding-bottom: 10pt;
}
#preview {
margin-left: 20pt;
}
img {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.15),
0 6px 20px 0 rgba(0, 0, 0, 0.15);
}
.line-separator {
background: rgb(56, 56, 56);
height: 1pt;
margin: 15pt 0;
}
#editor-inputs-tags-container {
margin-top: 5pt;
display: none;
}
#server-status {
float: right;
}
#server-status-color {
width: 8pt;
height: 8pt;
border-radius: 4pt;
background-color: rgb(128, 87, 0);
/* background-color: rgb(197, 1, 1); */
float: left;
transform: translateY(15%);
}
#server-status-msg {
color: rgb(128, 87, 0);
padding-left: 2pt;
font-size: 10pt;
}
#preview-prompt {
font-size: 16pt;
margin-bottom: 10pt;
}
#coffeeButton {
height: 23px;
transform: translateY(25%);
}
</style>
<!-- ALL OF THIS IS HERE FOR REFERNCE FOR THE TIME BEING BUT CAN BE SAFLEY REMOVED -->
<!-- All of the original DOM -->
<div id="container" style="display: none">
<div class="flex-container">
<div id="editor" class="col-50">
<div id="meta">
<div id="server-status">
<div id="server-status-color">&nbsp;</div>
<span id="server-status-msg">Stable Diffusion is starting..</span>
</div>
<h1>
Stable Diffusion UI
<small>v2.1 <span id="updateBranchLabel"></span></small>
</h1>
</div>
<div id="editor-inputs">
<div id="editor-inputs-prompt" class="row">
<label for="prompt">Prompt</label>
<textarea id="prompt" class="col-free">
a photograph of an astronaut riding a horse</textarea
>
</div>
<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" /><br />
<div
id="init_image_preview_container"
class="image_preview_container"
>
<img id="init_image_preview" src="" width="100" height="100" />
<button id="init_image_clear" class="image_clear_btn">X</button>
</div>
</div>
<div id="editor-inputs-tags-container" class="row">
<label>Tags: <small>(click a tag to remove it)</small></label>
<div id="editor-inputs-tags-list"></div>
</div>
<button id="makeImage">Make Image</button>
</div>
<div class="line-separator">&nbsp;</div>
<div id="editor-settings" class="panel-box">
<h4 class="collapsible">Advanced Settings</h4>
<ul id="editor-settings-entries" class="collapsible-content">
<li>
<input
id="use_face_correction"
name="use_face_correction"
type="checkbox"
checked
/>
<label for="use_face_correction"
>Fix incorrect faces and eyes (uses GFPGAN)</label
>
</li>
<li>
<input id="use_upscale" name="use_upscale" type="checkbox" />
<label for="use_upscale"
>Upscale the image to 4x resolution using
</label>
<select id="upscale_model" name="upscale_model">
<option value="RealESRGAN_x4plus" selected>
RealESRGAN_x4plus
</option>
<option value="RealESRGAN_x4plus_anime_6B">
RealESRGAN_x4plus_anime_6B
</option>
</select>
</li>
<li>
<input
id="show_only_filtered_image"
name="show_only_filtered_image"
type="checkbox"
checked
/>
<label for="show_only_filtered_image"
>Show only the corrected/upscaled image</label
>
</li>
<br />
<li>
<label for="seed">Seed:</label>
<input id="seed" name="seed" size="10" value="30000" />
<input
id="random_seed"
name="random_seed"
type="checkbox"
checked
/>
<label for="random_seed">Random Image</label>
</li>
<li>
<label for="num_outputs_total">Number of images to make:</label>
<input
id="num_outputs_total"
name="num_outputs_total"
value="1"
size="4"
/>
<label for="num_outputs_parallel">Generate in parallel:</label>
<input
id="num_outputs_parallel"
name="num_outputs_parallel"
value="1"
size="4"
/>
(images at once)
</li>
<li>
<label for="width">Width:</label>
<select id="width" name="width" value="512">
<option value="128">128 (*)</option>
<option value="192">192</option>
<option value="256">256 (*)</option>
<option value="320">320</option>
<option value="384">384</option>
<option value="448">448</option>
<option value="512" selected>512 (*)</option>
<option value="576">576</option>
<option value="640">640</option>
<option value="704">704</option>
<option value="768">768 (*)</option>
<option value="832">832</option>
<option value="896">896</option>
<option value="960">960</option>
<option value="1024">1024 (*)</option>
</select>
</li>
<li>
<label for="height">Height:</label>
<select id="height" name="height" value="512">
<option value="128">128 (*)</option>
<option value="192">192</option>
<option value="256">256 (*)</option>
<option value="320">320</option>
<option value="384">384</option>
<option value="448">448</option>
<option value="512" selected>512 (*)</option>
<option value="576">576</option>
<option value="640">640</option>
<option value="704">704</option>
<option value="768">768 (*)</option>
<option value="832">832</option>
<option value="896">896</option>
<option value="960">960</option>
<option value="1024">1024 (*)</option>
</select>
</li>
<li>
<label for="num_inference_steps"
>Number of inference steps:</label
>
<input
id="num_inference_steps"
name="num_inference_steps"
size="4"
value="50"
/>
</li>
<li>
<label for="guidance_scale">Guidance Scale:</label>
<input
id="guidance_scale"
name="guidance_scale"
value="75"
type="range"
min="10"
max="200"
/>
<span id="guidance_scale_value"></span>
</li>
<li>
<span id="prompt_strength_container"
><label for="prompt_strength">Prompt Strength:</label>
<input
id="prompt_strength"
name="prompt_strength"
value="8"
type="range"
min="0"
max="10" />
<span id="prompt_strength_value"></span><br
/></span>
</li>
<li>&nbsp;</li>
<li>
<input id="save_to_disk" name="save_to_disk" type="checkbox" />
<label for="save_to_disk"
>Automatically save to
<input id="diskPath" name="diskPath" size="40" disabled
/></label>
</li>
<li>
<input
id="sound_toggle"
name="sound_toggle"
type="checkbox"
checked
/>
<label for="sound_toggle">Play sound on task completion</label>
</li>
<li>
<input id="turbo" name="turbo" type="checkbox" checked />
<label for="turbo"
>Turbo mode (generates images faster, but uses an additional 1
GB of GPU memory)</label
>
</li>
<li>
<input id="use_cpu" name="use_cpu" type="checkbox" />
<label for="use_cpu"
>Use CPU instead of GPU (warning: this will be *very*
slow)</label
>
</li>
<li>
<input
id="use_full_precision"
name="use_full_precision"
type="checkbox"
/>
<label for="use_full_precision"
>Use full precision (for GPU-only. warning: this will consume
more VRAM)</label
>
</li>
<!-- <li><input id="allow_nsfw" name="allow_nsfw" type="checkbox"> <label for="allow_nsfw">Allow NSFW Content (You confirm you are above 18 years of age)</label></li> -->
<br />
<li>
<input
id="use_beta_channel"
name="use_beta_channel"
type="checkbox"
/>
<label for="use_beta_channel"
>🔥Beta channel. Get the latest features immediately (but
could be less stable). Please restart the program after
changing this.</label
>
</li>
</ul>
</div>
<div id="editor-modifiers" class="panel-box">
<h4 class="collapsible">Image Modifiers (art styles, tags etc)</h4>
<div
id="editor-modifiers-entries"
class="collapsible-content"
></div>
</div>
</div>
<div id="preview" class="col-50">
<div id="preview-prompt">
Type a prompt and press the "Make Image" button.<br /><br />You can
set an "Initial Image" if you want to guide the AI.<br /><br />You
can also add modifiers like "Realistic", "Pencil Sketch",
"ArtStation" etc by browsing through the "Image Modifiers" section
and selecting the desired modifiers.<br /><br />Click "Advanced
Settings" for additional settings like seed, image size, number of
images to generate etc.<br /><br />Enjoy! :)
</div>
<div id="outputMsg"></div>
<div id="current-images" class="img-preview"></div>
</div>
</div>
<div class="line-separator">&nbsp;</div>
<div id="footer" class="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="media/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">
<p>
<b>Disclaimer:</b> The authors of this project are not responsible
for 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>
<!-- All of the original script -->
<script>
const SOUND_ENABLED_KEY = "soundEnabled";
const SAVE_TO_DISK_KEY = "saveToDisk";
const USE_CPU_KEY = "useCPU";
const USE_FULL_PRECISION_KEY = "useFullPrecision";
const USE_TURBO_MODE_KEY = "useTurboMode";
const DISK_PATH_KEY = "diskPath";
const ADVANCED_PANEL_OPEN_KEY = "advancedPanelOpen";
const MODIFIERS_PANEL_OPEN_KEY = "modifiersPanelOpen";
const USE_FACE_CORRECTION_KEY = "useFaceCorrection";
const USE_UPSCALING_KEY = "useUpscaling";
const SHOW_ONLY_FILTERED_IMAGE_KEY = "showOnlyFilteredImage";
const HEALTH_PING_INTERVAL = 5; // seconds
const MAX_INIT_IMAGE_DIMENSION = 768;
const IMAGE_REGEX = new RegExp("data:image/[A-Za-z]+;base64");
let promptField = document.querySelector("#prompt");
let numOutputsTotalField = document.querySelector("#num_outputs_total");
let numOutputsParallelField = document.querySelector(
"#num_outputs_parallel"
);
let numInferenceStepsField = document.querySelector(
"#num_inference_steps"
);
let guidanceScaleField = document.querySelector("#guidance_scale");
let guidanceScaleValueLabel = document.querySelector(
"#guidance_scale_value"
);
let randomSeedField = document.querySelector("#random_seed");
let seedField = document.querySelector("#seed");
let widthField = document.querySelector("#width");
let heightField = document.querySelector("#height");
let initImageSelector = document.querySelector("#init_image");
let initImagePreview = document.querySelector("#init_image_preview");
// let maskImageSelector = document.querySelector("#mask")
// let maskImagePreview = document.querySelector("#mask_preview")
let turboField = document.querySelector("#turbo");
let useCPUField = document.querySelector("#use_cpu");
let useFullPrecisionField = document.querySelector("#use_full_precision");
let saveToDiskField = document.querySelector("#save_to_disk");
let diskPathField = document.querySelector("#diskPath");
// let allowNSFWField = document.querySelector("#allow_nsfw")
let useBetaChannelField = document.querySelector("#use_beta_channel");
let promptStrengthField = document.querySelector("#prompt_strength");
let promptStrengthValueLabel = document.querySelector(
"#prompt_strength_value"
);
let useFaceCorrectionField = document.querySelector(
"#use_face_correction"
);
let useUpscalingField = document.querySelector("#use_upscale");
let upscaleModelField = document.querySelector("#upscale_model");
let showOnlyFilteredImageField = document.querySelector(
"#show_only_filtered_image"
);
let updateBranchLabel = document.querySelector("#updateBranchLabel");
let makeImageBtn = document.querySelector("#makeImage");
let imagesContainer = document.querySelector("#current-images");
let initImagePreviewContainer = document.querySelector(
"#init_image_preview_container"
);
let initImageClearBtn = document.querySelector("#init_image_clear");
let promptStrengthContainer = document.querySelector(
"#prompt_strength_container"
);
// let maskSetting = document.querySelector('#mask_setting')
// let maskImagePreviewContainer = document.querySelector('#mask_preview_container')
// let maskImageClearBtn = document.querySelector('#mask_clear')
let editorModifierEntries = document.querySelector(
"#editor-modifiers-entries"
);
let editorModifierTagsList = document.querySelector(
"#editor-inputs-tags-list"
);
let editorTagsContainer = document.querySelector(
"#editor-inputs-tags-container"
);
let previewPrompt = document.querySelector("#preview-prompt");
let showConfigToggle = document.querySelector("#configToggleBtn");
// let configBox = document.querySelector('#config')
let outputMsg = document.querySelector("#outputMsg");
let soundToggle = document.querySelector("#sound_toggle");
let serverStatusColor = document.querySelector("#server-status-color");
let serverStatusMsg = document.querySelector("#server-status-msg");
let advancedPanelHandle = document.querySelector(
"#editor-settings .collapsible"
);
let modifiersPanelHandle = document.querySelector(
"#editor-modifiers .collapsible"
);
let serverStatus = "offline";
let activeTags = [];
let lastPromptUsed = "";
function getLocalStorageItem(key, fallback) {
let item = localStorage.getItem(key);
if (item === null) {
return fallback;
}
return item;
}
function getLocalStorageBoolItem(key, fallback) {
let item = localStorage.getItem(key);
if (item === null) {
return fallback;
}
return item === "true" ? true : false;
}
function handleBoolSettingChange(key) {
return function (e) {
localStorage.setItem(key, e.target.checked.toString());
};
}
function handleStringSettingChange(key) {
return function (e) {
localStorage.setItem(key, e.target.value.toString());
};
}
function isSoundEnabled() {
return getLocalStorageBoolItem(SOUND_ENABLED_KEY, true);
}
function isFaceCorrectionEnabled() {
return getLocalStorageBoolItem(USE_FACE_CORRECTION_KEY, false);
}
function isUpscalingEnabled() {
return getLocalStorageBoolItem(USE_UPSCALING_KEY, false);
}
function isShowOnlyFilteredImageEnabled() {
return getLocalStorageBoolItem(SHOW_ONLY_FILTERED_IMAGE_KEY, true);
}
function isSaveToDiskEnabled() {
return getLocalStorageBoolItem(SAVE_TO_DISK_KEY, false);
}
function isUseCPUEnabled() {
return getLocalStorageBoolItem(USE_CPU_KEY, false);
}
function isUseFullPrecisionEnabled() {
return getLocalStorageBoolItem(USE_FULL_PRECISION_KEY, false);
}
function isUseTurboModeEnabled() {
return getLocalStorageBoolItem(USE_TURBO_MODE_KEY, true);
}
function getSavedDiskPath() {
return getLocalStorageItem(DISK_PATH_KEY, "");
}
function isAdvancedPanelOpenEnabled() {
return getLocalStorageBoolItem(ADVANCED_PANEL_OPEN_KEY, false);
}
function isModifiersPanelOpenEnabled() {
return getLocalStorageBoolItem(MODIFIERS_PANEL_OPEN_KEY, false);
}
function setStatus(statusType, msg, msgType) {
if (statusType !== "server") {
return;
}
if (msgType == "error") {
// msg = '<span style="color: red">' + msg + '<span>'
serverStatusColor.style.backgroundColor = "red";
serverStatusMsg.style.color = "red";
serverStatusMsg.innerHTML = "Stable Diffusion has stopped";
} else if (msgType == "success") {
// msg = '<span style="color: green">' + msg + '<span>'
serverStatusColor.style.backgroundColor = "green";
serverStatusMsg.style.color = "green";
serverStatusMsg.innerHTML = "Stable Diffusion is ready";
serverStatus = "online";
}
}
function logMsg(msg, level) {
if (level === "error") {
outputMsg.innerHTML =
'<span style="color: red">Error: ' + msg + "</span>";
} else if (level === "warn") {
outputMsg.innerHTML =
'<span style="color: orange">Warning: ' + msg + "</span>";
} else {
outputMsg.innerHTML = msg;
}
console.log(level, msg);
}
function logError(msg, res) {
logMsg(msg, "error");
console.log("request error", res);
setStatus("request", "error", "error");
}
function playSound() {
const audio = new Audio("/media/ding.mp3");
audio.volume = 0.2;
audio.play();
}
async function healthCheck() {
try {
let res = await fetch("/ping");
res = await res.json();
if (res[0] == "OK") {
setStatus("server", "online", "success");
} else {
setStatus("server", "offline", "error");
}
} catch (e) {
setStatus("server", "offline", "error");
}
}
// makes a single image. don't call this directly, use makeImage() instead
async function doMakeImage(reqBody) {
let res = "";
let seed = reqBody["seed"];
try {
res = await fetch("/image", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(reqBody),
});
if (res.status != 200) {
if (serverStatus === "online") {
logError(
"Stable Diffusion had an error: " +
(await res.text()) +
". This happens sometimes. Maybe modify the prompt or seed a little bit?",
res
);
} else {
logError(
"Stable Diffusion is still starting up, please wait. If this goes on beyond a few minutes, Stable Diffusion has probably crashed.",
res
);
}
res = undefined;
} else {
res = await res.json();
if (res.status !== "succeeded") {
let msg = "";
if (res.detail !== undefined) {
msg = res.detail;
if (msg.toLowerCase().includes("out of memory")) {
msg += `<br/><br/>
<b>Suggestions</b>:
<br/>
1. If you have set an initial image, please try reducing its dimension to ${MAX_INIT_IMAGE_DIMENSION}x${MAX_INIT_IMAGE_DIMENSION} or smaller.<br/>
2. Try disabling the '<em>Turbo mode</em>' under '<em>Advanced Settings</em>'.<br/>
3. Try generating a smaller image.<br/>`;
}
} else {
msg = res;
}
logError(msg, res);
res = undefined;
}
}
} catch (e) {
console.log("request error", e);
setStatus("request", "error", "error");
}
if (!res) {
return false;
}
lastPromptUsed = reqBody["prompt"];
for (let idx in res.output) {
let imgBody = "";
try {
let imgData = res.output[idx];
imgBody = imgData.data;
} catch (e) {
console.log(imgBody);
setStatus("request", "invalid image", "error");
continue;
}
let imgItem = document.createElement("div");
imgItem.className = "imgItem";
let img = document.createElement("img");
img.width = parseInt(reqBody.width);
img.height = parseInt(reqBody.height);
img.src = imgBody;
let imgItemInfo = document.createElement("span");
imgItemInfo.className = "imgItemInfo";
let imgSeedLabel = document.createElement("span");
imgSeedLabel.className = "imgSeedLabel";
imgSeedLabel.innerHTML = "Seed: " + seed;
let imgUseBtn = document.createElement("button");
imgUseBtn.className = "imgUseBtn";
imgUseBtn.innerHTML = "Use as Input";
let imgSaveBtn = document.createElement("button");
imgSaveBtn.className = "imgSaveBtn";
imgSaveBtn.innerHTML = "Download";
imgItem.appendChild(img);
imgItem.appendChild(imgItemInfo);
imgItemInfo.appendChild(imgSeedLabel);
imgItemInfo.appendChild(imgUseBtn);
imgItemInfo.appendChild(imgSaveBtn);
imagesContainer.appendChild(imgItem);
imgUseBtn.addEventListener("click", function () {
initImageSelector.value = null;
initImagePreview.src = imgBody;
initImagePreviewContainer.style.display = "block";
promptStrengthContainer.style.display = "block";
// maskSetting.style.display = 'block'
randomSeedField.checked = false;
seedField.value = seed;
seedField.disabled = false;
});
imgSaveBtn.addEventListener("click", function () {
let imgDownload = document.createElement("a");
imgDownload.download = createFileName();
imgDownload.href = imgBody;
imgDownload.click();
});
imgItem.addEventListener("mouseenter", function () {
imgItemInfo.style.opacity = 1;
});
imgItem.addEventListener("mouseleave", function () {
imgItemInfo.style.opacity = 0.5;
});
}
return true;
}
function validateInput() {
let width = parseInt(widthField.value);
let height = parseInt(heightField.value);
if (IMAGE_REGEX.test(initImagePreview.src)) {
if (
initImagePreview.naturalWidth > MAX_INIT_IMAGE_DIMENSION ||
initImagePreview.naturalHeight > MAX_INIT_IMAGE_DIMENSION
) {
return {
isValid: false,
warning: `The dimensions of your initial image are very large, and can cause 'Out of Memory' errors! Please ensure that its dimensions are equal (or smaller) than the desired output image.
<br/><br/>
Your initial image size is ${initImagePreview.naturalWidth}x${initImagePreview.naturalHeight} pixels. Please try to keep it smaller than ${MAX_INIT_IMAGE_DIMENSION}x${MAX_INIT_IMAGE_DIMENSION}.`,
};
}
}
return { isValid: true };
}
async function makeImage() {
if (serverStatus !== "online") {
logError("The server is still starting up..");
return;
}
let validation = validateInput();
if (validation["isValid"]) {
outputMsg.innerHTML = "Fetching..";
} else {
if (validation["error"]) {
logError(validation["error"]);
return;
} else if (validation["warning"]) {
logMsg(validation["warning"], "warn");
}
}
setStatus("request", "fetching..");
makeImageBtn.innerHTML = "Processing..";
makeImageBtn.disabled = true;
let seed = randomSeedField.checked
? Math.floor(Math.random() * 10000000)
: parseInt(seedField.value);
let numOutputsTotal = parseInt(numOutputsTotalField.value);
let numOutputsParallel = parseInt(numOutputsParallelField.value);
let batchCount = Math.ceil(numOutputsTotal / numOutputsParallel);
let batchSize = numOutputsParallel;
let prompt = promptField.value;
if (activeTags.length > 0) {
let promptTags = activeTags.join(", ");
prompt += ", " + promptTags;
}
previewPrompt.innerHTML = prompt;
let reqBody = {
prompt: prompt,
num_outputs: batchSize,
num_inference_steps: numInferenceStepsField.value,
guidance_scale: parseInt(guidanceScaleField.value) / 10,
width: widthField.value,
height: heightField.value,
// allow_nsfw: allowNSFWField.checked,
turbo: turboField.checked,
use_cpu: useCPUField.checked,
use_full_precision: useFullPrecisionField.checked,
};
if (IMAGE_REGEX.test(initImagePreview.src)) {
reqBody["init_image"] = initImagePreview.src;
reqBody["prompt_strength"] = parseInt(promptStrengthField.value) / 10;
// if (IMAGE_REGEX.test(maskImagePreview.src)) {
// reqBody['mask'] = maskImagePreview.src
// }
}
if (saveToDiskField.checked && diskPathField.value.trim() !== "") {
reqBody["save_to_disk_path"] = diskPathField.value.trim();
}
if (useFaceCorrectionField.checked) {
reqBody["use_face_correction"] = "GFPGANv1.3";
}
if (useUpscalingField.checked) {
reqBody["use_upscale"] = upscaleModelField.value;
}
if (
showOnlyFilteredImageField.checked &&
(useUpscalingField.checked || useFaceCorrectionField.checked)
) {
reqBody["show_only_filtered_image"] =
showOnlyFilteredImageField.checked;
}
let time = new Date().getTime();
imagesContainer.innerHTML = "";
let successCount = 0;
for (let i = 0; i < batchCount; i++) {
reqBody["seed"] = seed + i * batchSize;
let success = await doMakeImage(reqBody);
if (success) {
outputMsg.innerHTML =
"Processed batch " + (i + 1) + "/" + batchCount;
successCount++;
}
}
makeImageBtn.innerHTML = "Make Image";
makeImageBtn.disabled = false;
if (isSoundEnabled()) {
playSound();
}
time = new Date().getTime() - time;
time /= 1000;
if (successCount === batchCount) {
outputMsg.innerHTML =
"Processed " + numOutputsTotal + " images in " + time + " seconds";
setStatus("request", "done", "success");
}
if (randomSeedField.checked) {
seedField.value = seed;
}
}
// create a file name with embedded prompt and metadata
// for easier cateloging and comparison
function createFileName() {
// Most important information is the prompt
let underscoreName = lastPromptUsed.replace(/[^a-zA-Z0-9]/g, "_");
underscoreName = underscoreName.substring(0, 100);
const seed = seedField.value;
const steps = numInferenceStepsField.value;
const guidance = guidanceScaleField.value;
// name and the top level metadata
let fileName = `${underscoreName}_Seed-${seed}_Steps-${steps}_Guidance-${guidance}`;
// add the tags
// let tags = [];
// let tagString = '';
// document.querySelectorAll(modifyTagsSelector).forEach(function(tag) {
// tags.push(tag.innerHTML);
// })
// join the tags with a pipe
// if (activeTags.length > 0) {
// tagString = '_Tags-';
// tagString += tags.join('|');
// }
// // append empty or populated tags
// fileName += `${tagString}`;
// add the file extension
fileName += `.png`;
return fileName;
}
soundToggle.addEventListener(
"click",
handleBoolSettingChange(SOUND_ENABLED_KEY)
);
soundToggle.checked = isSoundEnabled();
saveToDiskField.checked = isSaveToDiskEnabled();
diskPathField.disabled = !saveToDiskField.checked;
useFaceCorrectionField.addEventListener(
"click",
handleBoolSettingChange(USE_FACE_CORRECTION_KEY)
);
useFaceCorrectionField.checked = isFaceCorrectionEnabled();
useUpscalingField.checked = isUpscalingEnabled();
upscaleModelField.disabled = !useUpscalingField.checked;
showOnlyFilteredImageField.addEventListener(
"click",
handleBoolSettingChange(SHOW_ONLY_FILTERED_IMAGE_KEY)
);
showOnlyFilteredImageField.checked = isShowOnlyFilteredImageEnabled();
useCPUField.addEventListener(
"click",
handleBoolSettingChange(USE_CPU_KEY)
);
useCPUField.checked = isUseCPUEnabled();
useFullPrecisionField.addEventListener(
"click",
handleBoolSettingChange(USE_FULL_PRECISION_KEY)
);
useFullPrecisionField.checked = isUseFullPrecisionEnabled();
turboField.addEventListener(
"click",
handleBoolSettingChange(USE_TURBO_MODE_KEY)
);
turboField.checked = isUseTurboModeEnabled();
diskPathField.addEventListener(
"change",
handleStringSettingChange(DISK_PATH_KEY)
);
saveToDiskField.addEventListener("click", function (e) {
diskPathField.disabled = !this.checked;
handleBoolSettingChange(SAVE_TO_DISK_KEY)(e);
});
useUpscalingField.addEventListener("click", function (e) {
upscaleModelField.disabled = !this.checked;
handleBoolSettingChange(USE_UPSCALING_KEY)(e);
});
function setPanelOpen(panelHandle) {
let panelContents = panelHandle.nextElementSibling;
panelHandle.classList.add("active");
panelContents.style.display = "block";
}
if (isAdvancedPanelOpenEnabled()) {
setPanelOpen(advancedPanelHandle);
}
if (isModifiersPanelOpenEnabled()) {
setPanelOpen(modifiersPanelHandle);
}
makeImageBtn.addEventListener("click", makeImage);
function updateGuidanceScale() {
guidanceScaleValueLabel.innerHTML = guidanceScaleField.value / 10;
}
guidanceScaleField.addEventListener("input", updateGuidanceScale);
updateGuidanceScale();
function updatePromptStrength() {
promptStrengthValueLabel.innerHTML = promptStrengthField.value / 10;
}
promptStrengthField.addEventListener("input", updatePromptStrength);
updatePromptStrength();
useBetaChannelField.addEventListener("click", async function (e) {
if (serverStatus !== "online") {
logError("The server is still starting up..");
alert("The server is still starting up..");
e.preventDefault();
return false;
}
let updateBranch = this.checked ? "beta" : "main";
try {
let res = await fetch("/app_config", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
update_branch: updateBranch,
}),
});
res = await res.json();
console.log("set config status response", res);
} catch (e) {
console.log("set config status error", e);
}
});
async function getAppConfig() {
try {
let res = await fetch("/app_config");
config = await res.json();
if (config.update_branch === "beta") {
useBetaChannelField.checked = true;
updateBranchLabel.innerHTML = "(beta)";
}
console.log("get config status response", config);
} catch (e) {
console.log("get config status error", e);
}
}
function checkRandomSeed() {
if (randomSeedField.checked) {
seedField.disabled = true;
seedField.value = "0";
} else {
seedField.disabled = false;
}
}
randomSeedField.addEventListener("input", checkRandomSeed);
checkRandomSeed();
function showInitImagePreview() {
if (initImageSelector.files.length === 0) {
initImagePreviewContainer.style.display = "none";
promptStrengthContainer.style.display = "none";
// maskSetting.style.display = 'none'
return;
}
let reader = new FileReader();
let file = initImageSelector.files[0];
reader.addEventListener("load", function () {
// console.log(file.name, reader.result)
initImagePreview.src = reader.result;
initImagePreviewContainer.style.display = "block";
promptStrengthContainer.style.display = "block";
// maskSetting.style.display = 'block'
});
if (file) {
reader.readAsDataURL(file);
}
}
initImageSelector.addEventListener("change", showInitImagePreview);
showInitImagePreview();
initImageClearBtn.addEventListener("click", function () {
initImageSelector.value = null;
// maskImageSelector.value = null
initImagePreview.src = "";
// maskImagePreview.src = ''
initImagePreviewContainer.style.display = "none";
// maskImagePreviewContainer.style.display = 'none'
// maskSetting.style.display = 'none'
promptStrengthContainer.style.display = "none";
});
// function showMaskImagePreview() {
// if (maskImageSelector.files.length === 0) {
// maskImagePreviewContainer.style.display = 'none'
// return
// }
// let reader = new FileReader()
// let file = maskImageSelector.files[0]
// reader.addEventListener('load', function() {
// maskImagePreview.src = reader.result
// maskImagePreviewContainer.style.display = 'block'
// })
// if (file) {
// reader.readAsDataURL(file)
// }
// }
// maskImageSelector.addEventListener('change', showMaskImagePreview)
// showMaskImagePreview()
// maskImageClearBtn.addEventListener('click', function() {
// maskImageSelector.value = null
// maskImagePreview.src = ''
// maskImagePreviewContainer.style.display = 'none'
// })
</script>
<script>
function createCollapsibles(node) {
if (!node) {
node = document;
}
let collapsibles = node.querySelectorAll(".collapsible");
collapsibles.forEach(function (c) {
let handle = document.createElement("span");
handle.className = "collapsible-handle";
if (c.className.indexOf("active") !== -1) {
handle.innerHTML = "&#x2796;"; // minus
} else {
handle.innerHTML = "&#x2795;"; // plus
}
c.insertBefore(handle, c.firstChild);
c.addEventListener("click", function () {
this.classList.toggle("active");
let content = this.nextElementSibling;
if (content.style.display === "block") {
content.style.display = "none";
handle.innerHTML = "&#x2795;"; // plus
} else {
content.style.display = "block";
handle.innerHTML = "&#x2796;"; // minus
}
if (this == advancedPanelHandle) {
let state = content.style.display === "block" ? "true" : "false";
localStorage.setItem(ADVANCED_PANEL_OPEN_KEY, state);
} else if (this == modifiersPanelHandle) {
let state = content.style.display === "block" ? "true" : "false";
localStorage.setItem(MODIFIERS_PANEL_OPEN_KEY, state);
}
});
});
}
createCollapsibles();
function refreshTagsList() {
editorModifierTagsList.innerHTML = "";
if (activeTags.length == 0) {
editorTagsContainer.style.display = "none";
return;
} else {
editorTagsContainer.style.display = "block";
}
activeTags.forEach(function (tag) {
let el = document.createElement("div");
el.className = "prompt-modifier-tag";
el.innerHTML = tag;
editorModifierTagsList.appendChild(el);
el.addEventListener("click", function () {
let idx = activeTags.indexOf(tag);
if (idx !== -1) {
activeTags.splice(idx, 1);
refreshTagsList();
}
});
});
let brk = document.createElement("br");
brk.style.clear = "both";
editorModifierTagsList.appendChild(brk);
}
async function getDiskPath() {
try {
let diskPath = getSavedDiskPath();
if (diskPath !== "") {
diskPathField.value = diskPath;
return;
}
let res = await fetch("/output_dir");
if (res.status === 200) {
res = await res.json();
res = res[0];
document.querySelector("#diskPath").value = res;
}
} catch (e) {
console.log("error fetching output dir path", e);
}
}
async function loadModifiers() {
try {
let res = await fetch("/modifiers.json");
if (res.status === 200) {
res = await res.json();
res.forEach(function (m) {
let title = m[0];
let modifiers = m[1];
let titleEl = document.createElement("h5");
titleEl.className = "collapsible";
titleEl.innerHTML = title;
let modifiersEl = document.createElement("div");
modifiersEl.classList.add(
"collapsible-content",
"editor-modifiers-leaf"
);
modifiers.forEach(function (modifier) {
let tagEl = document.createElement("div");
tagEl.className = "prompt-modifier-tag";
tagEl.innerHTML = modifier;
modifiersEl.appendChild(tagEl);
tagEl.addEventListener("click", function () {
if (activeTags.includes(modifier)) {
return;
}
activeTags.push(modifier);
refreshTagsList();
});
});
let brk = document.createElement("br");
brk.style.clear = "both";
modifiersEl.appendChild(brk);
let e = document.createElement("div");
e.appendChild(titleEl);
e.appendChild(modifiersEl);
editorModifierEntries.appendChild(e);
});
createCollapsibles(editorModifierEntries);
}
} catch (e) {
console.log("error fetching modifiers", e);
}
}
/* TURNED OFF */
async function init() {
// await loadModifiers()
// await getDiskPath()
// await getAppConfig()
// setInterval(healthCheck, HEALTH_PING_INTERVAL * 1000)
// healthCheck()
// playSound()
}
init();
</script>
</body>
</html>