Compare commits

..

17 Commits
v1.1 ... v1.21

Author SHA1 Message Date
66d809e9ed Update screenshots with the new port 9000 2022-08-26 21:41:20 +05:30
1bd812a2cf Add a note about using ./server commands instead of docker-compose directly 2022-08-26 21:14:23 +05:30
96e4a4ae03 Switch to port 9000, and post a redirection notice at port 8000. This avoids a port conflicts since port 8000 is often used by other servers, and hopefully avoids a common source of new-user issues in the future 2022-08-26 21:04:55 +05:30
f526b2df94 Update screenshot for img2img and masking 2022-08-26 19:55:04 +05:30
a2a4b32f7b Screenshot showing img2img and masking 2022-08-26 19:53:10 +05:30
cb914ea77f Add new screenshots 2022-08-26 19:51:31 +05:30
e1bbc2876d Executable server 2022-08-26 19:35:21 +05:30
3bcde36821 Wrap the server operations in a single 'server' command. This will help manage the underlying engine better in the future 2022-08-26 19:33:32 +05:30
716ba93787 Inpainting/mask usage 2022-08-26 19:04:04 +05:30
34e6fee4e7 Merge branch 'main' of github.com:cmdr2/stable-diffusion-ui 2022-08-26 18:56:45 +05:30
3de2383505 Image masking support 2022-08-26 18:56:34 +05:30
5c8c9d3bac Update README.md 2022-08-26 07:53:03 +05:30
e45d1d42a8 Update README.md 2022-08-26 07:29:08 +05:30
252900356f Update README.md 2022-08-26 07:24:57 +05:30
8edce9fe36 Update README.md 2022-08-26 07:24:38 +05:30
e8fd6845c8 Reorganize usage notes for img2img 2022-08-26 07:15:19 +05:30
946505cc0e Tweak usage notes for img2img 2022-08-26 07:06:50 +05:30
12 changed files with 193 additions and 24 deletions

View File

@ -10,6 +10,6 @@ RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
EXPOSE 9000
ENTRYPOINT ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0"]
ENTRYPOINT ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "9000"]

15
OldPortDockerfile Normal file
View File

