mirror of
https://github.com/easydiffusion/easydiffusion.git
synced 2024-12-30 19:08:55 +01:00
1532 lines
49 KiB
HTML
1532 lines
49 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>
|
|
<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"> </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"> </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> </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"> </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 = "➖"; // minus
|
|
} else {
|
|
handle.innerHTML = "➕"; // 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 = "➕"; // plus
|
|
} else {
|
|
content.style.display = "block";
|
|
handle.innerHTML = "➖"; // 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>
|