easydiffusion/ui/frontend/dist/index.html

1532 lines
49 KiB
HTML
Raw Normal View History

2022-09-14 16:48:46 +02:00
<!DOCTYPE html>
<html lang="en">
2022-09-14 20:49:23 +02:00
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Stable Diffusion UI</title>
<script type="module" crossorigin src="/index.js"></script>
<link rel="stylesheet" href="/index.css">
</head>
<body>
<!-- The react app entry point. Currently no ui just poc importing and logging -->
<div id="root"></div>
<!-- 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>
2022-09-14 16:48:46 +02:00
</div>
2022-09-14 20:49:23 +02:00
<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
>
2022-09-14 16:48:46 +02:00
</div>
2022-09-14 20:49:23 +02:00
<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>
2022-09-14 16:48:46 +02:00
</div>
2022-09-14 20:49:23 +02:00
<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/>
2022-09-14 16:48:46 +02:00
<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/>
2022-09-14 20:49:23 +02:00
3. Try generating a smaller image.<br/>`;
2022-09-14 16:48:46 +02:00
}
2022-09-14 20:49:23 +02:00
} 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.
2022-09-14 16:48:46 +02:00
<br/><br/>
2022-09-14 20:49:23 +02:00
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}.`,
};
}
2022-09-14 16:48:46 +02:00
}
2022-09-14 20:49:23 +02:00
return { isValid: true };
}
async function makeImage() {
if (serverStatus !== "online") {
logError("The server is still starting up..");
return;
2022-09-14 16:48:46 +02:00
}
2022-09-14 20:49:23 +02:00
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");
}
2022-09-14 16:48:46 +02:00
}
2022-09-14 20:49:23 +02:00
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
2022-09-14 16:48:46 +02:00
}
2022-09-14 20:49:23 +02:00
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";
2022-09-14 16:48:46 +02:00
}
2022-09-14 20:49:23 +02:00
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);
2022-09-14 16:48:46 +02:00
}
2022-09-14 20:49:23 +02:00
}
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>
2022-09-14 16:48:46 +02:00
</html>