[
  {
    "path": ".circleci/config.yml",
    "content": "version: 2\njobs:\n  unit_test:\n    docker:\n      - image: circleci/python:3.6.1\n\n    working_directory: ~/repo\n\n    steps:\n      - checkout\n\n      # Download and cache dependencies\n      - restore_cache:\n          keys:\n            - v1-dependencies-{{ checksum \"requirements.txt\" }}\n            # fallback to using the latest cache if no exact match is found\n            - v1-dependencies-\n\n      - run:\n          name: install dependencies\n          command: |\n            python3 -m venv venv\n            . venv/bin/activate\n            pip install -r requirements.txt\n\n      - save_cache:\n          paths:\n            - ./venv\n          key: v1-dependencies-{{ checksum \"requirements.txt\" }}\n\n      # run tests!\n      - run:\n          name: run tests\n          command: |\n            . venv/bin/activate\n            pytest test/test.py\n\nworkflows:\n  version: 2\n  build:\n    jobs:\n      - unit_test\n"
  },
  {
    "path": ".gitignore",
    "content": "\n# Created by https://www.gitignore.io/api/linux,macos,python,pycharm,windows,visualstudiocode\n# Edit at https://www.gitignore.io/?templates=linux,macos,python,pycharm,windows,visualstudiocode\n\n### Linux ###\n*~\n\n# temporary files which can be created if a process still has a handle open of a deleted file\n.fuse_hidden*\n\n# KDE directory preferences\n.directory\n\n# Linux trash folder which might appear on any partition or disk\n.Trash-*\n\n# .nfs files are created when an open file is removed but is still being accessed\n.nfs*\n\n### macOS ###\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n### PyCharm ###\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm\n# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839\n\n# User-specific stuff\n.idea/**/workspace.xml\n.idea/**/tasks.xml\n.idea/**/usage.statistics.xml\n.idea/**/dictionaries\n.idea/**/shelf\n\n# Generated files\n.idea/**/contentModel.xml\n\n# Sensitive or high-churn files\n.idea/**/dataSources/\n.idea/**/dataSources.ids\n.idea/**/dataSources.local.xml\n.idea/**/sqlDataSources.xml\n.idea/**/dynamic.xml\n.idea/**/uiDesigner.xml\n.idea/**/dbnavigator.xml\n\n# Gradle\n.idea/**/gradle.xml\n.idea/**/libraries\n\n# Gradle and Maven with auto-import\n# When using Gradle or Maven with auto-import, you should exclude module files,\n# since they will be recreated, and may cause churn.  Uncomment if using\n# auto-import.\n# .idea/modules.xml\n# .idea/*.iml\n# .idea/modules\n# *.iml\n# *.ipr\n\n# CMake\ncmake-build-*/\n\n# Mongo Explorer plugin\n.idea/**/mongoSettings.xml\n\n# File-based project format\n*.iws\n\n# IntelliJ\nout/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Cursive Clojure plugin\n.idea/replstate.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n\n# Editor-based Rest Client\n.idea/httpRequests\n\n# Android studio 3.1+ serialized cache file\n.idea/caches/build_file_checksums.ser\n\n### PyCharm Patch ###\n# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721\n\n# *.iml\n# modules.xml\n# .idea/misc.xml\n# *.ipr\n\n# Sonarlint plugin\n.idea/**/sonarlint/\n\n# SonarQube Plugin\n.idea/**/sonarIssues.xml\n\n# Markdown Navigator plugin\n.idea/**/markdown-navigator.xml\n.idea/**/markdown-navigator/\n\n### Python ###\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\npip-wheel-metadata/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# pyenv\n.python-version\n\n# pipenv\n#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.\n#   However, in case of collaboration, if having platform-specific dependencies or dependencies\n#   having no cross-platform support, pipenv may install dependencies that don't work, or not\n#   install all needed dependencies.\n#Pipfile.lock\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# Mr Developer\n.mr.developer.cfg\n.project\n.pydevproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.dmypy.json\ndmypy.json\n\n# Pyre type checker\n.pyre/\n\n### VisualStudioCode ###\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n\n### VisualStudioCode Patch ###\n# Ignore all local history of files\n.history\n\n### Windows ###\n# Windows thumbnail cache files\nThumbs.db\nThumbs.db:encryptable\nehthumbs.db\nehthumbs_vista.db\n\n# Dump file\n*.stackdump\n\n# Folder config file\n[Dd]esktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n# End of https://www.gitignore.io/api/linux,macos,python,pycharm,windows,visualstudiocode"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"[python]\": {\n    \"editor.defaultFormatter\": \"ms-python.autopep8\"\n  },\n  \"python.formatting.provider\": \"none\"\n}\n"
  },
  {
    "path": "Dockerfile",
    "content": "# pull official base image\nFROM python:3.8.1-alpine\n\n# set work directory\nWORKDIR /src\n\n# set environment variables\nENV PYTHONDONTWRITEBYTECODE 1\nENV PYTHONUNBUFFERED 1\n\n# copy requirements file\nCOPY ./requirements.txt /src/requirements.txt\n\n# install dependencies\nRUN set -eux \\\n    && apk add --no-cache --virtual .build-deps build-base \\\n    libressl-dev libffi-dev gcc musl-dev python3-dev \\\n    postgresql-dev \\\n    && pip install --upgrade pip setuptools wheel \\\n    && pip install -r /src/requirements.txt \\\n    && rm -rf /root/.cache/pip\n\n# copy project\nCOPY . /src/\n\nEXPOSE 5001\nCMD [\"uvicorn\", \"app.main:app\", \"--reload\",  \"--host\", \"0.0.0.0\", \"--port\", \"5001\"]"
  },
  {
    "path": "README.md",
    "content": "## Problem of stable diffusion webui\n\nStable diffusion webui provides a powerful tool for AI image generation. However, the webui api has some limitations:\n\n1. 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.\n2. 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)\n\nThis repo is aiming to solve the above problems.\n\n## Preconditions:\n\n- Python 3\n- Stable diffusion Webui\n\n## Inspired by the project\n\nhttps://github.com/marciovrl/fastapi-example.git\n\n## Run local\n\n### Before run this project, please make sure you launched the stable diffusion webui api.\n\n### Install dependencies\n\n```\npip install -r requirements.txt\n```\n\n### Run server\n\n```\nuvicorn app.main:app --reload --port 5001\n```\n\n<!-- ### Run test\n\n```\npytest app/test.py\n```\n\n## Run with docker\n\n### Run server\n\n```\ndocker-compose up -d --build\n```\n\n### Run test\n\n```\ndocker-compose exec app pytest test/test.py\n``` -->\n\n## API documentation (provided by Swagger UI)\n\n```\nhttp://127.0.0.1:8000/docs\n```\n\n<!-- ### Run server\n\n```\ndocker-compose exec db psql --username=fastapi --dbname=fastapi_dev\n``` -->\n\n## Model swtich\n\nThere is an extra filed in txt2img/img2img api:\n\n    options: Optional[dict]\n\nYou can swtich stable diffusion by using this options.\n\n```\n\"options\":\n{\n\"sd_model_checkpoint\": <The model you want to use>\n}\n```\n"
  },
  {
    "path": "app/__init__.py",
    "content": ""
  },
  {
    "path": "app/api/api.py",
    "content": "import json\nimport requests\n\n\ndef img2img(payload):\n\n    url = 'http://0.0.0.0:7860/sdapi/v1/img2img'\n\n    headers = {\n        'Content-Type': 'application/json',\n    }\n\n    filter_data = {}\n\n    for k, v in payload.items():\n        if payload[k] != None:\n            filter_data[k] = v\n\n    print(\"img2img settings\", filter_data)\n\n    response = requests.post(url, headers=headers,\n                             data=json.dumps(filter_data))\n\n    res = response.json()\n\n    return res\n\n\ndef txt2img(payload):\n\n    url = 'http://0.0.0.0:7860/sdapi/v1/txt2img'\n\n    headers = {\n        'Content-Type': 'application/json',\n    }\n\n    filter_data = {}\n\n    for k, v in payload.items():\n        if payload[k] != None:\n            filter_data[k] = v\n\n    print(\"txt2img settings\", filter_data)\n\n    response = requests.post(url, headers=headers,\n                             data=json.dumps(filter_data))\n\n    res = response.json()\n\n    return res\n\n\ndef progress():\n    url = 'http://0.0.0.0:7860/sdapi/v1/progress?skip_current_image=false'\n\n    headers = {\n        'Content-Type': 'application/json',\n    }\n\n    response = requests.get(url, headers=headers)\n\n    res = response.json()\n\n    return res\n\n\ndef get_options():\n    url = 'http://0.0.0.0:7860/sdapi/v1/options'\n\n    headers = {\n        'Content-Type': 'application/json',\n    }\n\n    response = requests.get(url, headers=headers, timeout=5)\n\n    res = response.json()\n\n    return res\n\n\ndef set_options(payload):\n    url = 'http://0.0.0.0:7860/sdapi/v1/options'\n\n    headers = {\n        'Content-Type': 'application/json',\n    }\n\n    filter_data = {}\n\n    for k, v in payload.items():\n        if payload[k] != None:\n            filter_data[k] = v\n\n    print(\"set_options settings\", filter_data)\n\n    response = requests.post(url, headers=headers,\n                             data=json.dumps(filter_data))\n\n    res = response.json()\n\n    return res\n\n\ndef extra_single_image(payload):\n    url = 'http://0.0.0.0:7860/sdapi/v1/extra-single-image'\n\n    headers = {\n        'Content-Type': 'application/json',\n    }\n\n    filter_data = {}\n\n    for k, v in payload.items():\n        if payload[k] != None:\n            filter_data[k] = v\n\n    print(\"set_options settings\", filter_data)\n\n    response = requests.post(url, headers=headers,\n                             data=json.dumps(filter_data))\n\n    res = response.json()\n\n    return res\n\n\ndef controlnet_model_list():\n    url = 'http://0.0.0.0:7860/controlnet/model_list'\n\n    headers = {\n        'Content-Type': 'application/json',\n    }\n\n    response = requests.get(url, headers=headers)\n\n    res = response.json()\n\n    return res\n\n\ndef controlnet_module_list():\n    url = 'http://0.0.0.0:7860/controlnet/module_list'\n\n    headers = {\n        'Content-Type': 'application/json',\n    }\n\n    response = requests.get(url, headers=headers)\n\n    res = response.json()\n\n    return res\n\n\ndef sd_models():\n    url = 'http://0.0.0.0:7860/sdapi/v1/sd-models'\n\n    headers = {\n        'Content-Type': 'application/json',\n    }\n\n    response = requests.get(url, headers=headers)\n\n    res = response.json()\n\n    return res\n"
  },
  {
    "path": "app/db/models.py",
    "content": "from pydantic import BaseModel\nfrom typing import List, Optional\n\n\nclass Img2imgArgs(BaseModel):\n    init_images: Optional[List[str]]\n    resize_mode: Optional[int]\n    denoising_strength: Optional[float]\n    image_cfg_scale: Optional[int]\n    mask: Optional[str]\n    mask_blur: Optional[int]\n    inpainting_fill: Optional[int]\n    inpaint_full_res: Optional[bool]\n    inpaint_full_res_padding: Optional[int]\n    inpainting_mask_invert: Optional[bool]\n    initial_noise_multiplier: Optional[int]\n    prompt: Optional[str]\n    styles: Optional[List[str]]\n    seed: Optional[int]\n    subseed: Optional[int]\n    subseed_strength: Optional[int]\n    seed_resize_from_h: Optional[int]\n    seed_resize_from_w: Optional[int]\n    sampler_name: Optional[str]\n    batch_size: Optional[int]\n    n_iter: Optional[int]\n    steps: Optional[int]\n    cfg_scale: Optional[int]\n    width: Optional[int]\n    height: Optional[int]\n    restore_faces: Optional[bool]\n    tiling: Optional[bool]\n    do_not_save_samples: Optional[bool]\n    do_not_save_grid: Optional[bool]\n    negative_prompt: Optional[str]\n    eta: Optional[int]\n    s_min_uncond: Optional[int]\n    s_churn: Optional[int]\n    s_tmax: Optional[int]\n    s_tmin: Optional[int]\n    s_noise: Optional[int]\n    override_settings: Optional[dict]\n    override_settings_restore_afterwards: Optional[bool]\n    script_args: Optional[List[dict]]\n    sampler_index: Optional[str]\n    include_init_images: Optional[bool]\n    script_name: Optional[str]\n    send_images: Optional[bool]\n    save_images: Optional[bool]\n    alwayson_scripts: Optional[dict]\n    options: Optional[dict]\n\n\nclass Txt2imgArgs(BaseModel):\n    enable_hr: Optional[bool]\n    denoising_strength: Optional[float]\n    firstphase_width: Optional[int]\n    firstphase_height: Optional[int]\n    hr_scale: Optional[int]\n    hr_upscaler: Optional[str]\n    hr_second_pass_steps: Optional[int]\n    hr_resize_x: Optional[int]\n    hr_resize_y: Optional[int]\n    prompt: Optional[str]\n    styles: Optional[List[str]]\n    seed: Optional[int]\n    subseed: Optional[int]\n    subseed_strength: Optional[int]\n    seed_resize_from_h: Optional[int]\n    seed_resize_from_w: Optional[int]\n    sampler_name: Optional[str]\n    batch_size: Optional[int]\n    n_iter: Optional[int]\n    steps: Optional[int]\n    cfg_scale: Optional[int]\n    width: Optional[int]\n    height: Optional[int]\n    restore_faces: Optional[bool]\n    tiling: Optional[bool]\n    do_not_save_samples: Optional[bool]\n    do_not_save_grid: Optional[bool]\n    negative_prompt: Optional[str]\n    eta: Optional[int]\n    s_min_uncond: Optional[int]\n    s_churn: Optional[int]\n    s_tmax: Optional[int]\n    s_tmin: Optional[int]\n    s_noise: Optional[int]\n    override_settings: Optional[dict]\n    override_settings_restore_afterwards: Optional[bool]\n    script_args: Optional[List[dict]]\n    sampler_index: Optional[str]\n    script_name: Optional[str]\n    send_images: Optional[bool]\n    save_image: Optional[bool]\n    alwayson_scripts: Optional[dict]\n    options: Optional[dict]\n\n\nclass ExtraSingleImage(BaseModel):\n    resize_mode: Optional[int]\n    show_extras_results: Optional[bool]\n    gfpgan_visibility: Optional[int]\n    codeformer_visibility: Optional[int]\n    codeformer_weight: Optional[float]\n    upscaling_resize: Optional[int]\n    upscaling_resize_w: Optional[int]\n    upscaling_resize_h: Optional[int]\n    upscaling_crop: Optional[bool]\n    upscaler_1: Optional[str]\n    upscaler_2: Optional[str]\n    extras_upscaler_2_visibility: Optional[int]\n    upscale_first: Optional[bool]\n    image: Optional[str]\n"
  },
  {
    "path": "app/main.py",
    "content": "from fastapi import FastAPI, HTTPException\nfrom starlette.responses import Response\n\nfrom app.db.models import Img2imgArgs, Txt2imgArgs, ExtraSingleImage\nfrom app.api import api\nfrom app.manager import reqq\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef root():\n    return {\"message\": \"Fast API in Python\"}\n\n\n@app.post(\"/rawimg2img\", status_code=201)\ndef rawimg2img(payload: Img2imgArgs):\n    payload = payload.dict()\n\n    return api.img2img(payload)\n\n\n@app.post(\"/rawtxt2img\", status_code=201)\ndef rawtxt2img(payload: Txt2imgArgs):\n    payload = payload.dict()\n\n    return api.txt2img(payload)\n\n\n@app.post(\"/img2img\", status_code=201)\ndef img2img(payload: Img2imgArgs):\n    payload = payload.dict()\n    return reqq.add_req_queue(payload, \"img2img\")\n\n\n@app.post(\"/txt2img\", status_code=201)\ndef txt2img(payload: Txt2imgArgs):\n    payload = payload.dict()\n    return reqq.add_req_queue(payload, \"txt2img\")\n\n\n@app.get(\"/progress/{req_id}\")\ndef progress(req_id: str):\n    return reqq.get_result(req_id)\n\n\n@app.get(\"/controlnet/model_list\")\ndef controlnet_model_list():\n    return api.controlnet_model_list()\n\n\n@app.get(\"/controlnet/module_list\")\ndef controlnet_module_list():\n    return api.controlnet_module_list()\n\n\n@app.post(\"/sdapi/v1/extra-single-image\", status_code=201)\ndef extra_single_image(payload: ExtraSingleImage):\n    payload = payload.dict()\n    return api.extra_single_image(payload)\n\n\n@app.get(\"/sdapi/v1/sd-models\")\ndef sd_models():\n    return api.sd_models()\n"
  },
  {
    "path": "app/manager/reqq.py",
    "content": "import uuid\nimport queue\nimport threading\nimport time\nimport copy\nfrom app.api import api\nfrom fastapi import HTTPException\n\n\ncurrent_request = {}\nfinal_results = {}\ncurrent_options = {}\n\n\nclass QueueMonitor:\n    def __init__(self, q):\n        self.q = q\n        self.monitor_thread = threading.Thread(\n            target=self.monitor_queue, daemon=True)\n        self.monitor_thread.start()\n\n    def get_queue_size(self):\n        return self.q.qsize()\n\n    def monitor_queue(self):\n        while True:\n            current_size = self.get_queue_size()\n            if current_size > 0:\n                self.queue_has_items()\n            time.sleep(1)  # check the queue every second\n\n    def queue_has_items(self):\n        print(f\"Queue has items. Current size: {self.get_queue_size()}\")\n        self.callback_function()\n\n    def callback_function(self):\n        start_process_queue()\n\n\nrequests_queue = queue.Queue(20)\n\n# Create a QueueMonitor object with the Queue\nmonitor = QueueMonitor(requests_queue)\n\n\ndef start_process_queue():\n    global current_request\n    global final_results\n    if ((current_request.get(\"status\") != \"pending\") and (current_request.get(\"status\") != \"processing\")):\n        if not requests_queue.empty():\n            current_request = requests_queue.get()\n            current_request[\"status\"] = \"processing\"\n            print(\"current_request is processing\", current_request.get(\n                \"request_id\"), current_request.get(\"status\"))\n            request_options = current_request.get(\"options\")\n            compare_options(request_options)\n            if (current_request.get(\"type\") == \"txt2img\"):\n                res = api.txt2img(current_request.get(\"payload\"))\n                final_request = copy.deepcopy(current_request)\n                final_request[\"status\"] = \"done\"\n                final_request[\"result\"] = res\n                final_results[final_request.get(\"request_id\")] = final_request\n                print(\"request is complete\", final_request.get(\n                    \"request_id\"), final_request.get(\"status\"))\n                current_request[\"status\"] = \"finishing\"\n            if (current_request.get(\"type\") == \"img2img\"):\n                res = api.img2img(current_request.get(\"payload\"))\n                final_request = copy.deepcopy(current_request)\n                final_request[\"status\"] = \"done\"\n                final_request[\"result\"] = res\n                final_results[final_request.get(\"request_id\")] = final_request\n                print(\"request is complete\", final_request.get(\n                    \"request_id\"), final_request.get(\"status\"))\n                current_request[\"status\"] = \"finishing\"\n\n\ndef add_req_queue(payload, type):\n    # try:\n    #     api.get_options()\n    # except:\n    #     raise HTTPException(\n    #         status_code=500, detail=\"No options found, please check backend is running correctly.\")\n\n    filter_data = {}\n    options = {}\n\n    for k, v in payload.items():\n        if (k == \"options\"):\n            options = v\n        if payload[k] != None:\n            filter_data[k] = v\n\n    request_id = str(uuid.uuid4())\n    temp_request = {\n        \"type\": type,\n        \"payload\": filter_data,\n        \"request_id\": request_id,\n        \"status\": \"pending\",\n        \"options\": options\n    }\n    requests_queue.put(temp_request)\n    print(\"add request into queue, pending\", request_id)\n    return temp_request\n\n\ndef check_variable_in_queue(q, var):\n    queue_as_list = list(q.queue)\n    pending_requests = []\n    for i in queue_as_list:\n        pending_requests.append(i.get(\"request_id\"))\n    if var in pending_requests:\n        print(f\"{var} is in the queue.\")\n        return pending_requests.index(var)\n    else:\n        print(f\"{var} is not in the queue.\")\n        return -1\n\n\ndef get_result(request_id):\n    global final_results\n    print(\"final_results\", final_results.keys(), request_id)\n    if (request_id in final_results):\n        print(\"Found final result\", request_id)\n        return final_results[request_id]\n    elif (request_id == current_request.get(\"request_id\")):\n        res = api.progress()\n        temp_res = current_request\n        temp_res[\"result\"] = res\n        return temp_res\n    else:\n        index = check_variable_in_queue(requests_queue, request_id)\n        if (index > -1):\n            return {\"status\": \"pending\", \"request_id\": request_id, \"pending_count\": index+1}\n        else:\n            return {\"status\": \"not_found\"}\n\n\ndef compare_options(options):\n    global current_options\n    is_change = False\n    print(\"compare_options\", options)\n    for k, v in options.items():\n        if (current_options.get(k) != v):\n            is_change = True\n            break\n\n    if (is_change):\n        current_options = copy.deepcopy(options)\n        print(\"start to set options to api\", current_options)\n        api.set_options(options)\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: \"3.7\"\n\nservices:\n  app:\n    build: .\n    container_name: app\n    command: uvicorn app.main:app --reload --workers 1 --host 0.0.0.0 --port 8000\n    volumes:\n      - ./:/src/\n    ports:\n      - 8002:8000\n    environment:\n      - DATABASE_URL=postgresql://fastapi:fastapi@db/fastapi\n\n  db:\n    image: postgres:12.1-alpine\n    container_name: db\n    volumes:\n      - postgres_data:/var/lib/postgresql/data/\n    environment:\n      - POSTGRES_USER=fastapi\n      - POSTGRES_PASSWORD=fastapi\n      - POSTGRES_DB=fastapi\n\nvolumes:\n  postgres_data:\n"
  },
  {
    "path": "install.sh",
    "content": "apt update\napt install -y aria2\napt-get install python3-pip\napt install vim\napt-get install tmux\n\npip3 install -r requirements.txt\n\ngit clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git\ngit reset --hard 394ffa7\naria2c --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\nwget https://raw.githubusercontent.com/camenduru/stable-diffusion-webui-scripts/main/run_n_times.py -O ./stable-diffusion-webui/scripts/run_n_times.py\ngit clone https://github.com/camenduru/stable-diffusion-webui-images-browser ./stable-diffusion-webui/extensions/stable-diffusion-webui-images-browser\ngit clone https://github.com/camenduru/sd-civitai-browser ./stable-diffusion-webui/extensions/sd-civitai-browser\ngit clone https://github.com/kohya-ss/sd-webui-additional-networks ./stable-diffusion-webui/extensions/sd-webui-additional-networks\ngit clone https://github.com/Mikubill/sd-webui-controlnet ./stable-diffusion-webui/extensions/sd-webui-controlnet\ngit clone https://github.com/camenduru/sd-webui-tunnels ./stable-diffusion-webui/extensions/sd-webui-tunnels\ngit clone https://github.com/etherealxx/batchlinks-webui ./stable-diffusion-webui/extensions/batchlinks-webui\ngit clone https://github.com/camenduru/stable-diffusion-webui-catppuccin ./stable-diffusion-webui/extensions/stable-diffusion-webui-catppuccin\ngit clone https://github.com/AUTOMATIC1111/stable-diffusion-webui-rembg ./stable-diffusion-webui/extensions/stable-diffusion-webui-rembg\ngit clone https://github.com/ashen-sensored/stable-diffusion-webui-two-shot ./stable-diffusion-webui/extensions/stable-diffusion-webui-two-shot\ngit clone https://github.com/thomasasfk/sd-webui-aspect-ratio-helper ./stable-diffusion-webui/extensions/sd-webui-aspect-ratio-helper\ngit clone https://github.com/nonnonstop/sd-webui-3d-open-pose-editor ./stable-diffusion-webui/extensions/sd-webui-3d-open-pose-editor\ngit clone https://github.com/continue-revolution/sd-webui-segment-anything.git ./stable-diffusion-webui/extensions/sd-webui-segment-anything\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\n\naria2c --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\naria2c --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\naria2c --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\naria2c --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\n\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\naria2c --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\n\nsed -i -e '/    api = create_api/a\\' -e '    modules.script_callbacks.before_ui_callback()' ./stable-diffusion-webui/webui.py\nsed -i -e 's/\\\"sd_model_checkpoint\\\"\\,/\\\"sd_model_checkpoint\\,sd_vae\\,CLIP_stop_at_last_layers\\\"\\,/g' ./stable-diffusion-webui/modules/shared.py\n\ncd ./stable-diffusion-webui\napt install python3.10-venv\npython3.10 -m venv venv"
  },
  {
    "path": "launch.sh",
    "content": "python3 -m uvicorn app.main:app --reload --host 0.0.0.0 --port 5001 \n"
  },
  {
    "path": "launch_sd.sh",
    "content": "cd ./stable-diffusion-webui\nbash <(wget -qO- https://raw.githubusercontent.com/AUTOMATIC1111/stable-diffusion-webui/master/webui.sh) -f --listen --xformers --enable-insecure-extension-access --theme dark --api "
  },
  {
    "path": "requirements.txt",
    "content": "fastapi==0.98.0\npytest==7.4.0\nrequests==2.31.0\nuvicorn==0.22.0"
  },
  {
    "path": "test/__init__.py",
    "content": ""
  },
  {
    "path": "test/test.py",
    "content": "from starlette.testclient import TestClient\nfrom app.main import app\nimport json\n\nclient = TestClient(app)\n\n"
  }
]