easydiffusion/index.html

263 lines
8.4 KiB
HTML

<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 11pt;
}
#prompt {
width: 50vw;
height: 50pt;
}
@media screen and (max-width: 600px) {
#prompt {
width: 95%;
}
}
#configHeader {
margin-top: 5px;
margin-bottom: 5px;
font-size: 10pt;
}
#config {
font-size: 9pt;
margin-bottom: 5px;
padding-left: 10px;
}
#outputMsg {
font-size: small;
}
#footer {
margin-top: 5px;
padding-top: 5px;
font-size: small;
}
</style>
</html>
<body>
<h3>Stable Diffusion - Quick UI</h3>
<div id="status">Server status: <span id="serverStatus">checking..</span> | Request status: <span id="reqStatus">n/a</span></div>
<br/>
<b>Prompt:</b><br/>
<textarea id="prompt">a photograph of an astronaut riding a horse</textarea><br/>
<div id="configHeader"><b>Advanced settings:</b> [<a id="configToggleBtn" href="#">show</a>]</div>
<div id="config">
<label for="seed">Seed:</label> <input id="seed" name="seed" value="30000"> <input id="random_seed" name="random_seed" type="checkbox" checked> <label for="random_seed">Random Image</label> <br/>
<label for="num_outputs">Number of outputs:</label> <select id="num_outputs" name="num_outputs" value="1"><option value="1" selected>1</option><option value="4">4</option></select><br/>
<label for="width">Width:</label> <select id="width" name="width" value="512"><option value="128">128</option><option value="256">256</option><option value="512" selected>512</option><option value="768">768</option><option value="1024">1024</option></select><br/>
<label for="height">Height:</label> <select id="height" name="height" value="512"><option value="128">128</option><option value="256">256</option><option value="512" selected>512</option><option value="768">768</option></select><br/>
<label for="num_inference_steps">Number of inference steps:</label> <input id="num_inference_steps" name="num_inference_steps" value="50"><br/>
<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></span><br/>
</div>
<button id="makeImage">Make Image</button> <br/><br/>
<div id="outputMsg"></div>
<div id="images"></div>
<div id="footer">
<p>Please feel free to <a href="mailto:sd@cmdr2.org" target="_blank">email me</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>
<p><b>Disclaimer:</b> I am not responsible for any images generated using this interface.</p>
</div>
</body>
<script>
const HEALTH_PING_INTERVAL = 5 // seconds
let serverStatus = 'offline'
function setStatus(statusType, msg, msgType) {
let el = ''
if (statusType === 'server') {
el = '#serverStatus'
serverStatus = msg
} else if (statusType === 'request') {
el = '#reqStatus'
}
if (msgType == 'error') {
msg = '<span style="color: red">' + msg + '<span>'
} else if (msgType == 'success') {
msg = '<span style="color: green">' + msg + '<span>'
}
if (el) {
document.querySelector(el).innerHTML = msg
}
}
function playSound() {
const audio = new Audio('/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')
}
}
async function makeImage() {
setStatus('request', 'fetching..')
let btn = document.querySelector('#makeImage')
btn.innerHTML = 'Processing..'
btn.disabled = true;
let outputMsg = document.querySelector('#outputMsg')
outputMsg.innerHTML = 'Fetching..'
function logError(msg, res) {
outputMsg.innerHTML = '<span style="color: red">Error: ' + msg + '</span>'
console.log('request error', res)
setStatus('request', 'error', 'error')
}
let random_seed = document.querySelector("#random_seed")
let seed = (random_seed.checked ? Math.floor(Math.random() * 10000) : document.querySelector('#seed').value)
let reqBody = {
prompt: document.querySelector('#prompt').value,
num_outputs: document.querySelector('#num_outputs').value,
num_inference_steps: document.querySelector('#num_inference_steps').value,
guidance_scale: document.querySelector('#guidance_scale').value / 10,
width: document.querySelector('#width').value,
height: document.querySelector('#height').value,
seed: seed,
}
let res = ''
let time = new Date().getTime()
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. Please check the logs in your command line.", res)
}
res = undefined
} else {
res = await res.json()
if (res.status !== 'succeeded') {
let msg = ''
if (res.detail !== undefined) {
msg = res.detail[0].msg + " in " + JSON.stringify(res.detail[0].loc)
} else {
msg = res
}
logError(msg, res)
res = undefined
}
}
} catch (e) {
console.log('request error', e)
setStatus('request', 'error', 'error')
}
btn.innerHTML = 'Make Image'
btn.disabled = false;
playSound()
if (!res) {
return
}
time = new Date().getTime() - time
time /= 1000
outputMsg.innerHTML = 'Processed in ' + time + ' seconds. Seed: ' + seed
let images = document.querySelector('#images')
images.innerHTML = ''
for (let idx in res.output) {
let imgBody = ''
try {
imgBody = res.output[idx]
} catch (e) {
console.log(imgBody)
setStatus('request', 'invalid image', 'error')
return
}
let img = document.createElement('img')
img.width = parseInt(reqBody.width)
img.height = parseInt(reqBody.height)
img.src = imgBody
images.appendChild(img)
}
setStatus('request', 'done', 'success')
if (random_seed.checked) {
let seedEl = document.querySelector("#seed")
seedEl.value = seed
}
}
document.querySelector('#makeImage').addEventListener('click', makeImage)
let config = document.querySelector('#config')
config.style.display = 'none'
document.querySelector('#configToggleBtn').addEventListener('click', function() {
config.style.display = (config.style.display === 'none' ? 'block' : 'none')
document.querySelector('#configToggleBtn').innerHTML = (config.style.display === 'none' ? 'show' : 'hide')
return false
})
let guidanceScale = document.querySelector('#guidance_scale')
function updateGuidanceScale() {
let label = document.querySelector('#guidance_scale_value')
label.innerHTML = guidanceScale.value / 10
}
guidanceScale.addEventListener('input', updateGuidanceScale)
updateGuidanceScale()
let random_seed = document.querySelector("#random_seed")
function checkRandomSeed() {
let seed = document.querySelector("#seed")
if (random_seed.checked) {
seed.disabled = true
seed.value = "random"
} else {
seed.disabled = false
}
}
random_seed.addEventListener('input', checkRandomSeed)
checkRandomSeed()
setInterval(healthCheck, HEALTH_PING_INTERVAL * 1000)
</script>
</html>