@ -0,0 +1,15 @@
FROM python:3.9
RUN mkdir /app
WORKDIR /app
RUN apt update
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
ENTRYPOINT ["uvicorn", "old_port_main:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@ -1,15 +1,22 @@
A simple way to install and use [Stable Diffusion](https://replicate.com/stability-ai/stable-diffusion) on your local computer. Provides a browser UI for generating images from text prompts. Just enter your text prompt, and see the generated image.
# Stable Diffusion UI
### A simple way to install and use [Stable Diffusion](https://replicate.com/stability-ai/stable-diffusion) on your own computer
🎉 **New!** `img2img` is now supported! You can provide an image to generate new images based on it (and an optional text prompt). You can also use the generated image as the new input image in 1-click, to refine it further.
---
🎉 **New!** `img2img` and `inpaint` (masking) are now supported! You can provide an image to generate new images based on it (and an optional text prompt). You can also use the generated image as the new input image in 1-click, to refine it further. (Thanks [Andreas](https://github.com/andreasjansson)!)
# What does this do?
Two things:
1. Automatically downloads and installs Stable Diffusion on your local computer (no need to mess with conda or environments)
1. Automatically downloads and installs Stable Diffusion on your own computer (no need to mess with conda or environments)
2. Gives you a simple browser-based UI to talk to your local Stable Diffusion. Enter text prompts and view the generated image. No API keys required.
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 computer locally, it does not transmit your prompts or process on any remote server.
<p float="left">
<img src="https://github.com/cmdr2/stable-diffusion-ui/raw/main/media/shot-v3a.jpg" height="500" />
<img src="https://github.com/cmdr2/stable-diffusion-ui/raw/main/media/shot-v6a.jpg" height="500" />
</p>
<img src="https://github.com/cmdr2/stable-diffusion-ui/raw/main/media/shot-v4.jpg" height="500" alt="Screenshot of tool">
# System Requirements
1. Computer capable of running Stable Diffusion.
@ -20,23 +27,34 @@ All the processing will happen on your local computer, it does not transmit your
# Installation
1. Clone this repository: `git clone https://github.com/cmdr2/stable-diffusion-ui.git` or [download the zip file](https://github.com/cmdr2/stable-diffusion-ui/archive/refs/heads/main.zip) and unzip.
2. Open your terminal, and in the project directory run: `docker-compose up &` (warning: this will take some time during the first run, since it'll download Stable Diffusion's [docker image](https://replicate.com/stability-ai/stable-diffusion), nearly 17 GiB)
3. Open http://localhost:8000 in your browser. That's it!
2. Open your terminal, and in the project directory run: `./server` (warning: this will take some time during the first run, since it'll download Stable Diffusion's [docker image](https://replicate.com/stability-ai/stable-diffusion), nearly 17 GiB)
3. Open http://localhost:9000 in your browser. That's it!
If you're getting errors, please check the [Troubleshooting](#troubleshooting) section below.
To stop the server, please run `./server stop`
# Usage
1. Open http://localhost:8000 in your browser (after running `docker-compose up &` from step 2 previously).
2. Enter a text prompt, like `a photograph of an astronaut riding a horse` in the textbox.
3. Press `Make Image`. This will take some time, depending on your system's processing power.
4. See the image generated using your prompt.
5. **New!** img2img: You can also choose an `initial image`, to generate an image based on that. An optional text prompt can help you refine this image.
Open http://localhost:9000 in your browser (after running `./server` from step 2 previously).
## With a text description
1. Enter a text prompt, like `a photograph of an astronaut riding a horse` in the textbox.
2. Press `Make Image`. This will take some time, depending on your system's processing power.
3. See the image generated using your prompt.
## With an image
1. Click `Browse..` next to `Initial Image`. Select your desired image.
2. An optional text prompt can help you further describe the kind of image you want to generate.
3. Press `Make Image`. See the image generated using your prompt.
You can also set an `Image Mask` for telling Stable Diffusion to draw in only the black areas in your image mask. White areas in your mask will be ignored.
**Pro tip:** You can also click `Use as Input` on a generated image, to use it as the input image for your next generation. This can be useful for sequentially refining the generated image with a single click.
Please [file an issue](https://github.com/cmdr2/stable-diffusion-ui/issues) if this did not work for you (after trying the common [troubleshooting](#troubleshooting) steps)!
**Another tip:** Images with the same aspect ratio of your generated image work best. E.g. 1:1 if you're generating images sized 512x512.
To stop the server, please run `docker-compose down`
## Problems?
Please [file an issue](https://github.com/cmdr2/stable-diffusion-ui/issues) if this did not work for you (after trying the common [troubleshooting](#troubleshooting) steps)!
# 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'.
@ -55,10 +73,10 @@ Please ensure you have `docker-compose` version 1.29 or higher. Check `docker-co
## RuntimeError: Found no NVIDIA driver on your system:
If you have an NVIDIA GPU and the latest [NVIDIA driver](http://www.nvidia.com/Download/index.aspx), please ensure that you've installed [nvidia-container-toolkit](https://stackoverflow.com/a/58432877). (Thanks [u/exintrovert420](https://www.reddit.com/user/exintrovert420/))
## Some other process is already running at port 8000 / port 8000 could not be bound
You can override the port used. Please change `docker-compose.yml` inside the project directory, and update the line `8000:8000` to `1337:8000` (or where 1337 is whichever port number you want).
## Some other process is already running at port 9000 / port 9000 could not be bound
You can override the port used. Please change `docker-compose.yml` inside the project directory, and update the line `9000:9000` to `1337:9000` (where 1337 is whichever port number you want).
After doing this, please restart your server, by running `docker-compose down` and then `docker-compose up &`.
After doing this, please restart your server, by running `./server restart`.
After this, you can access the server at `http://localhost:1337` (where 1337 is the new port you specified earlier).

View File

@ -15,7 +15,7 @@ services:
stable-diffusion-ui:
container_name: sd-ui
ports:
- '8000:8000'
- '9000:9000'
build:
context: .
dockerfile: Dockerfile
@ -24,5 +24,15 @@ services:
depends_on:
- stability-ai
stable-diffusion-old-port-redirect:
container_name: sd-old-port-redirect
ports:
- '8000:8000'
build:
context: .
dockerfile: OldPortDockerfile
volumes:
- .:/app
networks:
default:

View File

@ -30,10 +30,10 @@
width: 95%;
}
}
#init_image_preview_container {
.image_preview_container {
display: none;
}
#init_image_clear {
.image_clear_btn {
position: absolute;
transform: translateX(-50%);
background: black;
@ -87,9 +87,17 @@
<textarea id="prompt">a photograph of an astronaut riding a horse</textarea><br/>
<label for="init_image"><b>Initial Image:</b> (optional) </label> <input id="init_image" name="init_image" type="file" /> </button><br/>
<div id="init_image_preview_container">
<div id="init_image_preview_container" class="image_preview_container">
<img id="init_image_preview" src="" width="100" height="100" />
<button id="init_image_clear">X</button>
<button id="init_image_clear" class="image_clear_btn">X</button>
</div><br/>
<div id="mask_setting">
<label for="mask"><b>Image Mask:</b> (optional) </label> <input id="mask" name="mask" type="file" /> </button><br/>
<div id="mask_preview_container" class="image_preview_container">
<img id="mask_preview" src="" width="100" height="100" />
<button id="mask_clear" class="image_clear_btn">X</button>
</div>
</div>
<div id="configHeader"><b>Advanced settings:</b> [<a id="configToggleBtn" href="#">show</a>]</div>
@ -133,6 +141,8 @@ let widthField = document.querySelector('#width')
let heightField = document.querySelector('#height')
let initImageSelector = document.querySelector("#init_image")
let initImagePreview = document.querySelector("#init_image_preview")
let maskImageSelector = document.querySelector("#mask")
let maskImagePreview = document.querySelector("#mask_preview")
let promptStrengthField = document.querySelector('#prompt_strength')
let promptStrengthValueLabel = document.querySelector('#prompt_strength_value')
@ -143,6 +153,10 @@ let initImagePreviewContainer = document.querySelector('#init_image_preview_cont
let initImageClearBtn = document.querySelector('#init_image_clear')
let promptStrengthContainer = document.querySelector('#prompt_strength_container')
let maskSetting = document.querySelector('#mask_setting')
let maskImagePreviewContainer = document.querySelector('#mask_preview_container')
let maskImageClearBtn = document.querySelector('#mask_clear')
let showConfigToggle = document.querySelector('#configToggleBtn')
let configBox = document.querySelector('#config')
let outputMsg = document.querySelector('#outputMsg')
@ -229,6 +243,10 @@ async function makeImage() {
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
}
}
let res = ''
@ -321,6 +339,8 @@ async function makeImage() {
initImagePreviewContainer.style.display = 'block'
promptStrengthContainer.style.display = 'block'
maskSetting.style.display = 'block'
randomSeedField.checked = false
seedField.value = seed
seedField.disabled = false
@ -380,6 +400,7 @@ function showInitImagePreview() {
if (initImageSelector.files.length === 0) {
initImagePreviewContainer.style.display = 'none'
promptStrengthContainer.style.display = 'none'
maskSetting.style.display = 'none'
return
}
@ -391,6 +412,8 @@ function showInitImagePreview() {
initImagePreview.src = reader.result
initImagePreviewContainer.style.display = 'block'
promptStrengthContainer.style.display = 'block'
maskSetting.style.display = 'block'
})
if (file) {
@ -402,11 +425,46 @@ showInitImagePreview()
initImageClearBtn.addEventListener('click', function() {
initImageSelector.value = null
maskImageSelector.value = null
initImagePreview.src = ''
maskImagePreview.src = ''
initImagePreviewContainer.style.display = 'none'
maskImagePreviewContainer.style.display = 'none'
maskSetting.style.display = 'none'
promptStrengthContainer.style.display = 'none'
})
function showMaskImagePreview() {
if (maskImageSelector.files.length === 0) {
maskImagePreviewContainer.style.display = 'none'
return
}
let reader = new FileReader()
let file = maskImageSelector.files[0]
reader.addEventListener('load', function() {
maskImagePreview.src = reader.result
maskImagePreviewContainer.style.display = 'block'
})
if (file) {
reader.readAsDataURL(file)
}
}
maskImageSelector.addEventListener('change', showMaskImagePreview)
showMaskImagePreview()
maskImageClearBtn.addEventListener('click', function() {
maskImageSelector.value = null
maskImagePreview.src = ''
maskImagePreviewContainer.style.display = 'none'
})
setInterval(healthCheck, HEALTH_PING_INTERVAL * 1000)
</script>

View File

@ -13,6 +13,7 @@ app = FastAPI()
class ImageRequest(BaseModel):
prompt: str
init_image: str = None # base64
mask: str = None # base64
num_outputs: str = "1"
num_inference_steps: str = "50"
guidance_scale: str = "7.5"
@ -51,6 +52,9 @@ async def image(req : ImageRequest):
data['input']['init_image'] = req.init_image
data['input']['prompt_strength'] = req.prompt_strength
if req.mask is not None:
data['input']['mask'] = req.mask
if req.seed == "-1":
del data['input']['seed']

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

BIN
media/shot-v3a.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

BIN
media/shot-v6a.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

38
old_port_main.py Normal file
View File

@ -0,0 +1,38 @@
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get('/', response_class=HTMLResponse)
def read_root():
return '''
<style>
body {
font-family: Arial;
font-size: 11pt;
}
pre {
display: inline;
background: #aaa;
padding: 2px;
border: 1px solid #777;
border-radius: 3px;
}
@media (prefers-color-scheme: dark) {
body {
background-color: rgb(32, 33, 36);
color: #eee;
}
pre {
background: #444;
}
}
</style>
<h4>The UI has moved to <a href="http://localhost:9000">http://localhost:9000</a>. The current address that you used (ending with :8000) will be removed in the future, so please use <a href="http://localhost:9000">http://localhost:9000</a> going ahead (and in any bookmarks you've saved).</h4>
<h4>Also, please use <pre>./server</pre> instead of <pre>docker-compose up &amp;</pre>. To stop, please use <pre>./server stop</pre>. This will help the project better manage the startup process in the future.</h4>
<h3>Why has the address changed?</h3>
<p>The previously used port (8000) is often used by other servers, which results in port conflicts. So the project's port number has been changed, while the project is still young. Otherwise port-conflicts with 8000 will be a common source of new-user issues in the future.</p>
<p>Sorry about this, and apologies for the inconvenience :)</p>
'''

26
server Executable file
View File

@ -0,0 +1,26 @@
#!/bin/bash
CMD="$1"
if [ -z "$1" ]; then
CMD="start"
fi
start_server() {
docker-compose up -d stable-diffusion-old-port-redirect > /dev/null 2>&1 # old port 8000 server, show redirect notice
docker-compose up stability-ai stable-diffusion-ui &
}
stop_server() {
docker-compose down
}
if [ "$CMD" == "start" ]; then
start_server
elif [ "$CMD" == "stop" ]; then
stop_server
elif [ "$CMD" == "restart" ]; then
stop_server
start_server
else
echo "Unknown option: $1 (Expected start or stop)"
fi