├── .circleci └── config.yml ├── .gitignore ├── .vscode └── settings.json ├── Dockerfile ├── README.md ├── app ├── __init__.py ├── api │ └── api.py ├── db │ └── models.py ├── main.py └── manager │ └── reqq.py ├── docker-compose.yml ├── install.sh ├── launch.sh ├── launch_sd.sh ├── requirements.txt └── test ├── __init__.py └── test.py /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | unit_test: 4 | docker: 5 | - image: circleci/python:3.6.1 6 | 7 | working_directory: ~/repo 8 | 9 | steps: 10 | - checkout 11 | 12 | # Download and cache dependencies 13 | - restore_cache: 14 | keys: 15 | - v1-dependencies-{{ checksum "requirements.txt" }} 16 | # fallback to using the latest cache if no exact match is found 17 | - v1-dependencies- 18 | 19 | - run: 20 | name: install dependencies 21 | command: | 22 | python3 -m venv venv 23 | . venv/bin/activate 24 | pip install -r requirements.txt 25 | 26 | - save_cache: 27 | paths: 28 | - ./venv 29 | key: v1-dependencies-{{ checksum "requirements.txt" }} 30 | 31 | # run tests! 32 | - run: 33 | name: run tests 34 | command: | 35 | . venv/bin/activate 36 | pytest test/test.py 37 | 38 | workflows: 39 | version: 2 40 | build: 41 | jobs: 42 | - unit_test 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/linux,macos,python,pycharm,windows,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=linux,macos,python,pycharm,windows,visualstudiocode 4 | 5 | ### Linux ### 6 | *~ 7 | 8 | # temporary files which can be created if a process still has a handle open of a deleted file 9 | .fuse_hidden* 10 | 11 | # KDE directory preferences 12 | .directory 13 | 14 | # Linux trash folder which might appear on any partition or disk 15 | .Trash-* 16 | 17 | # .nfs files are created when an open file is removed but is still being accessed 18 | .nfs* 19 | 20 | ### macOS ### 21 | # General 22 | .DS_Store 23 | .AppleDouble 24 | .LSOverride 25 | 26 | # Icon must end with two \r 27 | Icon 28 | 29 | # Thumbnails 30 | ._* 31 | 32 | # Files that might appear in the root of a volume 33 | .DocumentRevisions-V100 34 | .fseventsd 35 | .Spotlight-V100 36 | .TemporaryItems 37 | .Trashes 38 | .VolumeIcon.icns 39 | .com.apple.timemachine.donotpresent 40 | 41 | # Directories potentially created on remote AFP share 42 | .AppleDB 43 | .AppleDesktop 44 | Network Trash Folder 45 | Temporary Items 46 | .apdisk 47 | 48 | ### PyCharm ### 49 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 50 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 51 | 52 | # User-specific stuff 53 | .idea/**/workspace.xml 54 | .idea/**/tasks.xml 55 | .idea/**/usage.statistics.xml 56 | .idea/**/dictionaries 57 | .idea/**/shelf 58 | 59 | # Generated files 60 | .idea/**/contentModel.xml 61 | 62 | # Sensitive or high-churn files 63 | .idea/**/dataSources/ 64 | .idea/**/dataSources.ids 65 | .idea/**/dataSources.local.xml 66 | .idea/**/sqlDataSources.xml 67 | .idea/**/dynamic.xml 68 | .idea/**/uiDesigner.xml 69 | .idea/**/dbnavigator.xml 70 | 71 | # Gradle 72 | .idea/**/gradle.xml 73 | .idea/**/libraries 74 | 75 | # Gradle and Maven with auto-import 76 | # When using Gradle or Maven with auto-import, you should exclude module files, 77 | # since they will be recreated, and may cause churn. Uncomment if using 78 | # auto-import. 79 | # .idea/modules.xml 80 | # .idea/*.iml 81 | # .idea/modules 82 | # *.iml 83 | # *.ipr 84 | 85 | # CMake 86 | cmake-build-*/ 87 | 88 | # Mongo Explorer plugin 89 | .idea/**/mongoSettings.xml 90 | 91 | # File-based project format 92 | *.iws 93 | 94 | # IntelliJ 95 | out/ 96 | 97 | # mpeltonen/sbt-idea plugin 98 | .idea_modules/ 99 | 100 | # JIRA plugin 101 | atlassian-ide-plugin.xml 102 | 103 | # Cursive Clojure plugin 104 | .idea/replstate.xml 105 | 106 | # Crashlytics plugin (for Android Studio and IntelliJ) 107 | com_crashlytics_export_strings.xml 108 | crashlytics.properties 109 | crashlytics-build.properties 110 | fabric.properties 111 | 112 | # Editor-based Rest Client 113 | .idea/httpRequests 114 | 115 | # Android studio 3.1+ serialized cache file 116 | .idea/caches/build_file_checksums.ser 117 | 118 | ### PyCharm Patch ### 119 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 120 | 121 | # *.iml 122 | # modules.xml 123 | # .idea/misc.xml 124 | # *.ipr 125 | 126 | # Sonarlint plugin 127 | .idea/**/sonarlint/ 128 | 129 | # SonarQube Plugin 130 | .idea/**/sonarIssues.xml 131 | 132 | # Markdown Navigator plugin 133 | .idea/**/markdown-navigator.xml 134 | .idea/**/markdown-navigator/ 135 | 136 | ### Python ### 137 | # Byte-compiled / optimized / DLL files 138 | __pycache__/ 139 | *.py[cod] 140 | *$py.class 141 | 142 | # C extensions 143 | *.so 144 | 145 | # Distribution / packaging 146 | .Python 147 | build/ 148 | develop-eggs/ 149 | dist/ 150 | downloads/ 151 | eggs/ 152 | .eggs/ 153 | lib/ 154 | lib64/ 155 | parts/ 156 | sdist/ 157 | var/ 158 | wheels/ 159 | pip-wheel-metadata/ 160 | share/python-wheels/ 161 | *.egg-info/ 162 | .installed.cfg 163 | *.egg 164 | MANIFEST 165 | 166 | # PyInstaller 167 | # Usually these files are written by a python script from a template 168 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 169 | *.manifest 170 | *.spec 171 | 172 | # Installer logs 173 | pip-log.txt 174 | pip-delete-this-directory.txt 175 | 176 | # Unit test / coverage reports 177 | htmlcov/ 178 | .tox/ 179 | .nox/ 180 | .coverage 181 | .coverage.* 182 | .cache 183 | nosetests.xml 184 | coverage.xml 185 | *.cover 186 | .hypothesis/ 187 | .pytest_cache/ 188 | 189 | # Translations 190 | *.mo 191 | *.pot 192 | 193 | # Scrapy stuff: 194 | .scrapy 195 | 196 | # Sphinx documentation 197 | docs/_build/ 198 | 199 | # PyBuilder 200 | target/ 201 | 202 | # pyenv 203 | .python-version 204 | 205 | # pipenv 206 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 207 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 208 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 209 | # install all needed dependencies. 210 | #Pipfile.lock 211 | 212 | # celery beat schedule file 213 | celerybeat-schedule 214 | 215 | # SageMath parsed files 216 | *.sage.py 217 | 218 | # Spyder project settings 219 | .spyderproject 220 | .spyproject 221 | 222 | # Rope project settings 223 | .ropeproject 224 | 225 | # Mr Developer 226 | .mr.developer.cfg 227 | .project 228 | .pydevproject 229 | 230 | # mkdocs documentation 231 | /site 232 | 233 | # mypy 234 | .mypy_cache/ 235 | .dmypy.json 236 | dmypy.json 237 | 238 | # Pyre type checker 239 | .pyre/ 240 | 241 | ### VisualStudioCode ### 242 | .vscode/* 243 | !.vscode/settings.json 244 | !.vscode/tasks.json 245 | !.vscode/launch.json 246 | !.vscode/extensions.json 247 | 248 | ### VisualStudioCode Patch ### 249 | # Ignore all local history of files 250 | .history 251 | 252 | ### Windows ### 253 | # Windows thumbnail cache files 254 | Thumbs.db 255 | Thumbs.db:encryptable 256 | ehthumbs.db 257 | ehthumbs_vista.db 258 | 259 | # Dump file 260 | *.stackdump 261 | 262 | # Folder config file 263 | [Dd]esktop.ini 264 | 265 | # Recycle Bin used on file shares 266 | $RECYCLE.BIN/ 267 | 268 | # Windows Installer files 269 | *.cab 270 | *.msi 271 | *.msix 272 | *.msm 273 | *.msp 274 | 275 | # Windows shortcuts 276 | *.lnk 277 | 278 | # End of https://www.gitignore.io/api/linux,macos,python,pycharm,windows,visualstudiocode -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[python]": { 3 | "editor.defaultFormatter": "ms-python.autopep8" 4 | }, 5 | "python.formatting.provider": "none" 6 | } 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # pull official base image 2 | FROM python:3.8.1-alpine 3 | 4 | # set work directory 5 | WORKDIR /src 6 | 7 | # set environment variables 8 | ENV PYTHONDONTWRITEBYTECODE 1 9 | ENV PYTHONUNBUFFERED 1 10 | 11 | # copy requirements file 12 | COPY ./requirements.txt /src/requirements.txt 13 | 14 | # install dependencies 15 | RUN set -eux \ 16 | && apk add --no-cache --virtual .build-deps build-base \ 17 | libressl-dev libffi-dev gcc musl-dev python3-dev \ 18 | postgresql-dev \ 19 | && pip install --upgrade pip setuptools wheel \ 20 | && pip install -r /src/requirements.txt \ 21 | && rm -rf /root/.cache/pip 22 | 23 | # copy project 24 | COPY . /src/ 25 | 26 | EXPOSE 5001 27 | CMD ["uvicorn", "app.main:app", "--reload", "--host", "0.0.0.0", "--port", "5001"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Problem of stable diffusion webui 2 | 3 | Stable diffusion webui provides a powerful tool for AI image generation. However, the webui api has some limitations: 4 | 5 | 1. a blocking REST api call, which might take more than 30s to return the final value. Most gateways don't allow such long blocking time on api call. 6 | 2. webui api is a single thread process. Once the thread is occupied, other webui api will fail. (Even though there is a multi thread mode in stable diffusion webui) 7 | 8 | This repo is aiming to solve the above problems. 9 | 10 | ## Preconditions: 11 | 12 | - Python 3 13 | - Stable diffusion Webui 14 | 15 | ## Inspired by the project 16 | 17 | https://github.com/marciovrl/fastapi-example.git 18 | 19 | ## Run local 20 | 21 | ### Before run this project, please make sure you launched the stable diffusion webui api. 22 | 23 | ### Install dependencies 24 | 25 | ``` 26 | pip install -r requirements.txt 27 | ``` 28 | 29 | ### Run server 30 | 31 | ``` 32 | uvicorn app.main:app --reload --port 5001 33 | ``` 34 | 35 | 54 | 55 | ## API documentation (provided by Swagger UI) 56 | 57 | ``` 58 | http://127.0.0.1:8000/docs 59 | ``` 60 | 61 | 66 | 67 | ## Model swtich 68 | 69 | There is an extra filed in txt2img/img2img api: 70 | 71 | options: Optional[dict] 72 | 73 | You can swtich stable diffusion by using this options. 74 | 75 | ``` 76 | "options": 77 | { 78 | "sd_model_checkpoint": 79 | } 80 | ``` 81 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nftblackmagic/sdwebui-api-manager/71f03c950a18aa4bcba94b9bf23d7025a76d2e2c/app/__init__.py -------------------------------------------------------------------------------- /app/api/api.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | 4 | 5 | def img2img(payload): 6 | 7 | url = 'http://0.0.0.0:7860/sdapi/v1/img2img' 8 | 9 | headers = { 10 | 'Content-Type': 'application/json', 11 | } 12 | 13 | filter_data = {} 14 | 15 | for k, v in payload.items(): 16 | if payload[k] != None: 17 | filter_data[k] = v 18 | 19 | print("img2img settings", filter_data) 20 | 21 | response = requests.post(url, headers=headers, 22 | data=json.dumps(filter_data)) 23 | 24 | res = response.json() 25 | 26 | return res 27 | 28 | 29 | def txt2img(payload): 30 | 31 | url = 'http://0.0.0.0:7860/sdapi/v1/txt2img' 32 | 33 | headers = { 34 | 'Content-Type': 'application/json', 35 | } 36 | 37 | filter_data = {} 38 | 39 | for k, v in payload.items(): 40 | if payload[k] != None: 41 | filter_data[k] = v 42 | 43 | print("txt2img settings", filter_data) 44 | 45 | response = requests.post(url, headers=headers, 46 | data=json.dumps(filter_data)) 47 | 48 | res = response.json() 49 | 50 | return res 51 | 52 | 53 | def progress(): 54 | url = 'http://0.0.0.0:7860/sdapi/v1/progress?skip_current_image=false' 55 | 56 | headers = { 57 | 'Content-Type': 'application/json', 58 | } 59 | 60 | response = requests.get(url, headers=headers) 61 | 62 | res = response.json() 63 | 64 | return res 65 | 66 | 67 | def get_options(): 68 | url = 'http://0.0.0.0:7860/sdapi/v1/options' 69 | 70 | headers = { 71 | 'Content-Type': 'application/json', 72 | } 73 | 74 | response = requests.get(url, headers=headers, timeout=5) 75 | 76 | res = response.json() 77 | 78 | return res 79 | 80 | 81 | def set_options(payload): 82 | url = 'http://0.0.0.0:7860/sdapi/v1/options' 83 | 84 | headers = { 85 | 'Content-Type': 'application/json', 86 | } 87 | 88 | filter_data = {} 89 | 90 | for k, v in payload.items(): 91 | if payload[k] != None: 92 | filter_data[k] = v 93 | 94 | print("set_options settings", filter_data) 95 | 96 | response = requests.post(url, headers=headers, 97 | data=json.dumps(filter_data)) 98 | 99 | res = response.json() 100 | 101 | return res 102 | 103 | 104 | def extra_single_image(payload): 105 | url = 'http://0.0.0.0:7860/sdapi/v1/extra-single-image' 106 | 107 | headers = { 108 | 'Content-Type': 'application/json', 109 | } 110 | 111 | filter_data = {} 112 | 113 | for k, v in payload.items(): 114 | if payload[k] != None: 115 | filter_data[k] = v 116 | 117 | print("set_options settings", filter_data) 118 | 119 | response = requests.post(url, headers=headers, 120 | data=json.dumps(filter_data)) 121 | 122 | res = response.json() 123 | 124 | return res 125 | 126 | 127 | def controlnet_model_list(): 128 | url = 'http://0.0.0.0:7860/controlnet/model_list' 129 | 130 | headers = { 131 | 'Content-Type': 'application/json', 132 | } 133 | 134 | response = requests.get(url, headers=headers) 135 | 136 | res = response.json() 137 | 138 | return res 139 | 140 | 141 | def controlnet_module_list(): 142 | url = 'http://0.0.0.0:7860/controlnet/module_list' 143 | 144 | headers = { 145 | 'Content-Type': 'application/json', 146 | } 147 | 148 | response = requests.get(url, headers=headers) 149 | 150 | res = response.json() 151 | 152 | return res 153 | 154 | 155 | def sd_models(): 156 | url = 'http://0.0.0.0:7860/sdapi/v1/sd-models' 157 | 158 | headers = { 159 | 'Content-Type': 'application/json', 160 | } 161 | 162 | response = requests.get(url, headers=headers) 163 | 164 | res = response.json() 165 | 166 | return res 167 | -------------------------------------------------------------------------------- /app/db/models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from typing import List, Optional 3 | 4 | 5 | class Img2imgArgs(BaseModel): 6 | init_images: Optional[List[str]] 7 | resize_mode: Optional[int] 8 | denoising_strength: Optional[float] 9 | image_cfg_scale: Optional[int] 10 | mask: Optional[str] 11 | mask_blur: Optional[int] 12 | inpainting_fill: Optional[int] 13 | inpaint_full_res: Optional[bool] 14 | inpaint_full_res_padding: Optional[int] 15 | inpainting_mask_invert: Optional[bool] 16 | initial_noise_multiplier: Optional[int] 17 | prompt: Optional[str] 18 | styles: Optional[List[str]] 19 | seed: Optional[int] 20 | subseed: Optional[int] 21 | subseed_strength: Optional[int] 22 | seed_resize_from_h: Optional[int] 23 | seed_resize_from_w: Optional[int] 24 | sampler_name: Optional[str] 25 | batch_size: Optional[int] 26 | n_iter: Optional[int] 27 | steps: Optional[int] 28 | cfg_scale: Optional[int] 29 | width: Optional[int] 30 | height: Optional[int] 31 | restore_faces: Optional[bool] 32 | tiling: Optional[bool] 33 | do_not_save_samples: Optional[bool] 34 | do_not_save_grid: Optional[bool] 35 | negative_prompt: Optional[str] 36 | eta: Optional[int] 37 | s_min_uncond: Optional[int] 38 | s_churn: Optional[int] 39 | s_tmax: Optional[int] 40 | s_tmin: Optional[int] 41 | s_noise: Optional[int] 42 | override_settings: Optional[dict] 43 | override_settings_restore_afterwards: Optional[bool] 44 | script_args: Optional[List[dict]] 45 | sampler_index: Optional[str] 46 | include_init_images: Optional[bool] 47 | script_name: Optional[str] 48 | send_images: Optional[bool] 49 | save_images: Optional[bool] 50 | alwayson_scripts: Optional[dict] 51 | options: Optional[dict] 52 | 53 | 54 | class Txt2imgArgs(BaseModel): 55 | enable_hr: Optional[bool] 56 | denoising_strength: Optional[float] 57 | firstphase_width: Optional[int] 58 | firstphase_height: Optional[int] 59 | hr_scale: Optional[int] 60 | hr_upscaler: Optional[str] 61 | hr_second_pass_steps: Optional[int] 62 | hr_resize_x: Optional[int] 63 | hr_resize_y: Optional[int] 64 | prompt: Optional[str] 65 | styles: Optional[List[str]] 66 | seed: Optional[int] 67 | subseed: Optional[int] 68 | subseed_strength: Optional[int] 69 | seed_resize_from_h: Optional[int] 70 | seed_resize_from_w: Optional[int] 71 | sampler_name: Optional[str] 72 | batch_size: Optional[int] 73 | n_iter: Optional[int] 74 | steps: Optional[int] 75 | cfg_scale: Optional[int] 76 | width: Optional[int] 77 | height: Optional[int] 78 | restore_faces: Optional[bool] 79 | tiling: Optional[bool] 80 | do_not_save_samples: Optional[bool] 81 | do_not_save_grid: Optional[bool] 82 | negative_prompt: Optional[str] 83 | eta: Optional[int] 84 | s_min_uncond: Optional[int] 85 | s_churn: Optional[int] 86 | s_tmax: Optional[int] 87 | s_tmin: Optional[int] 88 | s_noise: Optional[int] 89 | override_settings: Optional[dict] 90 | override_settings_restore_afterwards: Optional[bool] 91 | script_args: Optional[List[dict]] 92 | sampler_index: Optional[str] 93 | script_name: Optional[str] 94 | send_images: Optional[bool] 95 | save_image: Optional[bool] 96 | alwayson_scripts: Optional[dict] 97 | options: Optional[dict] 98 | 99 | 100 | class ExtraSingleImage(BaseModel): 101 | resize_mode: Optional[int] 102 | show_extras_results: Optional[bool] 103 | gfpgan_visibility: Optional[int] 104 | codeformer_visibility: Optional[int] 105 | codeformer_weight: Optional[float] 106 | upscaling_resize: Optional[int] 107 | upscaling_resize_w: Optional[int] 108 | upscaling_resize_h: Optional[int] 109 | upscaling_crop: Optional[bool] 110 | upscaler_1: Optional[str] 111 | upscaler_2: Optional[str] 112 | extras_upscaler_2_visibility: Optional[int] 113 | upscale_first: Optional[bool] 114 | image: Optional[str] 115 | -------------------------------------------------------------------------------- /app/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, HTTPException 2 | from starlette.responses import Response 3 | 4 | from app.db.models import Img2imgArgs, Txt2imgArgs, ExtraSingleImage 5 | from app.api import api 6 | from app.manager import reqq 7 | 8 | app = FastAPI() 9 | 10 | 11 | @app.get("/") 12 | def root(): 13 | return {"message": "Fast API in Python"} 14 | 15 | 16 | @app.post("/rawimg2img", status_code=201) 17 | def rawimg2img(payload: Img2imgArgs): 18 | payload = payload.dict() 19 | 20 | return api.img2img(payload) 21 | 22 | 23 | @app.post("/rawtxt2img", status_code=201) 24 | def rawtxt2img(payload: Txt2imgArgs): 25 | payload = payload.dict() 26 | 27 | return api.txt2img(payload) 28 | 29 | 30 | @app.post("/img2img", status_code=201) 31 | def img2img(payload: Img2imgArgs): 32 | payload = payload.dict() 33 | return reqq.add_req_queue(payload, "img2img") 34 | 35 | 36 | @app.post("/txt2img", status_code=201) 37 | def txt2img(payload: Txt2imgArgs): 38 | payload = payload.dict() 39 | return reqq.add_req_queue(payload, "txt2img") 40 | 41 | 42 | @app.get("/progress/{req_id}") 43 | def progress(req_id: str): 44 | return reqq.get_result(req_id) 45 | 46 | 47 | @app.get("/controlnet/model_list") 48 | def controlnet_model_list(): 49 | return api.controlnet_model_list() 50 | 51 | 52 | @app.get("/controlnet/module_list") 53 | def controlnet_module_list(): 54 | return api.controlnet_module_list() 55 | 56 | 57 | @app.post("/sdapi/v1/extra-single-image", status_code=201) 58 | def extra_single_image(payload: ExtraSingleImage): 59 | payload = payload.dict() 60 | return api.extra_single_image(payload) 61 | 62 | 63 | @app.get("/sdapi/v1/sd-models") 64 | def sd_models(): 65 | return api.sd_models() 66 | -------------------------------------------------------------------------------- /app/manager/reqq.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | import queue 3 | import threading 4 | import time 5 | import copy 6 | from app.api import api 7 | from fastapi import HTTPException 8 | 9 | 10 | current_request = {} 11 | final_results = {} 12 | current_options = {} 13 | 14 | 15 | class QueueMonitor: 16 | def __init__(self, q): 17 | self.q = q 18 | self.monitor_thread = threading.Thread( 19 | target=self.monitor_queue, daemon=True) 20 | self.monitor_thread.start() 21 | 22 | def get_queue_size(self): 23 | return self.q.qsize() 24 | 25 | def monitor_queue(self): 26 | while True: 27 | current_size = self.get_queue_size() 28 | if current_size > 0: 29 | self.queue_has_items() 30 | time.sleep(1) # check the queue every second 31 | 32 | def queue_has_items(self): 33 | print(f"Queue has items. Current size: {self.get_queue_size()}") 34 | self.callback_function() 35 | 36 | def callback_function(self): 37 | start_process_queue() 38 | 39 | 40 | requests_queue = queue.Queue(20) 41 | 42 | # Create a QueueMonitor object with the Queue 43 | monitor = QueueMonitor(requests_queue) 44 | 45 | 46 | def start_process_queue(): 47 | global current_request 48 | global final_results 49 | if ((current_request.get("status") != "pending") and (current_request.get("status") != "processing")): 50 | if not requests_queue.empty(): 51 | current_request = requests_queue.get() 52 | current_request["status"] = "processing" 53 | print("current_request is processing", current_request.get( 54 | "request_id"), current_request.get("status")) 55 | request_options = current_request.get("options") 56 | compare_options(request_options) 57 | if (current_request.get("type") == "txt2img"): 58 | res = api.txt2img(current_request.get("payload")) 59 | final_request = copy.deepcopy(current_request) 60 | final_request["status"] = "done" 61 | final_request["result"] = res 62 | final_results[final_request.get("request_id")] = final_request 63 | print("request is complete", final_request.get( 64 | "request_id"), final_request.get("status")) 65 | current_request["status"] = "finishing" 66 | if (current_request.get("type") == "img2img"): 67 | res = api.img2img(current_request.get("payload")) 68 | final_request = copy.deepcopy(current_request) 69 | final_request["status"] = "done" 70 | final_request["result"] = res 71 | final_results[final_request.get("request_id")] = final_request 72 | print("request is complete", final_request.get( 73 | "request_id"), final_request.get("status")) 74 | current_request["status"] = "finishing" 75 | 76 | 77 | def add_req_queue(payload, type): 78 | # try: 79 | # api.get_options() 80 | # except: 81 | # raise HTTPException( 82 | # status_code=500, detail="No options found, please check backend is running correctly.") 83 | 84 | filter_data = {} 85 | options = {} 86 | 87 | for k, v in payload.items(): 88 | if (k == "options"): 89 | options = v 90 | if payload[k] != None: 91 | filter_data[k] = v 92 | 93 | request_id = str(uuid.uuid4()) 94 | temp_request = { 95 | "type": type, 96 | "payload": filter_data, 97 | "request_id": request_id, 98 | "status": "pending", 99 | "options": options 100 | } 101 | requests_queue.put(temp_request) 102 | print("add request into queue, pending", request_id) 103 | return temp_request 104 | 105 | 106 | def check_variable_in_queue(q, var): 107 | queue_as_list = list(q.queue) 108 | pending_requests = [] 109 | for i in queue_as_list: 110 | pending_requests.append(i.get("request_id")) 111 | if var in pending_requests: 112 | print(f"{var} is in the queue.") 113 | return pending_requests.index(var) 114 | else: 115 | print(f"{var} is not in the queue.") 116 | return -1 117 | 118 | 119 | def get_result(request_id): 120 | global final_results 121 | print("final_results", final_results.keys(), request_id) 122 | if (request_id in final_results): 123 | print("Found final result", request_id) 124 | return final_results[request_id] 125 | elif (request_id == current_request.get("request_id")): 126 | res = api.progress() 127 | temp_res = current_request 128 | temp_res["result"] = res 129 | return temp_res 130 | else: 131 | index = check_variable_in_queue(requests_queue, request_id) 132 | if (index > -1): 133 | return {"status": "pending", "request_id": request_id, "pending_count": index+1} 134 | else: 135 | return {"status": "not_found"} 136 | 137 | 138 | def compare_options(options): 139 | global current_options 140 | is_change = False 141 | print("compare_options", options) 142 | for k, v in options.items(): 143 | if (current_options.get(k) != v): 144 | is_change = True 145 | break 146 | 147 | if (is_change): 148 | current_options = copy.deepcopy(options) 149 | print("start to set options to api", current_options) 150 | api.set_options(options) 151 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | 3 | services: 4 | app: 5 | build: . 6 | container_name: app 7 | command: uvicorn app.main:app --reload --workers 1 --host 0.0.0.0 --port 8000 8 | volumes: 9 | - ./:/src/ 10 | ports: 11 | - 8002:8000 12 | environment: 13 | - DATABASE_URL=postgresql://fastapi:fastapi@db/fastapi 14 | 15 | db: 16 | image: postgres:12.1-alpine 17 | container_name: db 18 | volumes: 19 | - postgres_data:/var/lib/postgresql/data/ 20 | environment: 21 | - POSTGRES_USER=fastapi 22 | - POSTGRES_PASSWORD=fastapi 23 | - POSTGRES_DB=fastapi 24 | 25 | volumes: 26 | postgres_data: 27 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | apt update 2 | apt install -y aria2 3 | apt-get install python3-pip 4 | apt install vim 5 | apt-get install tmux 6 | 7 | pip3 install -r requirements.txt 8 | 9 | git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git 10 | git reset --hard 394ffa7 11 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/embed/upscale/resolve/main/4x-UltraSharp.pth -d ./stable-diffusion-webui/models/ESRGAN -o 4x-UltraSharp.pth 12 | wget https://raw.githubusercontent.com/camenduru/stable-diffusion-webui-scripts/main/run_n_times.py -O ./stable-diffusion-webui/scripts/run_n_times.py 13 | git clone https://github.com/camenduru/stable-diffusion-webui-images-browser ./stable-diffusion-webui/extensions/stable-diffusion-webui-images-browser 14 | git clone https://github.com/camenduru/sd-civitai-browser ./stable-diffusion-webui/extensions/sd-civitai-browser 15 | git clone https://github.com/kohya-ss/sd-webui-additional-networks ./stable-diffusion-webui/extensions/sd-webui-additional-networks 16 | git clone https://github.com/Mikubill/sd-webui-controlnet ./stable-diffusion-webui/extensions/sd-webui-controlnet 17 | git clone https://github.com/camenduru/sd-webui-tunnels ./stable-diffusion-webui/extensions/sd-webui-tunnels 18 | git clone https://github.com/etherealxx/batchlinks-webui ./stable-diffusion-webui/extensions/batchlinks-webui 19 | git clone https://github.com/camenduru/stable-diffusion-webui-catppuccin ./stable-diffusion-webui/extensions/stable-diffusion-webui-catppuccin 20 | git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui-rembg ./stable-diffusion-webui/extensions/stable-diffusion-webui-rembg 21 | git clone https://github.com/ashen-sensored/stable-diffusion-webui-two-shot ./stable-diffusion-webui/extensions/stable-diffusion-webui-two-shot 22 | git clone https://github.com/thomasasfk/sd-webui-aspect-ratio-helper ./stable-diffusion-webui/extensions/sd-webui-aspect-ratio-helper 23 | git clone https://github.com/nonnonstop/sd-webui-3d-open-pose-editor ./stable-diffusion-webui/extensions/sd-webui-3d-open-pose-editor 24 | git clone https://github.com/continue-revolution/sd-webui-segment-anything.git ./stable-diffusion-webui/extensions/sd-webui-segment-anything 25 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11e_sd15_ip2p_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11e_sd15_ip2p_fp16.safetensors 26 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11e_sd15_shuffle_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11e_sd15_shuffle_fp16.safetensors 27 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11p_sd15_canny_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_canny_fp16.safetensors 28 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11f1p_sd15_depth_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11f1p_sd15_depth_fp16.safetensors 29 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11p_sd15_inpaint_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_inpaint_fp16.safetensors 30 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11p_sd15_lineart_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_lineart_fp16.safetensors 31 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11p_sd15_mlsd_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_mlsd_fp16.safetensors 32 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11p_sd15_normalbae_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_normalbae_fp16.safetensors 33 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11p_sd15_openpose_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_openpose_fp16.safetensors 34 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11p_sd15_scribble_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_scribble_fp16.safetensors 35 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11p_sd15_seg_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_seg_fp16.safetensors 36 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11p_sd15_softedge_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_softedge_fp16.safetensors 37 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11p_sd15s2_lineart_anime_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15s2_lineart_anime_fp16.safetensors 38 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/control_v11f1e_sd15_tile_fp16.safetensors -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11f1e_sd15_tile_fp16.safetensors 39 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11e_sd15_ip2p_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11e_sd15_ip2p_fp16.yaml 40 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11e_sd15_shuffle_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11e_sd15_shuffle_fp16.yaml 41 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11p_sd15_canny_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_canny_fp16.yaml 42 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11f1p_sd15_depth_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11f1p_sd15_depth_fp16.yaml 43 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11p_sd15_inpaint_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_inpaint_fp16.yaml 44 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11p_sd15_lineart_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_lineart_fp16.yaml 45 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11p_sd15_mlsd_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_mlsd_fp16.yaml 46 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11p_sd15_normalbae_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_normalbae_fp16.yaml 47 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11p_sd15_openpose_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_openpose_fp16.yaml 48 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11p_sd15_scribble_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_scribble_fp16.yaml 49 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11p_sd15_seg_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_seg_fp16.yaml 50 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11p_sd15_softedge_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15_softedge_fp16.yaml 51 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11p_sd15s2_lineart_anime_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11p_sd15s2_lineart_anime_fp16.yaml 52 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/raw/main/control_v11f1e_sd15_tile_fp16.yaml -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o control_v11f1e_sd15_tile_fp16.yaml 53 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_style_sd14v1.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_style_sd14v1.pth 54 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_sketch_sd14v1.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_sketch_sd14v1.pth 55 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_seg_sd14v1.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_seg_sd14v1.pth 56 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_openpose_sd14v1.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_openpose_sd14v1.pth 57 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_keypose_sd14v1.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_keypose_sd14v1.pth 58 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_depth_sd14v1.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_depth_sd14v1.pth 59 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_color_sd14v1.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_color_sd14v1.pth 60 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_canny_sd14v1.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_canny_sd14v1.pth 61 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_canny_sd15v2.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_canny_sd15v2.pth 62 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_depth_sd15v2.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_depth_sd15v2.pth 63 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_sketch_sd15v2.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_sketch_sd15v2.pth 64 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/ControlNet-v1-1/resolve/main/t2iadapter_zoedepth_sd15v1.pth -d ./stable-diffusion-webui/extensions/sd-webui-controlnet/models -o t2iadapter_zoedepth_sd15v1.pth 65 | 66 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/anything-v3.0/resolve/main/Anything-V3.0-pruned.ckpt -d ./stable-diffusion-webui/models/Stable-diffusion -o Anything-V3.0-pruned.ckpt 67 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/ckpt/sd-vae-ft-mse-original/resolve/main/vae-ft-mse-840000-ema-pruned.ckpt -d ./stable-diffusion-webui/models/Stable-diffusion -o Anything-V3.0-pruned.vae.pt 68 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/xiaozaa/animaTest/resolve/main/animeoutlineV4_16.safetensors -d ./stable-diffusion-webui/models/Lora -o animeoutlineV4_16.safetensors 69 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/SG161222/Realistic_Vision_V4.0/resolve/main/Realistic_Vision_V4.0.safetensors -d ./stable-diffusion-webui/models/Stable-diffusion -o Realistic_Vision_V4.0.safetensors 70 | 71 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/Sasulee/animeLineartMangaLike_v30MangaLike/resolve/main/animeLineartMangaLike_v30MangaLike.safetensors -d ./stable-diffusion-webui/models/Lora -o animeLineartMangaLike_v30MangaLike.safetensors 72 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/datasets/Nerfgun3/bad_prompt/resolve/main/bad_prompt_version2.pt -d ./stable-diffusion-webui/embeddings -o bad_prompt_version2.pt 73 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/datasets/gsdf/EasyNegative/resolve/main/EasyNegative.pt -d ./stable-diffusion-webui/embeddings -o EasyNegative.pt 74 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/nick-x-hacker/bad-artist/resolve/main/bad-artist.pt -d ./stable-diffusion-webui/embeddings -o bad-artist.pt 75 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/embed/negative/resolve/main/bad-hands-5.pt -d ./stable-diffusion-webui/embeddings -o bad-hands-5.pt 76 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/embed/negative/resolve/main/ng_deepnegative_v1_75t.pt -d ./stable-diffusion-webui/embeddings -o ng_deepnegative_v1_75t.pt 77 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/embed/negative/resolve/main/EasyNegativeV2.safetensors -d ./stable-diffusion-webui/embeddings -o EasyNegativeV2.safetensors 78 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/embed/negative/resolve/main/verybadimagenegative_v1.3.pt -d ./stable-diffusion-webui/embeddings -o verybadimagenegative_v1.3.pt 79 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://huggingface.co/embed/negative/resolve/main/bad-image-v2-39000.pt -d ./stable-diffusion-webui/embeddings -o bad-image-v2-39000.pt 80 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://civitai.com/api/download/models/90072?type=Model&format=SafeTensor&size=pruned&fp=fp16 -d ./stable-diffusion-webui/models/Stable-diffusion -o photon_v1.safetensors 81 | aria2c --console-log-level=error -c -x 16 -s 16 -k 1M https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth -d ./stable-diffusion-webui/models/sam -o sam_vit_h_4b8939.pth 82 | 83 | sed -i -e '/ api = create_api/a\' -e ' modules.script_callbacks.before_ui_callback()' ./stable-diffusion-webui/webui.py 84 | sed -i -e 's/\"sd_model_checkpoint\"\,/\"sd_model_checkpoint\,sd_vae\,CLIP_stop_at_last_layers\"\,/g' ./stable-diffusion-webui/modules/shared.py 85 | 86 | cd ./stable-diffusion-webui 87 | apt install python3.10-venv 88 | python3.10 -m venv venv -------------------------------------------------------------------------------- /launch.sh: -------------------------------------------------------------------------------- 1 | python3 -m uvicorn app.main:app --reload --host 0.0.0.0 --port 5001 2 | -------------------------------------------------------------------------------- /launch_sd.sh: -------------------------------------------------------------------------------- 1 | cd ./stable-diffusion-webui 2 | bash <(wget -qO- https://raw.githubusercontent.com/AUTOMATIC1111/stable-diffusion-webui/master/webui.sh) -f --listen --xformers --enable-insecure-extension-access --theme dark --api -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi==0.98.0 2 | pytest==7.4.0 3 | requests==2.31.0 4 | uvicorn==0.22.0 -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nftblackmagic/sdwebui-api-manager/71f03c950a18aa4bcba94b9bf23d7025a76d2e2c/test/__init__.py -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | from starlette.testclient import TestClient 2 | from app.main import app 3 | import json 4 | 5 | client = TestClient(app) 6 | 7 | --------------------------------------------------------------------------------