forked from extern/easydiffusion
263 lines
8.3 KiB
HTML
263 lines
8.3 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="https://github.com/cmdr2/stable-diffusion-ui/issues" target="_blank">file an issue</a> or <a href="mailto:sd@cmdr2.org" target="_blank">email me</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('/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')
|
|
}
|
|
}
|
|
|
|
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.", 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> |