diff --git a/index.html b/index.html index e4cbc816..a7ee3098 100644 --- a/index.html +++ b/index.html @@ -66,16 +66,29 @@ padding-top: 10px; font-size: small; } - .imgUseBtn { + .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: 30pt; + margin-top: 55pt; margin-left: -5pt; } .imgItem { @@ -108,11 +121,11 @@
Advanced settings: [show]
-
-
+
+


-
+




@@ -137,7 +150,8 @@ const SOUND_ENABLED_KEY = "soundEnabled" const HEALTH_PING_INTERVAL = 5 // seconds let promptField = document.querySelector('#prompt') -let numOutputsField = document.querySelector('#num_outputs') +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') @@ -199,6 +213,12 @@ function setStatus(statusType, msg, msgType) { } } +function logError(msg, res) { + outputMsg.innerHTML = 'Error: ' + msg + '' + console.log('request error', res) + setStatus('request', 'error', 'error') +} + function playSound() { const audio = new Audio('/media/ding.mp3') audio.volume = 0.2 @@ -220,43 +240,10 @@ async function healthCheck() { } } -async function makeImage() { - setStatus('request', 'fetching..') - - makeImageBtn.innerHTML = 'Processing..' - makeImageBtn.disabled = true - - outputMsg.innerHTML = 'Fetching..' - - function logError(msg, res) { - outputMsg.innerHTML = 'Error: ' + msg + '' - console.log('request error', res) - setStatus('request', 'error', 'error') - } - - let seed = (randomSeedField.checked ? Math.floor(Math.random() * 10000) : seedField.value) - - let reqBody = { - prompt: promptField.value, - num_outputs: numOutputsField.value, - num_inference_steps: numInferenceStepsField.value, - guidance_scale: guidanceScaleField.value / 10, - width: widthField.value, - height: heightField.value, - seed: seed, - } - - if (initImagePreview.src.indexOf('data:image/png;base64') !== -1) { - reqBody['init_image'] = initImagePreview.src - reqBody['prompt_strength'] = promptStrengthField.value / 10 - - if (maskImagePreview.src.indexOf('data:image/png;base64') !== -1) { - reqBody['mask'] = maskImagePreview.src - } - } - +// makes a single image. don't call this directly, use makeImage() instead +async function doMakeImage(reqBody) { let res = '' - let time = new Date().getTime() + let seed = reqBody['seed'] try { res = await fetch('/image', { @@ -293,24 +280,10 @@ async function makeImage() { setStatus('request', 'error', 'error') } - makeImageBtn.innerHTML = 'Make Image' - makeImageBtn.disabled = false - - if (isSoundEnabled()) { - playSound() - } - if (!res) { return } - time = new Date().getTime() - time - time /= 1000 - - outputMsg.innerHTML = 'Processed in ' + time + ' seconds. Seed: ' + seed - - imagesContainer.innerHTML = '' - for (let idx in res.output) { let imgBody = '' @@ -319,7 +292,7 @@ async function makeImage() { } catch (e) { console.log(imgBody) setStatus('request', 'invalid image', 'error') - return + continue } let imgItem = document.createElement('div') @@ -330,6 +303,10 @@ async function makeImage() { img.height = parseInt(reqBody.height) img.src = imgBody + 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' @@ -339,6 +316,7 @@ async function makeImage() { imgSaveBtn.innerHTML = 'Download' imgItem.appendChild(img) + imgItem.appendChild(imgSeedLabel) imgItem.appendChild(imgUseBtn) imgItem.appendChild(imgSaveBtn) imagesContainer.appendChild(imgItem) @@ -364,6 +342,62 @@ async function makeImage() { imgDownload.click() }) } +} + +async function makeImage() { + setStatus('request', 'fetching..') + + makeImageBtn.innerHTML = 'Processing..' + makeImageBtn.disabled = true + + outputMsg.innerHTML = 'Fetching..' + + let seed = (randomSeedField.checked ? Math.floor(Math.random() * 10000) : parseInt(seedField.value)) + let numOutputsTotal = parseInt(numOutputsTotalField.value) + let numOutputsParallel = parseInt(numOutputsParallelField.value) + let batchCount = Math.ceil(numOutputsTotal / numOutputsParallel) + let batchSize = numOutputsParallel + + let reqBody = { + prompt: promptField.value, + num_outputs: batchSize, + num_inference_steps: numInferenceStepsField.value, + guidance_scale: parseInt(guidanceScaleField.value) / 10, + width: widthField.value, + height: heightField.value, + } + + if (initImagePreview.src.indexOf('data:image/png;base64') !== -1) { + reqBody['init_image'] = initImagePreview.src + reqBody['prompt_strength'] = parseInt(promptStrengthField.value) / 10 + + if (maskImagePreview.src.indexOf('data:image/png;base64') !== -1) { + reqBody['mask'] = maskImagePreview.src + } + } + + let time = new Date().getTime() + imagesContainer.innerHTML = '' + + for (let i = 0; i < batchCount; i++) { + reqBody['seed'] = seed + i + + await doMakeImage(reqBody) + + outputMsg.innerHTML = 'Processed batch ' + (i+1) + '/' + batchCount + } + + makeImageBtn.innerHTML = 'Make Image' + makeImageBtn.disabled = false + + if (isSoundEnabled()) { + playSound() + } + + time = new Date().getTime() - time + time /= 1000 + + outputMsg.innerHTML = 'Processed ' + numOutputsTotal + ' images in ' + time + ' seconds' setStatus('request', 'done', 'success')