Allow configuring advanced settings like seed, width, height, num_outputs, num_inference_steps and guidance_scale

This commit is contained in:
cmdr2 2022-08-24 12:33:35 +05:30
parent 6dac5341db
commit 5d305c03e7
6 changed files with 111 additions and 27 deletions

View File

@ -7,7 +7,7 @@ Two things:
All the processing will happen on your local computer, it does not transmit your prompts or process on any remote server. All the processing will happen on your local computer, it does not transmit your prompts or process on any remote server.
![Screenshot of tool](shot.jpg?raw=true) ![Screenshot of tool](shot-v1.jpg?raw=true)
# System Requirements # System Requirements
1. Requires [Docker](https://docs.docker.com/engine/install/) and [Python](https://www.python.org/downloads/) (3.6 or higher). 1. Requires [Docker](https://docs.docker.com/engine/install/) and [Python](https://www.python.org/downloads/) (3.6 or higher).
@ -27,6 +27,13 @@ All the processing will happen on your local computer, it does not transmit your
3. Press `Make Image`. This will take a while, depending on your system's processing power. 3. Press `Make Image`. This will take a while, depending on your system's processing power.
4. See the image generated using your prompt. If there's an error, the status message at the top will show 'error' in red. 4. See the image generated using your prompt. If there's an error, the status message at the top will show 'error' in red.
# Advanced Settings
You can also set the configuration like `seed`, `width`, `height`, `num_outputs`, `num_inference_steps` and `guidance_scale` using the 'show' button next to 'Advanced settings'.
Use the same `seed` number to get the same image for a certain prompt. This is useful for refining a prompt without losing the basic image design. Use a seed of `-1` to get random images.
![Screenshot of advanced settings](config-v1.jpg?raw=true)
# Behind the scenes # Behind the scenes
This project is a quick way to get started with Stable Diffusion. You do not need to have Stable Diffusion already installed, and do not need any API keys. This project will automatically download Stable Diffusion's docker image, the first time it is run. This project is a quick way to get started with Stable Diffusion. You do not need to have Stable Diffusion already installed, and do not need any API keys. This project will automatically download Stable Diffusion's docker image, the first time it is run.

BIN
config-v1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -15,9 +15,18 @@
width: 95%; width: 95%;
} }
} }
#image { #configHeader {
width: 512px; margin-top: 5px;
height: 512px; margin-bottom: 5px;
font-size: 10pt;
}
#config {
font-size: 9pt;
margin-bottom: 5px;
padding-left: 10px;
}
#outputMsg {
font-size: small;
} }
#footer { #footer {
margin-top: 5px; margin-top: 5px;
@ -36,9 +45,21 @@
<b>Prompt:</b><br/> <b>Prompt:</b><br/>
<textarea id="prompt">a photograph of an astronaut riding a horse</textarea><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"> <small>(use -1 for random seed)</small><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="7.5"><br/>
</div>
<button id="makeImage">Make Image</button> <br/><br/> <button id="makeImage">Make Image</button> <br/><br/>
<img id="image" /> <div id="outputMsg"></div>
<div id="images"></div>
<div id="footer"> <div id="footer">
<p>Please feel free to <a href="https://github.com/cmdr2/stable-diffusion-ui/issues/new">file an issue</a> if you have any problems or suggestions in using this interface.</p> <p>Please feel free to <a href="https://github.com/cmdr2/stable-diffusion-ui/issues/new">file an issue</a> if you have any problems or suggestions in using this interface.</p>
@ -96,8 +117,19 @@ async function makeImage() {
btn.innerHTML = 'Processing..' btn.innerHTML = 'Processing..'
btn.disabled = true; btn.disabled = true;
let prompt = document.querySelector('#prompt').value let outputMsg = document.querySelector('#outputMsg')
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,
width: document.querySelector('#width').value,
height: document.querySelector('#height').value,
seed: document.querySelector('#seed').value,
}
let res = '' let res = ''
let time = new Date().getTime()
try { try {
res = await fetch('/image', { res = await fetch('/image', {
@ -105,13 +137,21 @@ async function makeImage() {
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify(reqBody)
prompt: prompt,
width: 512,
height: 512
})
}) })
res = await res.json() res = await res.json()
if (res.status !== 'succeeded') {
if (res.detail !== undefined) {
outputMsg.innerHTML = 'Error: ' + res.detail[0].msg + " in " + JSON.stringify(res.detail[0].loc)
} else {
outputMsg.innerHTML = 'Error: ' + res
}
outputMsg.innerHTML = '<span style="color: red">' + outputMsg.innerHTML + '</span>'
console.log('request error', res)
setStatus('request', 'error', 'error')
res = undefined
}
} catch (e) { } catch (e) {
console.log('request error', e) console.log('request error', e)
setStatus('request', 'error', 'error') setStatus('request', 'error', 'error')
@ -126,24 +166,47 @@ async function makeImage() {
return return
} }
let imgBody = '' time = new Date().getTime() - time
time /= 1000
try { outputMsg.innerHTML = 'Processed in ' + time + ' seconds'
imgBody = res.output[0]
} catch (e) { let images = document.querySelector('#images')
console.log(imgBody) images.innerHTML = ''
setStatus('request', 'invalid image', 'error')
return 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)
} }
let img = document.querySelector('#image')
img.src = imgBody
setStatus('request', 'done', 'success') setStatus('request', 'done', 'success')
} }
document.querySelector('#makeImage').addEventListener('click', makeImage) 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
})
setInterval(healthCheck, HEALTH_PING_INTERVAL * 1000) setInterval(healthCheck, HEALTH_PING_INTERVAL * 1000)
</script> </script>

26
main.py
View File

@ -9,10 +9,15 @@ PREDICT_URL = LOCAL_SERVER_URL + '/predictions'
app = FastAPI() app = FastAPI()
# defaults from https://huggingface.co/blog/stable_diffusion
class ImageRequest(BaseModel): class ImageRequest(BaseModel):
prompt: str prompt: str
width: int = 512 num_outputs: str = "1"
height: int = 512 num_inference_steps: str = "50"
guidance_scale: str = "7.5"
width: str = "512"
height: str = "512"
seed: str = "30000"
@app.get('/') @app.get('/')
def read_root(): def read_root():
@ -28,13 +33,22 @@ async def ping():
@app.post('/image') @app.post('/image')
async def image(req : ImageRequest): async def image(req : ImageRequest):
res = requests.post(PREDICT_URL, json={ data = {
"input": { "input": {
"prompt": req.prompt, "prompt": req.prompt,
"width": str(req.width), "num_outputs": req.num_outputs,
"height": str(req.height), "num_inference_steps": req.num_inference_steps,
"width": req.width,
"height": req.height,
"seed": req.seed,
} }
}) }
if req.seed == "-1":
del data['input']['seed']
res = requests.post(PREDICT_URL, json=data)
print(res)
return res.json() return res.json()
@app.get('/ding.mp3') @app.get('/ding.mp3')

BIN
shot-v1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
shot.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB