Initial commit

This commit is contained in:
cmdr2 2022-08-24 01:58:18 +05:30
commit 4fbd3479f3
8 changed files with 249 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 cmdr2
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

28
README.md Normal file
View File

@ -0,0 +1,28 @@
A simple browser UI for generating images from text prompts, using [Stable Diffusion](https://replicate.com/stability-ai/stable-diffusion). Designed for running locally on your computer.
This project runs Stable Diffusion in a docker container behind the scenes, using Stable Diffusion's official Docker image on replicate.com.
![Screenshot of tool](shot1.jpeg?raw=true)
# System Requirements
1. Requires `docker` and `python3.6` (or higher).
2. Linux or Windows 11 (with WSL) or macOS. Basically if your system can run [Stable Diffusion](https://replicate.com/stability-ai/stable-diffusion).
# Installation
1. Download [Quick UI](https://github.com/cmdr2/stable-diffusion-ui/archive/refs/heads/main.zip)
2. Unzip: `unzip main.zip`
3. Enter: `cd stable-diffusion-ui`
4. Install dependencies: `pip install fastapi uvicorn` (this is the framework and server used by QuickUI)
5. Run: `./server.sh`
6. Open `http://localhost:8000` in your browser
# Usage
1. Open `http://localhost:8000` in your browser
2. Enter a text prompt, like `a photograph of an astronaut riding a horse` in the textbox.
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.
# Bugs reports and code contributions welcome
This was built in a few hours for fun. So if there are any problems, please feel free to file an issue.
Also, if you have any code contributions, please feel to submit a pull request.

BIN
ding.mp3 Normal file

Binary file not shown.

150
index.html Normal file
View File

@ -0,0 +1,150 @@
<!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%;
}
}
#image {
width: 512px;
height: 512px;
}
#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/>
<button id="makeImage">Make Image</button> <br/><br/>
<img id="image" />
<div id="footer">
<p>Please feel free to <a href="mailto:sd@cmdr2.org">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
function setStatus(statusType, msg, msgType) {
let el = ''
if (statusType === 'server') {
el = '#serverStatus'
} 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.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 prompt = document.querySelector('#prompt').value
let res = ''
try {
res = await fetch('/image', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: prompt,
width: 512,
height: 512
})
})
res = await res.json()
} catch (e) {
console.log('request error', e)
setStatus('request', 'error', 'error')
}
btn.innerHTML = 'Make Image'
btn.disabled = false;
playSound()
if (!res) {
return
}
let imgBody = ''
try {
imgBody = res.output[0]
} catch (e) {
console.log(imgBody)
setStatus('request', 'invalid image', 'error')
return
}
let img = document.querySelector('#image')
img.src = imgBody
setStatus('request', 'done', 'success')
}
document.querySelector('#makeImage').addEventListener('click', makeImage)
setInterval(healthCheck, HEALTH_PING_INTERVAL * 1000)
</script>
</html>

42
main.py Normal file
View File

@ -0,0 +1,42 @@
from fastapi import FastAPI
from starlette.responses import FileResponse
from pydantic import BaseModel
import requests
LOCAL_SERVER_URL = 'http://localhost:5000'
PREDICT_URL = LOCAL_SERVER_URL + '/predictions'
app = FastAPI()
class ImageRequest(BaseModel):
prompt: str
width: int = 512
height: int = 512
@app.get('/')
def read_root():
return FileResponse('index.html')
@app.get('/ping')
async def ping():
try:
requests.get(LOCAL_SERVER_URL)
return {'OK'}
except:
return {'ERROR'}
@app.post('/image')
async def image(req : ImageRequest):
res = requests.post(PREDICT_URL, json={
"input": {
"prompt": req.prompt,
"width": str(req.width),
"height": str(req.height),
}
})
return res.json()
@app.get('/ding.mp3')
def read_root():
return FileResponse('ding.mp3')

7
server.sh Normal file
View File

@ -0,0 +1,7 @@
#!/bin/bash
IMAGE_NAME="r8.im/stability-ai/stable-diffusion@sha256:06eb78b36068500c616a7f33c15e6fa40404f8e14b5bfad57ebe0c7fe0f6bdf1"
docker run --name sd -d -p 5000:5000 --gpus all $IMAGE_NAME
uvicorn main:app --reload

BIN
shot1.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB