<!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"> </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>