├── .github └── workflows │ ├── deploy.yml │ └── lint.yml ├── .gitignore ├── .readthedocs.yaml ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── docs ├── Makefile ├── backends │ ├── automatic1111.rst │ ├── diffusion-ui-backend.rst │ └── index.rst ├── conf.py ├── frontend.rst ├── index.rst ├── intro.rst ├── make.bat └── requirements.txt ├── pyproject.toml ├── setup.cfg ├── setup.py ├── src └── diffusionui │ ├── __init__.py │ ├── __version__.py │ ├── cli.py │ ├── gradio_interface.py │ ├── pipelines │ ├── README.md │ ├── __init__.py │ └── pipeline_stable_diffusion.py │ └── py.typed └── tox.ini /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Deploy to PyPI 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Set up Python 3.8 15 | uses: actions/setup-python@v2 16 | with: 17 | python-version: 3.8 18 | - name: Build wheel and source tarball 19 | run: | 20 | pip install wheel 21 | python setup.py sdist bdist_wheel 22 | - name: Publish a Python distribution to PyPI 23 | uses: pypa/gh-action-pypi-publish@v1.1.0 24 | with: 25 | user: __token__ 26 | password: ${{ secrets.pypi_password }} 27 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [main] 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Set up Python 3.8 15 | uses: actions/setup-python@v2 16 | with: 17 | python-version: 3.8 18 | - name: Install dependencies 19 | run: | 20 | python -m pip install --upgrade pip wheel 21 | pip install tox 22 | - name: Run lint and static type checks 23 | run: tox 24 | env: 25 | TOXENV: flake8,black,import-order,manifest 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # VIM 132 | *.swp 133 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-20.04 11 | tools: 12 | python: "3.9" 13 | 14 | # Build documentation in the docs/ directory with Sphinx 15 | sphinx: 16 | configuration: docs/conf.py 17 | 18 | # Optionally build your docs in additional formats such as PDF 19 | formats: 20 | - pdf 21 | 22 | python: 23 | install: 24 | - requirements: docs/requirements.txt 25 | - method: pip 26 | path: . 27 | extra_requirements: 28 | - dev 29 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for helping to make Diffusion-UI awesome! 4 | 5 | We welcome all kinds of contributions: 6 | 7 | - Bug fixes 8 | - Documentation improvements 9 | - New features 10 | - Refactoring & tidying 11 | 12 | ## Getting started 13 | 14 | If you have a specific contribution in mind, be sure to check the 15 | [issues](https://github.com/leszekhanusz/diffusion-ui-backend/issues) 16 | and [pull requests](https://github.com/leszekhanusz/diffusion-ui-backend/pulls) 17 | in progress - someone could already be working on something similar 18 | and you can help out. 19 | 20 | ## Coding guidelines 21 | 22 | Some tools are used to ensure a coherent coding style. 23 | You need to make sure that your code satisfy those requirements 24 | or the automated tests will fail. 25 | 26 | - [black code formatter](https://github.com/psf/black) 27 | - [flake8 style enforcement](https://flake8.pycqa.org/en/latest/index.html) 28 | - [isort to sort imports alphabetically](https://isort.readthedocs.io/en/stable/) 29 | 30 | On Linux or MacOS, you can fix and check your code style by running 31 | the Makefile command `make check` (this is also checked by running 32 | the automated tests with tox but it is much faster with make) 33 | 34 | ## How to create a good Pull Request 35 | 36 | 1. Make a fork of the main branch on github 37 | 2. Clone your forked repo on your computer 38 | 3. Create a feature branch `git checkout -b feature_my_awesome_feature` 39 | 4. Modify the code 40 | 5. Verify that the [Coding guidelines](#coding-guidelines) are respected 41 | 7. Make a commit and push it to your fork 42 | 8. From github, create the pull request. Automated tests from GitHub actions 43 | will then automatically check the code 44 | 9. If other modifications are needed, you are free to create more commits and 45 | push them on your branch. They'll get added to the PR automatically. 46 | 47 | Once the Pull Request is accepted and merged, you can safely 48 | delete the branch (and the forked repo if no more development is needed). 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Hanusz Leszek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | 3 | include LICENSE 4 | include README.md 5 | include Makefile 6 | include tox.ini 7 | 8 | recursive-include *.py 9 | 10 | include src/diffusionui/pipelines/README.md 11 | include src/diffusionui/py.typed 12 | 13 | include *.md 14 | recursive-include docs *.bat 15 | recursive-include docs *.py 16 | recursive-include docs *.rst 17 | recursive-include docs Makefile 18 | include docs/requirements.txt 19 | include *.yaml 20 | 21 | prune docs/_build 22 | 23 | global-exclude *.py[co] __pycache__ 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean tests docs 2 | 3 | SRC_PYTHON := src/diffusionui 4 | 5 | check: 6 | isort -v $(SRC_PYTHON) 7 | black $(SRC_PYTHON) 8 | flake8 $(SRC_PYTHON) 9 | check-manifest 10 | 11 | clean: 12 | find . -name "*.pyc" -delete 13 | find . -name "__pycache__" | xargs -I {} rm -rf {} 14 | find . -name "*.egg-info" | xargs -I {} rm -rf {} 15 | rm -rf ./.mypy_cache 16 | rm -rf ./dist 17 | rm -rf ./build 18 | rm -rf ./.tox 19 | rm -rf ./docs/_build 20 | rm -rf ./flagged 21 | 22 | docs: 23 | rm -rf ./docs/_build 24 | cd docs; make html 25 | xdg-open ./docs/_build/html/index.html 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## DEPRECATED 2 | 3 | This is repository is no longer maintained, please consider using 4 | [A1111 fork](https://github.com/AUTOMATIC1111/stable-diffusion-webui) instead. 5 | 6 | ## diffusion-ui-backend 7 | 8 | [Gradio](https://gradio.app) backend for the [diffusion-ui](https://github.com/leszekhanusz/diffusion-ui) web frontend 9 | using an [unified Stable Diffusion diffusers pipeline](src/diffusionui/pipelines/README.md) 10 | 11 | The gradio interface provides an API to generate images with [Stable Diffusion](https://github.com/CompVis/stable-diffusion) for: 12 | 13 | - text-to-image 14 | - image-to-image 15 | - inpainting 16 | 17 | ## Documentation 18 | 19 | The documentation is available [here](https://diffusionui.readthedocs.io) 20 | 21 | ## Installation 22 | 23 | Detailled installation instructions are available [in the documentation](https://diffusionui.readthedocs.io/en/latest/backends/stable-diffusion.html). 24 | 25 | First install [pytorch](https://pytorch.org) with cuda support (if you have a NVIDIA GPU): 26 | 27 | ``` 28 | conda install pytorch torchvision torchaudio cudatoolkit=11.6 -c pytorch -c conda-forge 29 | ``` 30 | 31 | Then install diffusionui and its dependencies: 32 | 33 | ```bash 34 | pip install diffusionui 35 | ``` 36 | 37 | ## First Usage 38 | 39 | The first time, you have to download the model: 40 | 41 | - create an account on https://huggingface.co 42 | - [Click on this page to accept the LICENSE](https://huggingface.co/CompVis/stable-diffusion-v1-4) 43 | - [generate a token in your settings](https://huggingface.co/docs/hub/security-tokens) 44 | - login on your console with `huggingface-cli login` 45 | - then download the model with: 46 | 47 | ```bash 48 | # using the low-memory model (for GPUs with low VRAM) 49 | diffusionui --low-mem --download-model 50 | 51 | # or using the full model 52 | diffusionui --download-model 53 | ``` 54 | 55 | ## Usage 56 | 57 | Once the model has been downloaded, you can start the backend by running: 58 | 59 | ```bash 60 | # For the low-memory model 61 | diffusionui --low-mem 62 | 63 | # For the full model 64 | diffusionui 65 | ``` 66 | 67 | It should produce an local URL for the gradio interface: 68 | 69 | ``` 70 | Running on local URL: http://127.0.0.1:7860/ 71 | ``` 72 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/backends/automatic1111.rst: -------------------------------------------------------------------------------- 1 | Automatic1111 2 | ============= 3 | 4 | Installation 5 | ^^^^^^^^^^^^ 6 | 7 | - First install the automatic1111 fork by following the 8 | `instructions on its GitHub page `_. 9 | You should be able to run its own webui interface by going to 10 | http://127.0.0.1:7860 11 | 12 | - Optionally run :code:`git checkout master` and :code:`git pull -r` in the 13 | `stable-diffusion-webui` folder to upgrade to the latest version 14 | 15 | - Add :code:`--no-gradio-queue --cors-allow-origins=http://localhost:5173,https://diffusionui.com` to your 16 | commandline arguments used to start the Automatic1111 fork. 17 | (In the `webui-user.bat` file on Windows) 18 | 19 | - Launch the automatic1111 webui with those arguments (on windows start the `webui.bat` script) 20 | 21 | - Go to https://diffusionui.com 22 | 23 | - click on the ⓘ icon to go to the model info tab 24 | 25 | - click on the :code:`Reset to default values` button and confirm by clicking Yes. 26 | 27 | .. warning:: 28 | 29 | The webui should run on the 7860 port. 30 | `Running on local URL: http://127.0.0.1:7860/` appearing in the console. 31 | It happens that if you restart the webui too soon that the port is changed 32 | to 7861. In that case, wait a minute and start again until it's on port 7860 33 | 34 | .. warning:: 35 | 36 | It does not work with the brave browser by default and potentially some strict 37 | adblockers. You'll need to deactivate the brave shield for this page. 38 | Note that diffusion-ui does not use tracking of any kind, they just don't 39 | like the fact that the backend config is downloaded from http://127.0.0.1:7860/config 40 | I guess... 41 | -------------------------------------------------------------------------------- /docs/backends/diffusion-ui-backend.rst: -------------------------------------------------------------------------------- 1 | Diffusion-ui-backend 2 | ==================== 3 | 4 | .. warning:: 5 | This backend is now obsolete and you should instead use the Automatic1111 backend. 6 | 7 | Installation 8 | ^^^^^^^^^^^^ 9 | 10 | .. tabs:: 11 | 12 | .. tab:: Linux 13 | 14 | - Install `conda`_ if it is not already installed 15 | 16 | - Create an environment named **dui**: 17 | 18 | .. code-block:: bash 19 | 20 | conda create -n dui python=3.10 21 | 22 | - Activate that environment (You will need to do that every time before running the backend): 23 | 24 | .. code-block:: bash 25 | 26 | conda activate dui 27 | 28 | - You now should have a **(dui)** text in front of your prompt indicating that you are inside that environment. 29 | 30 | - Inside this environment, install `pytorch `_ with cuda support: 31 | 32 | .. code-block:: bash 33 | 34 | conda install pytorch torchvision torchaudio cudatoolkit=11.6 -c pytorch -c conda-forge 35 | 36 | - Install the diffusionui backend and its dependencies: 37 | 38 | .. code-block:: bash 39 | 40 | pip install diffusionui 41 | 42 | .. tab:: Windows 43 | 44 | - Download `Miniconda `_ 45 | - Install Miniconda. Install for all users. Uncheck "Register Miniconda as the system Python 3.9" unless you want to 46 | - `Activate Developer mode `_ 47 | - Open Anaconda Prompt (miniconda3) 48 | - Create an environment named **dui**: 49 | 50 | .. code-block:: bash 51 | 52 | conda create -n dui python=3.10 53 | 54 | - Activate that environment (You will need to do that every time before running the backend): 55 | 56 | .. code-block:: bash 57 | 58 | conda activate dui 59 | 60 | - You now should have a **(dui)** text in front of your prompt indicating that you are inside that environment. 61 | 62 | - Install `pytorch `_ with cuda support: 63 | 64 | .. code-block:: bash 65 | 66 | conda install pytorch torchvision torchaudio cudatoolkit=11.6 -c pytorch -c conda-forge 67 | 68 | - Install the diffusionui backend and its dependencies: 69 | 70 | .. code-block:: bash 71 | 72 | pip install diffusionui 73 | 74 | First Usage 75 | ^^^^^^^^^^^^ 76 | 77 | The first time, you have to download the model: 78 | 79 | - create an account on https://huggingface.co 80 | - `Click on this page to accept the LICENSE `_ 81 | - `generate a token in your settings `_ 82 | - login on your console with `huggingface-cli login` 83 | - then download the model with: 84 | 85 | .. tabs:: 86 | 87 | .. tab:: Low VRAM (recommended) 88 | 89 | .. code-block:: bash 90 | 91 | diffusionui --low-mem --download-model 92 | 93 | .. tab:: High VRAM 94 | 95 | .. code-block:: bash 96 | 97 | diffusionui --download-model 98 | 99 | 100 | Usage 101 | ^^^^^ 102 | 103 | Once the installation has been done, you should have a **diffusionui** 104 | executable in the **dui** environment you created. 105 | 106 | Every time you need to run the backend, don't forget to activate that environment: 107 | 108 | .. code-block:: bash 109 | 110 | conda activate dui 111 | 112 | You can check the current installed version by typing: 113 | 114 | .. code-block:: bash 115 | 116 | diffusionui --version 117 | 118 | To start the backend, run: 119 | 120 | .. tabs:: 121 | 122 | .. tab:: Low VRAM (recommended) 123 | 124 | .. code-block:: bash 125 | 126 | diffusionui --low-mem 127 | 128 | .. tab:: High VRAM 129 | 130 | .. code-block:: bash 131 | 132 | diffusionui 133 | 134 | It should produce an local URL for the gradio interface: 135 | 136 | .. code-block:: bash 137 | 138 | Running on local URL: http://127.0.0.1:7860/ 139 | 140 | 141 | Once you have this local URL, congratulations 🚀 ! 142 | You can now visit https://diffusionui.com to access it with the nice interface. 143 | 144 | .. _conda: https://docs.conda.io 145 | 146 | Sharing 147 | ^^^^^^^ 148 | 149 | It is possible to use Diffusion-UI on your smartphone, tablet or other computer by 150 | sharing the backend on your PC. 151 | 152 | To share the backend: 153 | 154 | * use :code:`--share` to get a public url that can be used from an external device 155 | * optionaly use :code:`--access-code` to specify a required code to access the model 156 | 157 | .. code-block:: bash 158 | 159 | diffusionui --low-mem --share --access-code 1234 160 | 161 | You'll receive something like this: 162 | 163 | .. code-block:: 164 | 165 | Running on local URL: http://127.0.0.1:7860/ 166 | Running on public URL: https://16141.gradio.app 167 | 168 | Then, from your smartphone or tablet: 169 | 170 | * go to http://diffusionui.com 171 | * open the left panel with the top-left icon, then open the model info tab (ⓘ) 172 | * Click on the API URL and change it by replacing the hostname by the provided public URL 173 | (:code:`https://16141.gradio.app/api/predict` in this example) 174 | * Below, insert the access code if needed 175 | 176 | Once you've done this, you can use it on this device. 177 | The url and access code is saved in Local Storage in your browser so you need to do this only once. 178 | 179 | You can now show this amazing technology to all your friends! 180 | -------------------------------------------------------------------------------- /docs/backends/index.rst: -------------------------------------------------------------------------------- 1 | Backends 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | automatic1111 8 | diffusion-ui-backend 9 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | # -- Path setup -------------------------------------------------------------- 7 | 8 | # If extensions (or modules to document with autodoc) are in another directory, 9 | # add these directories to sys.path here. If the directory is relative to the 10 | # documentation root, use os.path.abspath to make it absolute, like shown here. 11 | # 12 | import os 13 | import sys 14 | sys.path.insert(0, os.path.abspath('./..')) 15 | 16 | # -- Project information ----------------------------------------------------- 17 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 18 | 19 | project = 'Diffusion-UI' 20 | copyright = '2022, Leszek Hanusz' 21 | author = 'Leszek Hanusz' 22 | from diffusionui import __version__ 23 | release = __version__ 24 | 25 | # -- General configuration --------------------------------------------------- 26 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 27 | 28 | extensions = ['sphinx_tabs.tabs'] 29 | 30 | templates_path = ['_templates'] 31 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 32 | 33 | 34 | 35 | # -- Options for HTML output ------------------------------------------------- 36 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 37 | 38 | html_theme = 'sphinx_rtd_theme' 39 | html_static_path = ['_static'] 40 | -------------------------------------------------------------------------------- /docs/frontend.rst: -------------------------------------------------------------------------------- 1 | Frontend 2 | ======== 3 | 4 | Installing the frontend is not necessary as it is available on http://diffusionui.com 5 | but you might want to do it either to make some modifications to the code or to run 6 | the website completely offline. 7 | 8 | To install the frontend, install `node.js`_, clone this repo and run: 9 | 10 | .. code-block:: bash 11 | 12 | npm install 13 | 14 | Then to get a local web page, run: 15 | 16 | .. code-block:: bash 17 | 18 | npm run dev 19 | 20 | .. _node.js: https://nodejs.org/en/download 21 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | DiffusionUI 2 | =========== 3 | 4 | .. toctree:: 5 | :maxdepth: 3 6 | 7 | intro 8 | frontend 9 | backends/index 10 | 11 | -------------------------------------------------------------------------------- /docs/intro.rst: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | `Diffusion-UI`_ is a web frontend to generate images using latent diffusion models. 5 | 6 | Thanks to `Stable Diffusion`_ which `released their model for free on August 22, 2022`_, 7 | it is now possible to generate amazing images, from text or from another image, 8 | for free, on your own computer. 9 | 10 | DiffusionUI is available on http://diffusionui.com, but to use the Stable Diffusion model 11 | you have to install the Stable Diffusion backend on your own computer. 12 | 13 | Absolutely no data is received on our servers when you are using http://diffusionui.com 14 | with a local backend and you can even use it offline once the website has been loaded. 15 | 16 | Requirements 17 | ------------ 18 | 19 | - 16GB RAM 20 | - Maxwell-architecture or newer GPU with at least 4GB VRAM 21 | 22 | Reporting Issues and Contributing 23 | --------------------------------- 24 | 25 | Please visit the GitHub repositories for Diffusion-UI ( 26 | `frontend `_, 27 | `backend `_ 28 | ) if you're interested in the current development or 29 | want to report issues or send pull requests. 30 | 31 | We welcome all kinds of contributions if the coding guidelines are respected. 32 | Please check the Contributing file ( 33 | `on frontend `_, 34 | `on backend `_ 35 | ) file to learn how to make a good pull request. 36 | 37 | .. _Diffusion-UI: https://diffusionui.com 38 | .. _Stable Diffusion: https://github.com/CompVis/stable-diffusion 39 | .. _released their model for free on August 22, 2022: https://stability.ai/blog/stable-diffusion-public-release 40 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx>=5.1.1,<6 2 | sphinx_rtd_theme==1.0.0 3 | sphinx_tabs==3.4.0 4 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 119 3 | 4 | [tool.isort] 5 | py_version = 38 6 | line_length = 119 7 | profile = "black" 8 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [wheel] 2 | universal = 1 3 | 4 | [flake8] 5 | max-line-length = 119 6 | 7 | [isort] 8 | multi_line_output = 3 9 | include_trailing_comma = True 10 | line_length = 119 11 | not_skip = __init__.py 12 | 13 | [mypy] 14 | ignore_missing_imports = true 15 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from setuptools import find_packages, setup 4 | 5 | install_requires = [ 6 | "diffusers==0.4.2", 7 | "gradio>=3.1.6", 8 | "torch", 9 | "transformers>=4.21.3", 10 | ] 11 | 12 | dev_requires = [ 13 | "black==22.3.0", 14 | "check-manifest>=0.42,<1", 15 | "sphinx>=5.1.1,<6", 16 | "sphinx_rtd_theme==1.0.0", 17 | "sphinx_tabs==3.4.0", 18 | "flake8==3.8.1", 19 | "isort==5.10.1", 20 | ] 21 | 22 | console_scripts = [ 23 | "diffusionui=diffusionui.cli:diffusionui_cli", 24 | ] 25 | 26 | # Get version from __version__.py file 27 | current_folder = os.path.abspath(os.path.dirname(__file__)) 28 | about = {} 29 | with open( 30 | os.path.join(current_folder, "src", "diffusionui", "__version__.py"), "r" 31 | ) as f: 32 | exec(f.read(), about) 33 | 34 | setup( 35 | name="diffusionui", 36 | version=about["__version__"], 37 | description="Unified Stable Diffusion pipeline for diffusers", 38 | long_description=open("README.md").read(), 39 | long_description_content_type="text/markdown", 40 | url="https://github.com/leszekhanusz/diffusion-ui-backend", 41 | author="Leszek Hanusz", 42 | author_email="leszek.hanusz@gmail.com", 43 | license="Apache", 44 | classifiers=[ 45 | "Development Status :: 5 - Production/Stable", 46 | "Intended Audience :: Developers", 47 | "Intended Audience :: Science/Research", 48 | "License :: OSI Approved :: Apache Software License", 49 | "Topic :: Scientific/Engineering :: Artificial Intelligence", 50 | "Operating System :: OS Independent", 51 | "Programming Language :: Python :: 3", 52 | "Programming Language :: Python :: 3 :: Only", 53 | "Programming Language :: Python :: 3.6", 54 | "Programming Language :: Python :: 3.7", 55 | "Programming Language :: Python :: 3.8", 56 | "Programming Language :: Python :: 3.9", 57 | "Programming Language :: Python :: 3.10", 58 | ], 59 | keywords="diffusers stable-diffusion", 60 | package_dir={"": "src"}, 61 | packages=find_packages("src"), 62 | # PEP-561: https://www.python.org/dev/peps/pep-0561/ 63 | package_data={"diffusionui": ["py.typed"]}, 64 | install_requires=install_requires, 65 | extras_require={ 66 | "dev": dev_requires, 67 | }, 68 | include_package_data=True, 69 | python_requires=">=3.6.0", 70 | zip_safe=False, 71 | platforms="any", 72 | entry_points={"console_scripts": console_scripts}, 73 | ) 74 | -------------------------------------------------------------------------------- /src/diffusionui/__init__.py: -------------------------------------------------------------------------------- 1 | from .__version__ import __version__ 2 | from .pipelines import StableDiffusionPipeline 3 | 4 | __all__ = [ 5 | "__version__", 6 | "StableDiffusionPipeline", 7 | ] 8 | -------------------------------------------------------------------------------- /src/diffusionui/__version__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.4.1" 2 | __api_version__ = 3 3 | -------------------------------------------------------------------------------- /src/diffusionui/cli.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import time 3 | from argparse import ArgumentParser 4 | 5 | import torch 6 | 7 | from .__version__ import __version__ 8 | from .gradio_interface import make_gradio_interface 9 | from .pipelines import StableDiffusionPipeline 10 | 11 | 12 | def get_parser() -> ArgumentParser: 13 | description = """ 14 | Generate a gradio interface providing a unified pipeline for Stable Diffusion 15 | images generations, doing text-to-image, image-to-image and inpainting 16 | using the same interface. 17 | """ 18 | 19 | parser = ArgumentParser( 20 | description=description, 21 | ) 22 | 23 | parser.add_argument("--version", action="version", version=f"v{__version__}") 24 | 25 | parser.add_argument( 26 | "--low-mem", 27 | help="Reduce GPU VRAM usage", 28 | action="store_true", 29 | dest="low_mem", 30 | ) 31 | 32 | parser.add_argument( 33 | "--download-model", 34 | help="Download the Stable Diffusion model", 35 | action="store_true", 36 | dest="download_model", 37 | ) 38 | 39 | parser.add_argument( 40 | "-m", 41 | "--model", 42 | help="choose the stable diffusion model", 43 | dest="model", 44 | default="CompVis/stable-diffusion-v1-4", 45 | ) 46 | 47 | parser.add_argument( 48 | "--disable-nsfw-filter", 49 | help="Disable the NSFW filter", 50 | action="store_true", 51 | dest="disable_nsfw_filter", 52 | ) 53 | 54 | parser.add_argument( 55 | "--share", 56 | help="Create a link to be able to run your model from elsewhere", 57 | action="store_true", 58 | dest="share", 59 | ) 60 | 61 | parser.add_argument( 62 | "--auth", 63 | type=str, 64 | help='gradio authentication. "username:password" or more "user1:pass1,user2:pass2"', 65 | default=None, 66 | ) 67 | 68 | parser.add_argument( 69 | "--access-code", 70 | type=str, 71 | help="Optional access code to limit access to the model without using gradio auth", 72 | default=None, 73 | ) 74 | 75 | parser.add_argument( 76 | "--output-dir", 77 | type=str, 78 | help="Optional path of the folder where images are stored. By default images are not saved.", 79 | default=None, 80 | ) 81 | 82 | return parser 83 | 84 | 85 | def diffusionui_cli(): 86 | 87 | # Get arguments from command line 88 | parser = get_parser() 89 | args = parser.parse_args() 90 | 91 | # Set the pipe arguments depending on options selected 92 | pipe_args = { 93 | "device": "cuda", 94 | "use_auth_token": args.download_model, 95 | "local_files_only": not (args.download_model), 96 | } 97 | 98 | if args.low_mem: 99 | pipe_args["revision"] = "fp16" 100 | pipe_args["torch_dtype"] = torch.float16 101 | 102 | # Make unified diffusers pipe 103 | pipe = StableDiffusionPipeline.from_pretrained( 104 | args.model, 105 | **pipe_args, 106 | ).to("cuda") 107 | 108 | # Disable the nsfw filter if requested 109 | if args.disable_nsfw_filter: 110 | pipe.disable_nsfw_filter() 111 | 112 | # Generate gradio interface 113 | gradio_interface = make_gradio_interface( 114 | pipe, 115 | access_code=args.access_code, 116 | output_dir=args.output_dir, 117 | ) 118 | 119 | if not args.share: 120 | print("\nTo create a public link, use --share") 121 | 122 | # Start it 123 | SERVER_PORT = 7860 124 | while True: 125 | try: 126 | gradio_interface.launch( 127 | server_port=SERVER_PORT, 128 | quiet=True, 129 | share=args.share, 130 | auth=[tuple(cred.split(":")) for cred in args.auth.strip('"').split(",")] if args.auth else None, 131 | ) 132 | except OSError as e: 133 | if str(e).startswith(f"Port {SERVER_PORT} is in use"): 134 | logging.warning(f"Port {SERVER_PORT} is in use. Trying again in 5 seconds.") 135 | time.sleep(5) 136 | continue 137 | break 138 | -------------------------------------------------------------------------------- /src/diffusionui/gradio_interface.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import logging 3 | import os 4 | 5 | import gradio as gr 6 | import torch 7 | from torch import autocast 8 | 9 | from .__version__ import __api_version__ 10 | 11 | 12 | def make_gradio_interface(pipe, access_code, output_dir): 13 | def run_pipe( 14 | *, 15 | prompt, 16 | negative_prompt, 17 | init_image, 18 | mask_image, 19 | nb_steps, 20 | strength, 21 | guidance_scale, 22 | seeds, 23 | pipe, 24 | ): 25 | 26 | seed = seeds[0] 27 | generator = torch.Generator(device="cuda") 28 | generator = generator.manual_seed(seed) 29 | 30 | with autocast("cuda"): 31 | images = pipe( 32 | prompt, 33 | negative_prompt=negative_prompt, 34 | init_image=init_image, 35 | mask_image=mask_image, 36 | strength=strength, 37 | guidance_scale=guidance_scale, 38 | num_inference_steps=nb_steps, 39 | generator=generator, 40 | ).images 41 | 42 | return images 43 | 44 | def gradio_run( 45 | api_version, 46 | prompt, 47 | negative_prompt, 48 | init_image, 49 | mask_image, 50 | nb_images, 51 | nb_steps, 52 | strength, 53 | guidance_scale, 54 | seeds, 55 | provided_access_code, 56 | ): 57 | 58 | if access_code: 59 | if provided_access_code != access_code: 60 | raise Exception("Incorrect access code") 61 | 62 | if api_version != __api_version__: 63 | logging.warning( 64 | f"Backend API version ({__api_version__}) is different than " f"frontend API version ({api_version})." 65 | ) 66 | 67 | if api_version > __api_version__: 68 | 69 | logging.warning("You should update the backend by running " "'pip install diffusionui --upgrade'") 70 | 71 | # Generate seeds if needed 72 | generator = torch.Generator() 73 | 74 | if seeds: 75 | seeds = [int(seed) for seed in seeds.split(",")] 76 | else: 77 | seeds = [generator.seed() for _ in range(nb_images)] 78 | 79 | all_generated_images = [] 80 | 81 | for i in range(nb_images): 82 | 83 | # If we don't have enough seeds, stop generating images 84 | try: 85 | next_seeds = seeds[i:] 86 | if len(next_seeds) == 0: 87 | break 88 | except IndexError: 89 | break 90 | 91 | generated_images = run_pipe( 92 | prompt=prompt, 93 | negative_prompt=negative_prompt, 94 | init_image=init_image, 95 | mask_image=mask_image, 96 | nb_steps=nb_steps, 97 | strength=strength, 98 | guidance_scale=guidance_scale, 99 | seeds=next_seeds, 100 | pipe=pipe, 101 | ) 102 | 103 | all_generated_images.extend(generated_images) 104 | 105 | seeds_str = ",".join([str(seed) for seed in seeds]) 106 | 107 | if output_dir is not None: 108 | 109 | if not os.path.exists(output_dir): 110 | logging.warning(f"Path {output_dir} does not exist. Images are not saved.") 111 | 112 | else: 113 | for index, image in enumerate(all_generated_images): 114 | seed = seeds[index] 115 | hash_image = hashlib.sha1(image.tobytes()).hexdigest() 116 | filename = f"{seed}_{hash_image}.png" 117 | filepath = os.path.join(output_dir, filename) 118 | 119 | image.save(filepath) 120 | 121 | return all_generated_images, seeds_str 122 | 123 | gradio_interface = gr.Interface( 124 | gradio_run, 125 | inputs=[ 126 | gr.Number(label="API Version", value=__api_version__, visible=False), 127 | gr.Textbox(label="Prompt"), 128 | gr.Textbox(label="Negative Prompt"), 129 | gr.Image(type="pil", label="Init image"), 130 | gr.Image(type="pil", label="Mask image"), 131 | gr.Slider(minimum=1, maximum=4, value=2, step=1, label="Number of images"), 132 | gr.Slider(minimum=1, maximum=200, value=50, label="Number of steps"), 133 | gr.Slider(minimum=0, maximum=1, value=0.5, label="Strength"), 134 | gr.Slider(minimum=0, maximum=20, value=7.5, label="Guidance scale"), 135 | gr.Textbox(label="Seeds"), 136 | gr.Textbox(label="Access code", visible=access_code is not None), 137 | ], 138 | outputs=[ 139 | gr.Gallery(label="Images"), 140 | gr.Text(label="Seeds"), 141 | ], 142 | ) 143 | 144 | return gradio_interface 145 | -------------------------------------------------------------------------------- /src/diffusionui/pipelines/README.md: -------------------------------------------------------------------------------- 1 | # Unified Stable Diffusion pipeline 2 | 3 | This repository provides a unified [Stable Diffusion](https://github.com/CompVis/stable-diffusion) pipeline to generate images using the same pipeline with [diffusers](https://github.com/huggingface/diffusers) for: 4 | 5 | - text-to-image 6 | - image-to-image 7 | - inpainting 8 | 9 | This pipeline cannot be imported directly from diffusers because of the [diffusers philosophy](https://github.com/huggingface/diffusers/issues/307). 10 | 11 | ## Installation 12 | 13 | ```bash 14 | pip install diffusionui 15 | ``` 16 | 17 | ## Usage 18 | 19 | ``` 20 | from diffusionui import StableDiffusionPipeline 21 | ``` 22 | 23 | Then use any of the examples from [diffusers](https://github.com/huggingface/diffusers) by replacing `StableDiffusionImg2ImgPipeline` and `StableDiffusionInpaintPipeline` by `StableDiffusionPipeline`. 24 | -------------------------------------------------------------------------------- /src/diffusionui/pipelines/__init__.py: -------------------------------------------------------------------------------- 1 | from .pipeline_stable_diffusion import StableDiffusionPipeline 2 | 3 | __all__ = [ 4 | StableDiffusionPipeline, 5 | ] 6 | -------------------------------------------------------------------------------- /src/diffusionui/pipelines/pipeline_stable_diffusion.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional, Union 2 | 3 | import PIL 4 | import torch 5 | from diffusers import ( 6 | AutoencoderKL, 7 | DDIMScheduler, 8 | DiffusionPipeline, 9 | LMSDiscreteScheduler, 10 | PNDMScheduler, 11 | StableDiffusionImg2ImgPipeline, 12 | StableDiffusionInpaintPipeline, 13 | ) 14 | from diffusers import StableDiffusionPipeline as StableDiffusionText2ImgPipeline 15 | from diffusers import UNet2DConditionModel 16 | from diffusers.pipelines.stable_diffusion import StableDiffusionSafetyChecker 17 | from transformers import CLIPFeatureExtractor, CLIPTextModel, CLIPTokenizer 18 | 19 | 20 | class DummySafetyChecker: 21 | @staticmethod 22 | def __call__(images, clip_input): 23 | return images, False 24 | 25 | 26 | class StableDiffusionPipeline(DiffusionPipeline): 27 | def __init__( 28 | self, 29 | vae: AutoencoderKL, 30 | text_encoder: CLIPTextModel, 31 | tokenizer: CLIPTokenizer, 32 | unet: UNet2DConditionModel, 33 | scheduler: Union[DDIMScheduler, PNDMScheduler, LMSDiscreteScheduler], 34 | safety_checker: StableDiffusionSafetyChecker, 35 | feature_extractor: CLIPFeatureExtractor, 36 | ): 37 | super().__init__() 38 | 39 | scheduler = scheduler.set_format("pt") 40 | 41 | text2img = StableDiffusionText2ImgPipeline( 42 | vae=vae, 43 | text_encoder=text_encoder, 44 | tokenizer=tokenizer, 45 | unet=unet, 46 | scheduler=scheduler, 47 | safety_checker=safety_checker, 48 | feature_extractor=feature_extractor, 49 | ) 50 | 51 | img2img = StableDiffusionImg2ImgPipeline( 52 | vae=vae, 53 | text_encoder=text_encoder, 54 | tokenizer=tokenizer, 55 | unet=unet, 56 | scheduler=scheduler, 57 | safety_checker=safety_checker, 58 | feature_extractor=feature_extractor, 59 | ) 60 | 61 | inpaint = StableDiffusionInpaintPipeline( 62 | vae=vae, 63 | text_encoder=text_encoder, 64 | tokenizer=tokenizer, 65 | unet=unet, 66 | scheduler=scheduler, 67 | safety_checker=safety_checker, 68 | feature_extractor=feature_extractor, 69 | ) 70 | 71 | self.register_modules( 72 | text2img=text2img, 73 | img2img=img2img, 74 | inpaint=inpaint, 75 | ) 76 | 77 | self.register_modules( 78 | vae=vae, 79 | text_encoder=text_encoder, 80 | tokenizer=tokenizer, 81 | unet=unet, 82 | scheduler=scheduler, 83 | safety_checker=safety_checker, 84 | feature_extractor=feature_extractor, 85 | ) 86 | 87 | def disable_nsfw_filter(self): 88 | self.safety_checker = DummySafetyChecker() 89 | self.text2img.safety_checker = self.safety_checker 90 | self.img2img.safety_checker = self.safety_checker 91 | self.inpaint.safety_checker = self.safety_checker 92 | 93 | def __call__( 94 | self, 95 | prompt: Union[str, List[str]], 96 | init_image: Optional[Union[torch.FloatTensor, PIL.Image.Image]] = None, 97 | mask_image: Optional[Union[torch.FloatTensor, PIL.Image.Image]] = None, 98 | strength: float = 0.8, 99 | height: Optional[int] = 512, 100 | width: Optional[int] = 512, 101 | num_inference_steps: Optional[int] = 50, 102 | guidance_scale: Optional[float] = 7.5, 103 | eta: Optional[float] = 0.0, 104 | generator: Optional[torch.Generator] = None, 105 | latents: Optional[torch.FloatTensor] = None, 106 | output_type: Optional[str] = "pil", 107 | **kwargs, 108 | ): 109 | 110 | if init_image is None: 111 | result = self.text2img( 112 | prompt=prompt, 113 | height=height, 114 | width=width, 115 | num_inference_steps=num_inference_steps, 116 | guidance_scale=guidance_scale, 117 | eta=eta, 118 | generator=generator, 119 | latents=latents, 120 | output_type=output_type, 121 | **kwargs, 122 | ) 123 | else: 124 | if mask_image is None: 125 | result = self.img2img( 126 | prompt=prompt, 127 | init_image=init_image, 128 | strength=strength, 129 | num_inference_steps=num_inference_steps, 130 | guidance_scale=guidance_scale, 131 | eta=eta, 132 | generator=generator, 133 | output_type=output_type, 134 | **kwargs, 135 | ) 136 | else: 137 | result = self.inpaint( 138 | prompt=prompt, 139 | init_image=init_image, 140 | mask_image=mask_image, 141 | strength=strength, 142 | num_inference_steps=num_inference_steps, 143 | guidance_scale=guidance_scale, 144 | eta=eta, 145 | generator=generator, 146 | output_type=output_type, 147 | **kwargs, 148 | ) 149 | 150 | return result 151 | -------------------------------------------------------------------------------- /src/diffusionui/py.typed: -------------------------------------------------------------------------------- 1 | # Marker file for PEP 561. 2 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = 3 | black,flake8,import-order,manifest 4 | 5 | [gh-actions] 6 | python = 7 | 3.6: py36 8 | 3.7: py37 9 | 3.8: py38 10 | 3.9: py39 11 | 3.10: py310 12 | 13 | [testenv:black] 14 | basepython = python3.8 15 | deps = -e.[dev] 16 | commands = 17 | black --check src 18 | 19 | [testenv:flake8] 20 | basepython = python3.8 21 | deps = -e.[dev] 22 | commands = 23 | flake8 src 24 | 25 | [testenv:import-order] 26 | basepython = python3.8 27 | deps = -e.[dev] 28 | commands = 29 | isort --check-only --diff src/diffusionui 30 | 31 | [testenv:manifest] 32 | basepython = python3.8 33 | deps = -e.[dev] 34 | commands = 35 | check-manifest -v 36 | --------------------------------------------------------------------------------