"use strict" // Opt in to a restricted variant of JavaScript
const HEALTH_PING_INTERVAL = 5 // seconds
const MAX_INIT_IMAGE_DIMENSION = 768
const MIN_GPUS_TO_SHOW_SELECTION = 2
const IMAGE_REGEX = new RegExp('data:image/[A-Za-z]+;base64')
let sessionId = Date.now()
let promptField = document.querySelector('#prompt')
let promptsFromFileSelector = document.querySelector('#prompt_from_file')
let promptsFromFileBtn = document.querySelector('#promptsFromFileBtn')
let negativePromptField = document.querySelector('#negative_prompt')
let numOutputsTotalField = document.querySelector('#num_outputs_total')
let numOutputsParallelField = document.querySelector('#num_outputs_parallel')
let numInferenceStepsField = document.querySelector('#num_inference_steps')
let guidanceScaleSlider = document.querySelector('#guidance_scale_slider')
let guidanceScaleField = document.querySelector('#guidance_scale')
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 initImageSizeBox = document.querySelector("#init_image_size_box")
let maskImageSelector = document.querySelector("#mask")
let maskImagePreview = document.querySelector("#mask_preview")
let turboField = document.querySelector('#turbo')
let useCPUField = document.querySelector('#use_cpu')
let autoPickGPUsField = document.querySelector('#auto_pick_gpus')
let useGPUsField = document.querySelector('#use_gpus')
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 promptStrengthSlider = document.querySelector('#prompt_strength_slider')
let promptStrengthField = document.querySelector('#prompt_strength')
let samplerField = document.querySelector('#sampler')
let samplerSelectionContainer = document.querySelector("#samplerSelection")
let useFaceCorrectionField = document.querySelector("#use_face_correction")
let useUpscalingField = document.querySelector("#use_upscale")
let upscaleModelField = document.querySelector("#upscale_model")
let stableDiffusionModelField = document.querySelector('#stable_diffusion_model')
let vaeModelField = document.querySelector('#vae_model')
let outputFormatField = document.querySelector('#output_format')
let showOnlyFilteredImageField = document.querySelector("#show_only_filtered_image")
let updateBranchLabel = document.querySelector("#updateBranchLabel")
let streamImageProgressField = document.querySelector("#stream_image_progress")
let makeImageBtn = document.querySelector('#makeImage')
let stopImageBtn = document.querySelector('#stopImage')
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 initialText = document.querySelector("#initial-text")
let previewTools = document.querySelector("#preview-tools")
let clearAllPreviewsBtn = document.querySelector("#clear-all-previews")
// let maskSetting = document.querySelector('#editor-inputs-mask_setting')
// let maskImagePreviewContainer = document.querySelector('#mask_preview_container')
// let maskImageClearBtn = document.querySelector('#mask_clear')
let maskSetting = document.querySelector('#enable_mask')
let imagePreview = document.querySelector("#preview")
// 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')
document.querySelector('.drawing-board-control-navigation-back').innerHTML = ''
document.querySelector('.drawing-board-control-navigation-forward').innerHTML = ''
let maskResetButton = document.querySelector('.drawing-board-control-navigation-reset')
maskResetButton.innerHTML = 'Clear'
maskResetButton.style.fontWeight = 'normal'
maskResetButton.style.fontSize = '10pt'
let serverState = {'status': 'Offline', 'time': Date.now()}
let bellPending = false
let taskQueue = []
let currentTask = null
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 getSetting("sound_toggle")
}
function getSavedDiskPath() {
return getSetting("diskPath")
}
function setStatus(statusType, msg, msgType) {
}
function setServerStatus(msgType, msg) {
switch(msgType) {
case 'online':
serverStatusColor.style.color = 'green'
serverStatusMsg.style.color = 'green'
serverStatusMsg.innerText = 'Stable Diffusion is ' + msg
break
case 'busy':
serverStatusColor.style.color = 'rgb(200, 139, 0)'
serverStatusMsg.style.color = 'rgb(200, 139, 0)'
serverStatusMsg.innerText = 'Stable Diffusion is ' + msg
break
case 'error':
serverStatusColor.style.color = 'red'
serverStatusMsg.style.color = 'red'
serverStatusMsg.innerText = 'Stable Diffusion has stopped'
break
}
}
function isServerAvailable() {
if (typeof serverState !== 'object') {
return false
}
switch (serverState.status) {
case 'LoadingModel':
case 'Rendering':
case 'Online':
return true
default:
return false
}
}
function logMsg(msg, level, outputMsg) {
if (outputMsg.hasChildNodes()) {
outputMsg.appendChild(document.createElement('br'))
}
if (level === 'error') {
outputMsg.innerHTML += 'Error: ' + msg + ''
} else if (level === 'warn') {
outputMsg.innerHTML += 'Warning: ' + msg + ''
} else {
outputMsg.innerText += msg
}
console.log(level, msg)
}
function logError(msg, res, outputMsg) {
logMsg(msg, 'error', outputMsg)
console.log('request error', res)
setStatus('request', 'error', 'error')
}
function playSound() {
const audio = new Audio('/media/ding.mp3')
audio.volume = 0.2
var promise = audio.play()
if (promise !== undefined) {
promise.then(_ => {}).catch(error => {
console.warn("browser blocked autoplay")
})
}
}
function setSystemInfo(devices) {
let cpu = devices.all.cpu
let allGPUs = Object.keys(devices.all).filter(d => d != 'cpu')
let activeGPUs = Object.keys(devices.active)
allGPUs = allGPUs.map(d => devices.all[d])
activeGPUs = activeGPUs.map(d => devices.all[d]).map(d => `${d}
`)
let systemInfo = `
${cpu} | |
${allGPUs.join('')} | |
${activeGPUs.join('')} |
StepUpdate: ${JSON.stringify(stepUpdate, undefined, 4)}` } logError(msg, res, outputMsg) return false } if (typeof stepUpdate !== 'object' || !res || res.status != 200) { if (!isServerAvailable()) { logError("Stable Diffusion is still starting up, please wait. If this goes on beyond a few minutes, Stable Diffusion has probably crashed. Please check the error message in the command-line window.", res, outputMsg) } else if (typeof res === 'object') { let msg = 'Stable Diffusion had an error reading the response: ' try { // 'Response': body stream already read msg += 'Read: ' + await res.text() } catch(e) { msg += 'Unexpected end of stream. ' } if (finalJSON) { msg += 'Buffered data: ' + finalJSON } logError(msg, res, outputMsg) } else { let msg = `Unexpected Read Error:
Response: ${res}` logError(msg, res, outputMsg) } return false } showImages(reqBody, stepUpdate, outputContainer, false) } catch (e) { console.log('request error', e) logError('Stable Diffusion had an error. Please check the logs in the command-line window.
StepUpdate: ${typeof stepUpdate === 'object' ? JSON.stringify(stepUpdate, undefined, 4) : stepUpdate}
' + e.stack + '', res, outputMsg) setStatus('request', 'error', 'error') return false } return true } async function checkTasks() { if (taskQueue.length === 0) { setStatus('request', 'done', 'success') setTimeout(checkTasks, 500) stopImageBtn.style.display = 'none' renameMakeImageButton() currentTask = null if (bellPending) { if (isSoundEnabled()) { playSound() } bellPending = false } return } setStatus('request', 'fetching..') stopImageBtn.style.display = 'block' renameMakeImageButton() bellPending = true previewTools.style.display = 'block' let task = taskQueue.pop() currentTask = task let time = Date.now() let successCount = 0 task.isProcessing = true task['stopTask'].innerHTML = ' Stop' task['taskStatusLabel'].innerText = "Starting" task['taskStatusLabel'].classList.add('waitingTaskLabel') const genSeeds = Boolean(typeof task.reqBody.seed !== 'number' || (task.reqBody.seed === task.seed && task.numOutputsTotal > 1)) const startSeed = task.reqBody.seed || task.seed for (let i = 0; i < task.batchCount; i++) { let newTask = task if (task.batchCount > 1) { // Each output render batch needs it's own task instance to avoid altering the other runs after they are completed. newTask = Object.assign({}, task, { reqBody: Object.assign({}, task.reqBody) }) } if (genSeeds) { newTask.reqBody.seed = parseInt(startSeed) + (i * newTask.reqBody.num_outputs) newTask.seed = newTask.reqBody.seed } else if (newTask.seed !== newTask.reqBody.seed) { newTask.seed = newTask.reqBody.seed } let success = await doMakeImage(newTask) task.batchesDone++ if (!task.isProcessing || !success) { break } if (success) { successCount++ } } task.isProcessing = false task['stopTask'].innerHTML = ' Remove' task['taskStatusLabel'].style.display = 'none' time = Date.now() - time time /= 1000 if (successCount === task.batchCount) { task.outputMsg.innerText = 'Processed ' + task.numOutputsTotal + ' images in ' + time + ' seconds' task.progressBar.style.height = "0px" task.progressBar.style.border = "0px solid var(--background-color3)" task.progressBar.classList.remove("active") // setStatus('request', 'done', 'success') } else { if (task.outputMsg.innerText.toLowerCase().indexOf('error') === -1) { task.outputMsg.innerText = 'Task ended after ' + time + ' seconds' } } if (randomSeedField.checked) { seedField.value = task.seed } currentTask = null if (typeof requestIdleCallback === 'function') { requestIdleCallback(checkTasks, { timeout: 30 * 1000 }) } else { setTimeout(checkTasks, 500) } } if (typeof requestIdleCallback === 'function') { requestIdleCallback(checkTasks, { timeout: 30 * 1000 }) } else { setTimeout(checkTasks, 10) } function getCurrentUserRequest() { const numOutputsTotal = parseInt(numOutputsTotalField.value) const numOutputsParallel = parseInt(numOutputsParallelField.value) const seed = (randomSeedField.checked ? Math.floor(Math.random() * 10000000) : parseInt(seedField.value)) const newTask = { isProcessing: false, stopped: false, batchesDone: 0, numOutputsTotal: numOutputsTotal, batchCount: Math.ceil(numOutputsTotal / numOutputsParallel), seed, reqBody: { session_id: sessionId, seed, negative_prompt: negativePromptField.value.trim(), num_outputs: numOutputsParallel, num_inference_steps: numInferenceStepsField.value, guidance_scale: guidanceScaleField.value, width: widthField.value, height: heightField.value, // allow_nsfw: allowNSFWField.checked, turbo: turboField.checked, render_device: getCurrentRenderDeviceSelection(), use_full_precision: useFullPrecisionField.checked, use_stable_diffusion_model: stableDiffusionModelField.value, use_vae_model: vaeModelField.value, stream_progress_updates: true, stream_image_progress: (numOutputsTotal > 50 ? false : streamImageProgressField.checked), show_only_filtered_image: showOnlyFilteredImageField.checked, output_format: outputFormatField.value } } if (IMAGE_REGEX.test(initImagePreview.src)) { newTask.reqBody.init_image = initImagePreview.src newTask.reqBody.prompt_strength = promptStrengthField.value // if (IMAGE_REGEX.test(maskImagePreview.src)) { // newTask.reqBody.mask = maskImagePreview.src // } if (maskSetting.checked) { newTask.reqBody.mask = inpaintingEditor.getImg() } newTask.reqBody.sampler = 'ddim' } else { newTask.reqBody.sampler = samplerField.value } if (saveToDiskField.checked && diskPathField.value.trim() !== '') { newTask.reqBody.save_to_disk_path = diskPathField.value.trim() } if (useFaceCorrectionField.checked) { newTask.reqBody.use_face_correction = 'GFPGANv1.3' } if (useUpscalingField.checked) { newTask.reqBody.use_upscale = upscaleModelField.value } return newTask } function getCurrentRenderDeviceSelection() { let selectedGPUs = $('#use_gpus').val() if (useCPUField.checked && !autoPickGPUsField.checked) { return 'cpu' } if (autoPickGPUsField.checked || selectedGPUs.length == 0) { return 'auto' } return selectedGPUs.join(',') } function makeImage() { if (!isServerAvailable()) { alert('The server is not available.') return } const taskTemplate = getCurrentUserRequest() const newTaskRequests = [] getPrompts().forEach((prompt) => newTaskRequests.push(Object.assign({}, taskTemplate, { reqBody: Object.assign({ prompt: prompt }, taskTemplate.reqBody) }))) newTaskRequests.forEach(createTask) initialText.style.display = 'none' } function createTask(task) { let taskConfig = `Seed: ${task.seed}, Sampler: ${task.reqBody.sampler}, Inference Steps: ${task.reqBody.num_inference_steps}, Guidance Scale: ${task.reqBody.guidance_scale}, Model: ${task.reqBody.use_stable_diffusion_model}` if (task.reqBody.use_vae_model.trim() !== '') { taskConfig += `, VAE: ${task.reqBody.use_vae_model}` } if (task.reqBody.negative_prompt.trim() !== '') { taskConfig += `, Negative Prompt: ${task.reqBody.negative_prompt}` } if (task.reqBody.init_image !== undefined) { taskConfig += `, Prompt Strength: ${task.reqBody.prompt_strength}` } if (task.reqBody.use_face_correction) { taskConfig += `, Fix Faces: ${task.reqBody.use_face_correction}` } if (task.reqBody.use_upscale) { taskConfig += `, Upscale: ${task.reqBody.use_upscale}` } let taskEntry = document.createElement('div') taskEntry.className = 'imageTaskContainer' taskEntry.innerHTML = `