diff --git a/README.md b/README.md index bc62945c0c5..bdf468fc018 100644 --- a/README.md +++ b/README.md @@ -1,205 +1,227 @@ -# Stable Diffusion web UI -A web interface for Stable Diffusion, implemented using Gradio library. - -![](screenshot.png) - -## Features -[Detailed feature showcase with images](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features): -- Original txt2img and img2img modes -- One click install and run script (but you still must install python and git) -- Outpainting -- Inpainting -- Color Sketch -- Prompt Matrix -- Stable Diffusion Upscale -- Attention, specify parts of text that the model should pay more attention to - - a man in a `((tuxedo))` - will pay more attention to tuxedo - - a man in a `(tuxedo:1.21)` - alternative syntax - - select text and press `Ctrl+Up` or `Ctrl+Down` (or `Command+Up` or `Command+Down` if you're on a MacOS) to automatically adjust attention to selected text (code contributed by anonymous user) -- Loopback, run img2img processing multiple times -- X/Y/Z plot, a way to draw a 3 dimensional plot of images with different parameters -- Textual Inversion - - have as many embeddings as you want and use any names you like for them - - use multiple embeddings with different numbers of vectors per token - - works with half precision floating point numbers - - train embeddings on 8GB (also reports of 6GB working) -- Extras tab with: - - GFPGAN, neural network that fixes faces - - CodeFormer, face restoration tool as an alternative to GFPGAN - - RealESRGAN, neural network upscaler - - ESRGAN, neural network upscaler with a lot of third party models - - SwinIR and Swin2SR ([see here](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/2092)), neural network upscalers - - LDSR, Latent diffusion super resolution upscaling -- Resizing aspect ratio options -- Sampling method selection - - Adjust sampler eta values (noise multiplier) - - More advanced noise setting options -- Interrupt processing at any time -- 4GB video card support (also reports of 2GB working) -- Correct seeds for batches -- Live prompt token length validation -- Generation parameters - - parameters you used to generate images are saved with that image - - in PNG chunks for PNG, in EXIF for JPEG - - can drag the image to PNG info tab to restore generation parameters and automatically copy them into UI - - can be disabled in settings - - drag and drop an image/text-parameters to promptbox -- Read Generation Parameters Button, loads parameters in promptbox to UI -- Settings page -- Running arbitrary python code from UI (must run with `--allow-code` to enable) -- Mouseover hints for most UI elements -- Possible to change defaults/mix/max/step values for UI elements via text config -- Tiling support, a checkbox to create images that can be tiled like textures -- Progress bar and live image generation preview - - Can use a separate neural network to produce previews with almost none VRAM or compute requirement -- Negative prompt, an extra text field that allows you to list what you don't want to see in generated image -- Styles, a way to save part of prompt and easily apply them via dropdown later -- Variations, a way to generate same image but with tiny differences -- Seed resizing, a way to generate same image but at slightly different resolution -- CLIP interrogator, a button that tries to guess prompt from an image -- Prompt Editing, a way to change prompt mid-generation, say to start making a watermelon and switch to anime girl midway -- Batch Processing, process a group of files using img2img -- Img2img Alternative, reverse Euler method of cross attention control -- Highres Fix, a convenience option to produce high resolution pictures in one click without usual distortions -- Reloading checkpoints on the fly -- Checkpoint Merger, a tab that allows you to merge up to 3 checkpoints into one -- [Custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Custom-Scripts) with many extensions from community -- [Composable-Diffusion](https://energy-based-model.github.io/Compositional-Visual-Generation-with-Composable-Diffusion-Models/), a way to use multiple prompts at once - - separate prompts using uppercase `AND` - - also supports weights for prompts: `a cat :1.2 AND a dog AND a penguin :2.2` -- No token limit for prompts (original stable diffusion lets you use up to 75 tokens) -- DeepDanbooru integration, creates danbooru style tags for anime prompts -- [xformers](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers), major speed increase for select cards: (add `--xformers` to commandline args) -- via extension: [History tab](https://github.com/yfszzx/stable-diffusion-webui-images-browser): view, direct and delete images conveniently within the UI -- Generate forever option -- Training tab - - hypernetworks and embeddings options - - Preprocessing images: cropping, mirroring, autotagging using BLIP or deepdanbooru (for anime) -- Clip skip -- Hypernetworks -- Loras (same as Hypernetworks but more pretty) -- A separate UI where you can choose, with preview, which embeddings, hypernetworks or Loras to add to your prompt -- Can select to load a different VAE from settings screen -- Estimated completion time in progress bar -- API -- Support for dedicated [inpainting model](https://github.com/runwayml/stable-diffusion#inpainting-with-stable-diffusion) by RunwayML -- via extension: [Aesthetic Gradients](https://github.com/AUTOMATIC1111/stable-diffusion-webui-aesthetic-gradients), a way to generate images with a specific aesthetic by using clip images embeds (implementation of [https://github.com/vicgalle/stable-diffusion-aesthetic-gradients](https://github.com/vicgalle/stable-diffusion-aesthetic-gradients)) -- [Stable Diffusion 2.0](https://github.com/Stability-AI/stablediffusion) support - see [wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#stable-diffusion-20) for instructions -- [Alt-Diffusion](https://arxiv.org/abs/2211.06679) support - see [wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#alt-diffusion) for instructions -- Now without any bad letters! -- Load checkpoints in safetensors format -- Eased resolution restriction: generated image's dimensions must be a multiple of 8 rather than 64 -- Now with a license! -- Reorder elements in the UI from settings screen -- [Segmind Stable Diffusion](https://huggingface.co/segmind/SSD-1B) support - -## Installation and Running -Make sure the required [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) are met and follow the instructions available for: -- [NVidia](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) (recommended) -- [AMD](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-AMD-GPUs) GPUs. -- [Intel CPUs, Intel GPUs (both integrated and discrete)](https://github.com/openvinotoolkit/stable-diffusion-webui/wiki/Installation-on-Intel-Silicon) (external wiki page) -- [Ascend NPUs](https://github.com/wangshuai09/stable-diffusion-webui/wiki/Install-and-run-on-Ascend-NPUs) (external wiki page) - -Alternatively, use online services (like Google Colab): - -- [List of Online Services](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Online-Services) - -### Installation on Windows 10/11 with NVidia-GPUs using release package -1. Download `sd.webui.zip` from [v1.0.0-pre](https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases/tag/v1.0.0-pre) and extract its contents. -2. Run `update.bat`. -3. Run `run.bat`. -> For more details see [Install-and-Run-on-NVidia-GPUs](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) - -### Automatic Installation on Windows -1. Install [Python 3.10.6](https://www.python.org/downloads/release/python-3106/) (Newer version of Python does not support torch), checking "Add Python to PATH". -2. Install [git](https://git-scm.com/download/win). -3. Download the stable-diffusion-webui repository, for example by running `git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git`. -4. Run `webui-user.bat` from Windows Explorer as normal, non-administrator, user. - -### Automatic Installation on Linux -1. Install the dependencies: -```bash -# Debian-based: -sudo apt install wget git python3 python3-venv libgl1 libglib2.0-0 -# Red Hat-based: -sudo dnf install wget git python3 gperftools-libs libglvnd-glx -# openSUSE-based: -sudo zypper install wget git python3 libtcmalloc4 libglvnd -# Arch-based: -sudo pacman -S wget git python3 -``` -If your system is very new, you need to install python3.11 or python3.10: -```bash -# Ubuntu 24.04 -sudo add-apt-repository ppa:deadsnakes/ppa -sudo apt update -sudo apt install python3.11 - -# Manjaro/Arch -sudo pacman -S yay -yay -S python311 # do not confuse with python3.11 package - -# Only for 3.11 -# Then set up env variable in launch script -export python_cmd="python3.11" -# or in webui-user.sh -python_cmd="python3.11" -``` -2. Navigate to the directory you would like the webui to be installed and execute the following command: -```bash -wget -q https://raw.githubusercontent.com/AUTOMATIC1111/stable-diffusion-webui/master/webui.sh -``` -Or just clone the repo wherever you want: -```bash -git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui -``` - -3. Run `webui.sh`. -4. Check `webui-user.sh` for options. -### Installation on Apple Silicon - -Find the instructions [here](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Installation-on-Apple-Silicon). - -## Contributing -Here's how to add code to this repo: [Contributing](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Contributing) - -## Documentation - -The documentation was moved from this README over to the project's [wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki). - -For the purposes of getting Google and other search engines to crawl the wiki, here's a link to the (not for humans) [crawlable wiki](https://github-wiki-see.page/m/AUTOMATIC1111/stable-diffusion-webui/wiki). - -## Credits -Licenses for borrowed code can be found in `Settings -> Licenses` screen, and also in `html/licenses.html` file. - -- Stable Diffusion - https://github.com/Stability-AI/stablediffusion, https://github.com/CompVis/taming-transformers, https://github.com/mcmonkey4eva/sd3-ref -- k-diffusion - https://github.com/crowsonkb/k-diffusion.git -- Spandrel - https://github.com/chaiNNer-org/spandrel implementing - - GFPGAN - https://github.com/TencentARC/GFPGAN.git - - CodeFormer - https://github.com/sczhou/CodeFormer - - ESRGAN - https://github.com/xinntao/ESRGAN - - SwinIR - https://github.com/JingyunLiang/SwinIR - - Swin2SR - https://github.com/mv-lab/swin2sr -- LDSR - https://github.com/Hafiidz/latent-diffusion -- MiDaS - https://github.com/isl-org/MiDaS -- Ideas for optimizations - https://github.com/basujindal/stable-diffusion -- Cross Attention layer optimization - Doggettx - https://github.com/Doggettx/stable-diffusion, original idea for prompt editing. -- Cross Attention layer optimization - InvokeAI, lstein - https://github.com/invoke-ai/InvokeAI (originally http://github.com/lstein/stable-diffusion) -- Sub-quadratic Cross Attention layer optimization - Alex Birch (https://github.com/Birch-san/diffusers/pull/1), Amin Rezaei (https://github.com/AminRezaei0x443/memory-efficient-attention) -- Textual Inversion - Rinon Gal - https://github.com/rinongal/textual_inversion (we're not using his code, but we are using his ideas). -- Idea for SD upscale - https://github.com/jquesnelle/txt2imghd -- Noise generation for outpainting mk2 - https://github.com/parlance-zz/g-diffuser-bot -- CLIP interrogator idea and borrowing some code - https://github.com/pharmapsychotic/clip-interrogator -- Idea for Composable Diffusion - https://github.com/energy-based-model/Compositional-Visual-Generation-with-Composable-Diffusion-Models-PyTorch -- xformers - https://github.com/facebookresearch/xformers -- DeepDanbooru - interrogator for anime diffusers https://github.com/KichangKim/DeepDanbooru -- Sampling in float32 precision from a float16 UNet - marunine for the idea, Birch-san for the example Diffusers implementation (https://github.com/Birch-san/diffusers-play/tree/92feee6) -- Instruct pix2pix - Tim Brooks (star), Aleksander Holynski (star), Alexei A. Efros (no star) - https://github.com/timothybrooks/instruct-pix2pix -- Security advice - RyotaK -- UniPC sampler - Wenliang Zhao - https://github.com/wl-zhao/UniPC -- TAESD - Ollin Boer Bohan - https://github.com/madebyollin/taesd -- LyCORIS - KohakuBlueleaf -- Restart sampling - lambertae - https://github.com/Newbeeer/diffusion_restart_sampling -- Hypertile - tfernd - https://github.com/tfernd/HyperTile -- Initial Gradio script - posted on 4chan by an Anonymous user. Thank you Anonymous user. -- (You) +# Stable Diffusion web UI +A web interface for Stable Diffusion, implemented using Gradio library. + +![](screenshot.png) + +## Features +[Detailed feature showcase with images](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features): +- Original txt2img and img2img modes +- One click install and run script (but you still must install python and git) +- Outpainting +- Inpainting +- Color Sketch +- Prompt Matrix +- Stable Diffusion Upscale +- Attention, specify parts of text that the model should pay more attention to + - a man in a `((tuxedo))` - will pay more attention to tuxedo + - a man in a `(tuxedo:1.21)` - alternative syntax + - select text and press `Ctrl+Up` or `Ctrl+Down` (or `Command+Up` or `Command+Down` if you're on a MacOS) to automatically adjust attention to selected text (code contributed by anonymous user) +- Loopback, run img2img processing multiple times +- X/Y/Z plot, a way to draw a 3 dimensional plot of images with different parameters +- Textual Inversion + - have as many embeddings as you want and use any names you like for them + - use multiple embeddings with different numbers of vectors per token + - works with half precision floating point numbers + - train embeddings on 8GB (also reports of 6GB working) +- Extras tab with: + - GFPGAN, neural network that fixes faces + - CodeFormer, face restoration tool as an alternative to GFPGAN + - RealESRGAN, neural network upscaler + - ESRGAN, neural network upscaler with a lot of third party models + - SwinIR and Swin2SR ([see here](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/2092)), neural network upscalers + - LDSR, Latent diffusion super resolution upscaling +- Resizing aspect ratio options +- Sampling method selection + - Adjust sampler eta values (noise multiplier) + - More advanced noise setting options +- Interrupt processing at any time +- 4GB video card support (also reports of 2GB working) +- Correct seeds for batches +- Live prompt token length validation +- Generation parameters + - parameters you used to generate images are saved with that image + - in PNG chunks for PNG, in EXIF for JPEG + - can drag the image to PNG info tab to restore generation parameters and automatically copy them into UI + - can be disabled in settings + - drag and drop an image/text-parameters to promptbox +- Read Generation Parameters Button, loads parameters in promptbox to UI +- Settings page +- Running arbitrary python code from UI (must run with `--allow-code` to enable) +- Mouseover hints for most UI elements +- Possible to change defaults/mix/max/step values for UI elements via text config +- Tiling support, a checkbox to create images that can be tiled like textures +- Progress bar and live image generation preview + - Can use a separate neural network to produce previews with almost none VRAM or compute requirement +- Negative prompt, an extra text field that allows you to list what you don't want to see in generated image +- Styles, a way to save part of prompt and easily apply them via dropdown later +- Variations, a way to generate same image but with tiny differences +- Seed resizing, a way to generate same image but at slightly different resolution +- CLIP interrogator, a button that tries to guess prompt from an image +- Prompt Editing, a way to change prompt mid-generation, say to start making a watermelon and switch to anime girl midway +- Batch Processing, process a group of files using img2img +- Img2img Alternative, reverse Euler method of cross attention control +- Highres Fix, a convenience option to produce high resolution pictures in one click without usual distortions +- Reloading checkpoints on the fly +- Checkpoint Merger, a tab that allows you to merge up to 3 checkpoints into one +- [Custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Custom-Scripts) with many extensions from community +- [Composable-Diffusion](https://energy-based-model.github.io/Compositional-Visual-Generation-with-Composable-Diffusion-Models/), a way to use multiple prompts at once + - separate prompts using uppercase `AND` + - also supports weights for prompts: `a cat :1.2 AND a dog AND a penguin :2.2` +- No token limit for prompts (original stable diffusion lets you use up to 75 tokens) +- DeepDanbooru integration, creates danbooru style tags for anime prompts +- [xformers](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers), major speed increase for select cards: (add `--xformers` to commandline args) +- via extension: [History tab](https://github.com/yfszzx/stable-diffusion-webui-images-browser): view, direct and delete images conveniently within the UI +- Generate forever option +- Training tab + - hypernetworks and embeddings options + - Preprocessing images: cropping, mirroring, autotagging using BLIP or deepdanbooru (for anime) +- Clip skip +- Hypernetworks +- Loras (same as Hypernetworks but more pretty) +- A separate UI where you can choose, with preview, which embeddings, hypernetworks or Loras to add to your prompt +- Can select to load a different VAE from settings screen +- Estimated completion time in progress bar +- API +- Support for dedicated [inpainting model](https://github.com/runwayml/stable-diffusion#inpainting-with-stable-diffusion) by RunwayML +- via extension: [Aesthetic Gradients](https://github.com/AUTOMATIC1111/stable-diffusion-webui-aesthetic-gradients), a way to generate images with a specific aesthetic by using clip images embeds (implementation of [https://github.com/vicgalle/stable-diffusion-aesthetic-gradients](https://github.com/vicgalle/stable-diffusion-aesthetic-gradients)) +- [Stable Diffusion 2.0](https://github.com/Stability-AI/stablediffusion) support - see [wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#stable-diffusion-20) for instructions +- [Alt-Diffusion](https://arxiv.org/abs/2211.06679) support - see [wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#alt-diffusion) for instructions +- Now without any bad letters! +- Load checkpoints in safetensors format +- Eased resolution restriction: generated image's dimensions must be a multiple of 8 rather than 64 +- Now with a license! +- Reorder elements in the UI from settings screen +- [Segmind Stable Diffusion](https://huggingface.co/segmind/SSD-1B) support + +## Installation and Running +Make sure the required [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) are met and follow the instructions available for: +- [NVidia](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) (recommended) +- [AMD](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-AMD-GPUs) GPUs. +- [Intel CPUs, Intel GPUs (both integrated and discrete)](https://github.com/openvinotoolkit/stable-diffusion-webui/wiki/Installation-on-Intel-Silicon) (external wiki page) +- [Ascend NPUs](https://github.com/wangshuai09/stable-diffusion-webui/wiki/Install-and-run-on-Ascend-NPUs) (external wiki page) + +Alternatively, use online services (like Google Colab): + +- [List of Online Services](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Online-Services) + +### Installation on Windows 10/11 with NVidia-GPUs using release package +1. Download `sd.webui.zip` from [v1.0.0-pre](https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases/tag/v1.0.0-pre) and extract its contents. +2. Run `update.bat`. +3. Run `run.bat`. +> For more details see [Install-and-Run-on-NVidia-GPUs](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) + +### Automatic Installation on Windows +1. Install [Python 3.10.6](https://www.python.org/downloads/release/python-3106/) (Newer version of Python does not support torch), checking "Add Python to PATH". +2. Install [git](https://git-scm.com/download/win). +3. Download the stable-diffusion-webui repository, for example by running `git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git`. +4. Run `webui-user.bat` from Windows Explorer as normal, non-administrator, user. + +### Automatic Installation on Linux +1. Install the dependencies: +```bash +# Debian-based: +sudo apt install wget git python3 python3-venv libgl1 libglib2.0-0 +# Red Hat-based: +sudo dnf install wget git python3 gperftools-libs libglvnd-glx +# openSUSE-based: +sudo zypper install wget git python3 libtcmalloc4 libglvnd +# Arch-based: +sudo pacman -S wget git python3 +``` +If your system is very new, you need to install python3.11 or python3.10: +```bash +# Ubuntu 24.04 +sudo add-apt-repository ppa:deadsnakes/ppa +sudo apt update +sudo apt install python3.11 + +# Manjaro/Arch +sudo pacman -S yay +yay -S python311 # do not confuse with python3.11 package + +# Only for 3.11 +# Then set up env variable in launch script +export python_cmd="python3.11" +# or in webui-user.sh +python_cmd="python3.11" +``` +2. Navigate to the directory you would like the webui to be installed and execute the following command: +```bash +wget -q https://raw.githubusercontent.com/AUTOMATIC1111/stable-diffusion-webui/master/webui.sh +``` +Or just clone the repo wherever you want: +```bash +git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui +``` + +3. Run `webui.sh`. +4. Check `webui-user.sh` for options. +### Installation on Apple Silicon + +Find the instructions [here](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Installation-on-Apple-Silicon). + +### Troubleshooting Network Issues + +If you encounter network-related issues while cloning repositories or installing packages, follow these steps: + +1. **Check Network Connectivity**: Ensure that your internet connection is stable and working. You can use the `ping` command to check connectivity to `github.com`: + ```bash + ping github.com + ``` + +2. **Set Up Proxy**: If you are behind a proxy, configure your proxy settings for `git` and `pip`. Replace `ip:port` with your proxy's IP address and port: + ```bash + git config --global http.proxy http://ip:port + git config --global https.proxy http://ip:port + pip config set global.proxy http://ip:port + ``` + +3. **Retry Mechanism**: If the issue persists, you can add a retry mechanism to the `git_clone` function in `modules/launch_utils.py` to handle transient network issues. This will automatically retry the cloning process a few times before failing. + +4. **Check Firewall and Security Software**: Ensure that your firewall or security software is not blocking the connection to `github.com`. + +5. **Use VPN**: If you are in a region with restricted access to certain websites, consider using a VPN to bypass these restrictions. + +## Contributing +Here's how to add code to this repo: [Contributing](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Contributing) + +## Documentation + +The documentation was moved from this README over to the project's [wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki). + +For the purposes of getting Google and other search engines to crawl the wiki, here's a link to the (not for humans) [crawlable wiki](https://github-wiki-see.page/m/AUTOMATIC1111/stable-diffusion-webui/wiki). + +## Credits +Licenses for borrowed code can be found in `Settings -> Licenses` screen, and also in `html/licenses.html` file. + +- Stable Diffusion - https://github.com/Stability-AI/stablediffusion, https://github.com/CompVis/taming-transformers, https://github.com/mcmonkey4eva/sd3-ref +- k-diffusion - https://github.com/crowsonkb/k-diffusion.git +- Spandrel - https://github.com/chaiNNer-org/spandrel implementing + - GFPGAN - https://github.com/TencentARC/GFPGAN.git + - CodeFormer - https://github.com/sczhou/CodeFormer + - ESRGAN - https://github.com/xinntao/ESRGAN + - SwinIR - https://github.com/JingyunLiang/SwinIR + - Swin2SR - https://github.com/mv-lab/swin2sr +- LDSR - https://github.com/Hafiidz/latent-diffusion +- MiDaS - https://github.com/isl-org/MiDaS +- Ideas for optimizations - https://github.com/basujindal/stable-diffusion +- Cross Attention layer optimization - Doggettx - https://github.com/Doggettx/stable-diffusion, original idea for prompt editing. +- Cross Attention layer optimization - InvokeAI, lstein - https://github.com/invoke-ai/InvokeAI (originally http://github.com/lstein/stable-diffusion) +- Sub-quadratic Cross Attention layer optimization - Alex Birch (https://github.com/Birch-san/diffusers/pull/1), Amin Rezaei (https://github.com/AminRezaei0x443/memory-efficient-attention) +- Textual Inversion - Rinon Gal - https://github.com/rinongal/textual_inversion (we're not using his code, but we are using his ideas). +- Idea for SD upscale - https://github.com/jquesnelle/txt2imghd +- Noise generation for outpainting mk2 - https://github.com/parlance-zz/g-diffuser-bot +- CLIP interrogator idea and borrowing some code - https://github.com/pharmapsychotic/clip-interrogator +- Idea for Composable Diffusion - https://github.com/energy-based-model/Compositional-Visual-Generation-with-Composable-Diffusion-Models-PyTorch +- xformers - https://github.com/facebookresearch/xformers +- DeepDanbooru - interrogator for anime diffusers https://github.com/KichangKim/DeepDanbooru +- Sampling in float32 precision from a float16 UNet - marunine for the idea, Birch-san for the example Diffusers implementation (https://github.com/Birch-san/diffusers-play/tree/92feee6) +- Instruct pix2pix - Tim Brooks (star), Aleksander Holynski (star), Alexei A. Efros (no star) - https://github.com/timothybrooks/instruct-pix2pix +- Security advice - RyotaK +- UniPC sampler - Wenliang Zhao - https://github.com/wl-zhao/UniPC +- TAESD - Ollin Boer Bohan - https://github.com/madebyollin/taesd +- LyCORIS - KohakuBlueleaf +- Restart sampling - lambertae - https://github.com/Newbeeer/diffusion_restart_sampling +- Hypertile - tfernd - https://github.com/tfernd/HyperTile +- Initial Gradio script - posted on 4chan by an Anonymous user. Thank you Anonymous user. +- (You) diff --git a/launch.py b/launch.py index f83820d2534..2f28f69f4c7 100644 --- a/launch.py +++ b/launch.py @@ -1,48 +1,61 @@ -from modules import launch_utils - -args = launch_utils.args -python = launch_utils.python -git = launch_utils.git -index_url = launch_utils.index_url -dir_repos = launch_utils.dir_repos - -commit_hash = launch_utils.commit_hash -git_tag = launch_utils.git_tag - -run = launch_utils.run -is_installed = launch_utils.is_installed -repo_dir = launch_utils.repo_dir - -run_pip = launch_utils.run_pip -check_run_python = launch_utils.check_run_python -git_clone = launch_utils.git_clone -git_pull_recursive = launch_utils.git_pull_recursive -list_extensions = launch_utils.list_extensions -run_extension_installer = launch_utils.run_extension_installer -prepare_environment = launch_utils.prepare_environment -configure_for_tests = launch_utils.configure_for_tests -start = launch_utils.start - - -def main(): - if args.dump_sysinfo: - filename = launch_utils.dump_sysinfo() - - print(f"Sysinfo saved as {filename}. Exiting...") - - exit(0) - - launch_utils.startup_timer.record("initial startup") - - with launch_utils.startup_timer.subcategory("prepare environment"): - if not args.skip_prepare_environment: - prepare_environment() - - if args.test_server: - configure_for_tests() - - start() - - -if __name__ == "__main__": - main() +import socket +from modules import launch_utils + +args = launch_utils.args +python = launch_utils.python +git = launch_utils.git +index_url = launch_utils.index_url +dir_repos = launch_utils.dir_repos + +commit_hash = launch_utils.commit_hash +git_tag = launch_utils.git_tag + +run = launch_utils.run +is_installed = launch_utils.is_installed +repo_dir = launch_utils.repo_dir + +run_pip = launch_utils.run_pip +check_run_python = launch_utils.check_run_python +git_clone = launch_utils.git_clone +git_pull_recursive = launch_utils.git_pull_recursive +list_extensions = launch_utils.list_extensions +run_extension_installer = launch_utils.run_extension_installer +prepare_environment = launch_utils.prepare_environment +configure_for_tests = launch_utils.configure_for_tests +start = launch_utils.start + + +def check_network_connectivity(): + try: + socket.create_connection(("www.github.com", 80)) + return True + except OSError: + return False + + +def main(): + if args.dump_sysinfo: + filename = launch_utils.dump_sysinfo() + + print(f"Sysinfo saved as {filename}. Exiting...") + + exit(0) + + launch_utils.startup_timer.record("initial startup") + + with launch_utils.startup_timer.subcategory("prepare environment"): + if not args.skip_prepare_environment: + if check_network_connectivity(): + prepare_environment() + else: + print("Network connectivity check failed. Please check your network settings and try again.") + exit(1) + + if args.test_server: + configure_for_tests() + + start() + + +if __name__ == "__main__": + main() diff --git a/modules/launch_utils.py b/modules/launch_utils.py index 20c7dc127a7..8815ad927bb 100644 --- a/modules/launch_utils.py +++ b/modules/launch_utils.py @@ -1,482 +1,488 @@ -# this scripts installs necessary requirements and launches main program in webui.py -import logging -import re -import subprocess -import os -import shutil -import sys -import importlib.util -import importlib.metadata -import platform -import json -import shlex -from functools import lru_cache - -from modules import cmd_args, errors -from modules.paths_internal import script_path, extensions_dir -from modules.timer import startup_timer -from modules import logging_config - -args, _ = cmd_args.parser.parse_known_args() -logging_config.setup_logging(args.loglevel) - -python = sys.executable -git = os.environ.get('GIT', "git") -index_url = os.environ.get('INDEX_URL', "") -dir_repos = "repositories" - -# Whether to default to printing command output -default_command_live = (os.environ.get('WEBUI_LAUNCH_LIVE_OUTPUT') == "1") - -os.environ.setdefault('GRADIO_ANALYTICS_ENABLED', 'False') - - -def check_python_version(): - is_windows = platform.system() == "Windows" - major = sys.version_info.major - minor = sys.version_info.minor - micro = sys.version_info.micro - - if is_windows: - supported_minors = [10] - else: - supported_minors = [7, 8, 9, 10, 11] - - if not (major == 3 and minor in supported_minors): - import modules.errors - - modules.errors.print_error_explanation(f""" -INCOMPATIBLE PYTHON VERSION - -This program is tested with 3.10.6 Python, but you have {major}.{minor}.{micro}. -If you encounter an error with "RuntimeError: Couldn't install torch." message, -or any other error regarding unsuccessful package (library) installation, -please downgrade (or upgrade) to the latest version of 3.10 Python -and delete current Python and "venv" folder in WebUI's directory. - -You can download 3.10 Python from here: https://www.python.org/downloads/release/python-3106/ - -{"Alternatively, use a binary release of WebUI: https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases/tag/v1.0.0-pre" if is_windows else ""} - -Use --skip-python-version-check to suppress this warning. -""") - - -@lru_cache() -def commit_hash(): - try: - return subprocess.check_output([git, "-C", script_path, "rev-parse", "HEAD"], shell=False, encoding='utf8').strip() - except Exception: - return "" - - -@lru_cache() -def git_tag(): - try: - return subprocess.check_output([git, "-C", script_path, "describe", "--tags"], shell=False, encoding='utf8').strip() - except Exception: - try: - - changelog_md = os.path.join(script_path, "CHANGELOG.md") - with open(changelog_md, "r", encoding="utf-8") as file: - line = next((line.strip() for line in file if line.strip()), "") - line = line.replace("## ", "") - return line - except Exception: - return "" - - -def run(command, desc=None, errdesc=None, custom_env=None, live: bool = default_command_live) -> str: - if desc is not None: - print(desc) - - run_kwargs = { - "args": command, - "shell": True, - "env": os.environ if custom_env is None else custom_env, - "encoding": 'utf8', - "errors": 'ignore', - } - - if not live: - run_kwargs["stdout"] = run_kwargs["stderr"] = subprocess.PIPE - - result = subprocess.run(**run_kwargs) - - if result.returncode != 0: - error_bits = [ - f"{errdesc or 'Error running command'}.", - f"Command: {command}", - f"Error code: {result.returncode}", - ] - if result.stdout: - error_bits.append(f"stdout: {result.stdout}") - if result.stderr: - error_bits.append(f"stderr: {result.stderr}") - raise RuntimeError("\n".join(error_bits)) - - return (result.stdout or "") - - -def is_installed(package): - try: - dist = importlib.metadata.distribution(package) - except importlib.metadata.PackageNotFoundError: - try: - spec = importlib.util.find_spec(package) - except ModuleNotFoundError: - return False - - return spec is not None - - return dist is not None - - -def repo_dir(name): - return os.path.join(script_path, dir_repos, name) - - -def run_pip(command, desc=None, live=default_command_live): - if args.skip_install: - return - - index_url_line = f' --index-url {index_url}' if index_url != '' else '' - return run(f'"{python}" -m pip {command} --prefer-binary{index_url_line}', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}", live=live) - - -def check_run_python(code: str) -> bool: - result = subprocess.run([python, "-c", code], capture_output=True, shell=False) - return result.returncode == 0 - - -def git_fix_workspace(dir, name): - run(f'"{git}" -C "{dir}" fetch --refetch --no-auto-gc', f"Fetching all contents for {name}", f"Couldn't fetch {name}", live=True) - run(f'"{git}" -C "{dir}" gc --aggressive --prune=now', f"Pruning {name}", f"Couldn't prune {name}", live=True) - return - - -def run_git(dir, name, command, desc=None, errdesc=None, custom_env=None, live: bool = default_command_live, autofix=True): - try: - return run(f'"{git}" -C "{dir}" {command}', desc=desc, errdesc=errdesc, custom_env=custom_env, live=live) - except RuntimeError: - if not autofix: - raise - - print(f"{errdesc}, attempting autofix...") - git_fix_workspace(dir, name) - - return run(f'"{git}" -C "{dir}" {command}', desc=desc, errdesc=errdesc, custom_env=custom_env, live=live) - - -def git_clone(url, dir, name, commithash=None): - # TODO clone into temporary dir and move if successful - - if os.path.exists(dir): - if commithash is None: - return - - current_hash = run_git(dir, name, 'rev-parse HEAD', None, f"Couldn't determine {name}'s hash: {commithash}", live=False).strip() - if current_hash == commithash: - return - - if run_git(dir, name, 'config --get remote.origin.url', None, f"Couldn't determine {name}'s origin URL", live=False).strip() != url: - run_git(dir, name, f'remote set-url origin "{url}"', None, f"Failed to set {name}'s origin URL", live=False) - - run_git(dir, name, 'fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}", autofix=False) - - run_git(dir, name, f'checkout {commithash}', f"Checking out commit for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}", live=True) - - return - - try: - run(f'"{git}" clone --config core.filemode=false "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}", live=True) - except RuntimeError: - shutil.rmtree(dir, ignore_errors=True) - raise - - if commithash is not None: - run(f'"{git}" -C "{dir}" checkout {commithash}', None, "Couldn't checkout {name}'s hash: {commithash}") - - -def git_pull_recursive(dir): - for subdir, _, _ in os.walk(dir): - if os.path.exists(os.path.join(subdir, '.git')): - try: - output = subprocess.check_output([git, '-C', subdir, 'pull', '--autostash']) - print(f"Pulled changes for repository in '{subdir}':\n{output.decode('utf-8').strip()}\n") - except subprocess.CalledProcessError as e: - print(f"Couldn't perform 'git pull' on repository in '{subdir}':\n{e.output.decode('utf-8').strip()}\n") - - -def version_check(commit): - try: - import requests - commits = requests.get('https://api.github.com/repos/AUTOMATIC1111/stable-diffusion-webui/branches/master').json() - if commit != "" and commits['commit']['sha'] != commit: - print("--------------------------------------------------------") - print("| You are not up to date with the most recent release. |") - print("| Consider running `git pull` to update. |") - print("--------------------------------------------------------") - elif commits['commit']['sha'] == commit: - print("You are up to date with the most recent release.") - else: - print("Not a git clone, can't perform version check.") - except Exception as e: - print("version check failed", e) - - -def run_extension_installer(extension_dir): - path_installer = os.path.join(extension_dir, "install.py") - if not os.path.isfile(path_installer): - return - - try: - env = os.environ.copy() - env['PYTHONPATH'] = f"{script_path}{os.pathsep}{env.get('PYTHONPATH', '')}" - - stdout = run(f'"{python}" "{path_installer}"', errdesc=f"Error running install.py for extension {extension_dir}", custom_env=env).strip() - if stdout: - print(stdout) - except Exception as e: - errors.report(str(e)) - - -def list_extensions(settings_file): - settings = {} - - try: - with open(settings_file, "r", encoding="utf8") as file: - settings = json.load(file) - except FileNotFoundError: - pass - except Exception: - errors.report(f'\nCould not load settings\nThe config file "{settings_file}" is likely corrupted\nIt has been moved to the "tmp/config.json"\nReverting config to default\n\n''', exc_info=True) - os.replace(settings_file, os.path.join(script_path, "tmp", "config.json")) - - disabled_extensions = set(settings.get('disabled_extensions', [])) - disable_all_extensions = settings.get('disable_all_extensions', 'none') - - if disable_all_extensions != 'none' or args.disable_extra_extensions or args.disable_all_extensions or not os.path.isdir(extensions_dir): - return [] - - return [x for x in os.listdir(extensions_dir) if x not in disabled_extensions] - - -def run_extensions_installers(settings_file): - if not os.path.isdir(extensions_dir): - return - - with startup_timer.subcategory("run extensions installers"): - for dirname_extension in list_extensions(settings_file): - logging.debug(f"Installing {dirname_extension}") - - path = os.path.join(extensions_dir, dirname_extension) - - if os.path.isdir(path): - run_extension_installer(path) - startup_timer.record(dirname_extension) - - -re_requirement = re.compile(r"\s*([-_a-zA-Z0-9]+)\s*(?:==\s*([-+_.a-zA-Z0-9]+))?\s*") - - -def requirements_met(requirements_file): - """ - Does a simple parse of a requirements.txt file to determine if all rerqirements in it - are already installed. Returns True if so, False if not installed or parsing fails. - """ - - import importlib.metadata - import packaging.version - - with open(requirements_file, "r", encoding="utf8") as file: - for line in file: - if line.strip() == "": - continue - - m = re.match(re_requirement, line) - if m is None: - return False - - package = m.group(1).strip() - version_required = (m.group(2) or "").strip() - - if version_required == "": - continue - - try: - version_installed = importlib.metadata.version(package) - except Exception: - return False - - if packaging.version.parse(version_required) != packaging.version.parse(version_installed): - return False - - return True - - -def prepare_environment(): - torch_index_url = os.environ.get('TORCH_INDEX_URL', "https://download.pytorch.org/whl/cu121") - torch_command = os.environ.get('TORCH_COMMAND', f"pip install torch==2.1.2 torchvision==0.16.2 --extra-index-url {torch_index_url}") - if args.use_ipex: - if platform.system() == "Windows": - # The "Nuullll/intel-extension-for-pytorch" wheels were built from IPEX source for Intel Arc GPU: https://github.com/intel/intel-extension-for-pytorch/tree/xpu-main - # This is NOT an Intel official release so please use it at your own risk!! - # See https://github.com/Nuullll/intel-extension-for-pytorch/releases/tag/v2.0.110%2Bxpu-master%2Bdll-bundle for details. - # - # Strengths (over official IPEX 2.0.110 windows release): - # - AOT build (for Arc GPU only) to eliminate JIT compilation overhead: https://github.com/intel/intel-extension-for-pytorch/issues/399 - # - Bundles minimal oneAPI 2023.2 dependencies into the python wheels, so users don't need to install oneAPI for the whole system. - # - Provides a compatible torchvision wheel: https://github.com/intel/intel-extension-for-pytorch/issues/465 - # Limitation: - # - Only works for python 3.10 - url_prefix = "https://github.com/Nuullll/intel-extension-for-pytorch/releases/download/v2.0.110%2Bxpu-master%2Bdll-bundle" - torch_command = os.environ.get('TORCH_COMMAND', f"pip install {url_prefix}/torch-2.0.0a0+gite9ebda2-cp310-cp310-win_amd64.whl {url_prefix}/torchvision-0.15.2a0+fa99a53-cp310-cp310-win_amd64.whl {url_prefix}/intel_extension_for_pytorch-2.0.110+gitc6ea20b-cp310-cp310-win_amd64.whl") - else: - # Using official IPEX release for linux since it's already an AOT build. - # However, users still have to install oneAPI toolkit and activate oneAPI environment manually. - # See https://intel.github.io/intel-extension-for-pytorch/index.html#installation for details. - torch_index_url = os.environ.get('TORCH_INDEX_URL', "https://pytorch-extension.intel.com/release-whl/stable/xpu/us/") - torch_command = os.environ.get('TORCH_COMMAND', f"pip install torch==2.0.0a0 intel-extension-for-pytorch==2.0.110+gitba7f6c1 --extra-index-url {torch_index_url}") - requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt") - requirements_file_for_npu = os.environ.get('REQS_FILE_FOR_NPU', "requirements_npu.txt") - - xformers_package = os.environ.get('XFORMERS_PACKAGE', 'xformers==0.0.23.post1') - clip_package = os.environ.get('CLIP_PACKAGE', "https://github.com/openai/CLIP/archive/d50d76daa670286dd6cacf3bcd80b5e4823fc8e1.zip") - openclip_package = os.environ.get('OPENCLIP_PACKAGE', "https://github.com/mlfoundations/open_clip/archive/bb6e834e9c70d9c27d0dc3ecedeebeaeb1ffad6b.zip") - - assets_repo = os.environ.get('ASSETS_REPO', "https://github.com/AUTOMATIC1111/stable-diffusion-webui-assets.git") - stable_diffusion_repo = os.environ.get('STABLE_DIFFUSION_REPO', "https://github.com/Stability-AI/stablediffusion.git") - stable_diffusion_xl_repo = os.environ.get('STABLE_DIFFUSION_XL_REPO', "https://github.com/Stability-AI/generative-models.git") - k_diffusion_repo = os.environ.get('K_DIFFUSION_REPO', 'https://github.com/crowsonkb/k-diffusion.git') - blip_repo = os.environ.get('BLIP_REPO', 'https://github.com/salesforce/BLIP.git') - - assets_commit_hash = os.environ.get('ASSETS_COMMIT_HASH', "6f7db241d2f8ba7457bac5ca9753331f0c266917") - stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "cf1d67a6fd5ea1aa600c4df58e5b47da45f6bdbf") - stable_diffusion_xl_commit_hash = os.environ.get('STABLE_DIFFUSION_XL_COMMIT_HASH', "45c443b316737a4ab6e40413d7794a7f5657c19f") - k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "ab527a9a6d347f364e3d185ba6d714e22d80cb3c") - blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9") - - try: - # the existence of this file is a signal to webui.sh/bat that webui needs to be restarted when it stops execution - os.remove(os.path.join(script_path, "tmp", "restart")) - os.environ.setdefault('SD_WEBUI_RESTARTING', '1') - except OSError: - pass - - if not args.skip_python_version_check: - check_python_version() - - startup_timer.record("checks") - - commit = commit_hash() - tag = git_tag() - startup_timer.record("git version info") - - print(f"Python {sys.version}") - print(f"Version: {tag}") - print(f"Commit hash: {commit}") - - if args.reinstall_torch or not is_installed("torch") or not is_installed("torchvision"): - run(f'"{python}" -m {torch_command}', "Installing torch and torchvision", "Couldn't install torch", live=True) - startup_timer.record("install torch") - - if args.use_ipex: - args.skip_torch_cuda_test = True - if not args.skip_torch_cuda_test and not check_run_python("import torch; assert torch.cuda.is_available()"): - raise RuntimeError( - 'Torch is not able to use GPU; ' - 'add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check' - ) - startup_timer.record("torch GPU test") - - if not is_installed("clip"): - run_pip(f"install {clip_package}", "clip") - startup_timer.record("install clip") - - if not is_installed("open_clip"): - run_pip(f"install {openclip_package}", "open_clip") - startup_timer.record("install open_clip") - - if (not is_installed("xformers") or args.reinstall_xformers) and args.xformers: - run_pip(f"install -U -I --no-deps {xformers_package}", "xformers") - startup_timer.record("install xformers") - - if not is_installed("ngrok") and args.ngrok: - run_pip("install ngrok", "ngrok") - startup_timer.record("install ngrok") - - os.makedirs(os.path.join(script_path, dir_repos), exist_ok=True) - - git_clone(assets_repo, repo_dir('stable-diffusion-webui-assets'), "assets", assets_commit_hash) - git_clone(stable_diffusion_repo, repo_dir('stable-diffusion-stability-ai'), "Stable Diffusion", stable_diffusion_commit_hash) - git_clone(stable_diffusion_xl_repo, repo_dir('generative-models'), "Stable Diffusion XL", stable_diffusion_xl_commit_hash) - git_clone(k_diffusion_repo, repo_dir('k-diffusion'), "K-diffusion", k_diffusion_commit_hash) - git_clone(blip_repo, repo_dir('BLIP'), "BLIP", blip_commit_hash) - - startup_timer.record("clone repositores") - - if not os.path.isfile(requirements_file): - requirements_file = os.path.join(script_path, requirements_file) - - if not requirements_met(requirements_file): - run_pip(f"install -r \"{requirements_file}\"", "requirements") - startup_timer.record("install requirements") - - if not os.path.isfile(requirements_file_for_npu): - requirements_file_for_npu = os.path.join(script_path, requirements_file_for_npu) - - if "torch_npu" in torch_command and not requirements_met(requirements_file_for_npu): - run_pip(f"install -r \"{requirements_file_for_npu}\"", "requirements_for_npu") - startup_timer.record("install requirements_for_npu") - - if not args.skip_install: - run_extensions_installers(settings_file=args.ui_settings_file) - - if args.update_check: - version_check(commit) - startup_timer.record("check version") - - if args.update_all_extensions: - git_pull_recursive(extensions_dir) - startup_timer.record("update extensions") - - if "--exit" in sys.argv: - print("Exiting because of --exit argument") - exit(0) - - -def configure_for_tests(): - if "--api" not in sys.argv: - sys.argv.append("--api") - if "--ckpt" not in sys.argv: - sys.argv.append("--ckpt") - sys.argv.append(os.path.join(script_path, "test/test_files/empty.pt")) - if "--skip-torch-cuda-test" not in sys.argv: - sys.argv.append("--skip-torch-cuda-test") - if "--disable-nan-check" not in sys.argv: - sys.argv.append("--disable-nan-check") - - os.environ['COMMANDLINE_ARGS'] = "" - - -def start(): - print(f"Launching {'API server' if '--nowebui' in sys.argv else 'Web UI'} with arguments: {shlex.join(sys.argv[1:])}") - import webui - if '--nowebui' in sys.argv: - webui.api_only() - else: - webui.webui() - - -def dump_sysinfo(): - from modules import sysinfo - import datetime - - text = sysinfo.get() - filename = f"sysinfo-{datetime.datetime.utcnow().strftime('%Y-%m-%d-%H-%M')}.json" - - with open(filename, "w", encoding="utf8") as file: - file.write(text) - - return filename +# this scripts installs necessary requirements and launches main program in webui.py +import logging +import re +import subprocess +import os +import shutil +import sys +import importlib.util +import importlib.metadata +import platform +import json +import shlex +from functools import lru_cache + +from modules import cmd_args, errors +from modules.paths_internal import script_path, extensions_dir +from modules.timer import startup_timer +from modules import logging_config + +args, _ = cmd_args.parser.parse_known_args() +logging_config.setup_logging(args.loglevel) + +python = sys.executable +git = os.environ.get('GIT', "git") +index_url = os.environ.get('INDEX_URL', "") +dir_repos = "repositories" + +# Whether to default to printing command output +default_command_live = (os.environ.get('WEBUI_LAUNCH_LIVE_OUTPUT') == "1") + +os.environ.setdefault('GRADIO_ANALYTICS_ENABLED', 'False') + + +def check_python_version(): + is_windows = platform.system() == "Windows" + major = sys.version_info.major + minor = sys.version_info.minor + micro = sys.version_info.micro + + if is_windows: + supported_minors = [10] + else: + supported_minors = [7, 8, 9, 10, 11] + + if not (major == 3 and minor in supported_minors): + import modules.errors + + modules.errors.print_error_explanation(f""" +INCOMPATIBLE PYTHON VERSION + +This program is tested with 3.10.6 Python, but you have {major}.{minor}.{micro}. +If you encounter an error with "RuntimeError: Couldn't install torch." message, +or any other error regarding unsuccessful package (library) installation, +please downgrade (or upgrade) to the latest version of 3.10 Python +and delete current Python and "venv" folder in WebUI's directory. + +You can download 3.10 Python from here: https://www.python.org/downloads/release/python-3106/ + +{"Alternatively, use a binary release of WebUI: https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases/tag/v1.0.0-pre" if is_windows else ""} + +Use --skip-python-version-check to suppress this warning. +""") + + +@lru_cache() +def commit_hash(): + try: + return subprocess.check_output([git, "-C", script_path, "rev-parse", "HEAD"], shell=False, encoding='utf8').strip() + except Exception: + return "" + + +@lru_cache() +def git_tag(): + try: + return subprocess.check_output([git, "-C", script_path, "describe", "--tags"], shell=False, encoding='utf8').strip() + except Exception: + try: + + changelog_md = os.path.join(script_path, "CHANGELOG.md") + with open(changelog_md, "r", encoding="utf-8") as file: + line = next((line.strip() for line in file if line.strip()), "") + line = line.replace("## ", "") + return line + except Exception: + return "" + + +def run(command, desc=None, errdesc=None, custom_env=None, live: bool = default_command_live) -> str: + if desc is not None: + print(desc) + + run_kwargs = { + "args": command, + "shell": True, + "env": os.environ if custom_env is None else custom_env, + "encoding": 'utf8', + "errors": 'ignore', + } + + if not live: + run_kwargs["stdout"] = run_kwargs["stderr"] = subprocess.PIPE + + result = subprocess.run(**run_kwargs) + + if result.returncode != 0: + error_bits = [ + f"{errdesc or 'Error running command'}.", + f"Command: {command}", + f"Error code: {result.returncode}", + ] + if result.stdout: + error_bits.append(f"stdout: {result.stdout}") + if result.stderr: + error_bits.append(f"stderr: {result.stderr}") + raise RuntimeError("\n".join(error_bits)) + + return (result.stdout or "") + + +def is_installed(package): + try: + dist = importlib.metadata.distribution(package) + except importlib.metadata.PackageNotFoundError: + try: + spec = importlib.util.find_spec(package) + except ModuleNotFoundError: + return False + + return spec is not None + + return dist is not None + + +def repo_dir(name): + return os.path.join(script_path, dir_repos, name) + + +def run_pip(command, desc=None, live=default_command_live): + if args.skip_install: + return + + index_url_line = f' --index-url {index_url}' if index_url != '' else '' + return run(f'"{python}" -m pip {command} --prefer-binary{index_url_line}', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}", live=live) + + +def check_run_python(code: str) -> bool: + result = subprocess.run([python, "-c", code], capture_output=True, shell=False) + return result.returncode == 0 + + +def git_fix_workspace(dir, name): + run(f'"{git}" -C "{dir}" fetch --refetch --no-auto-gc', f"Fetching all contents for {name}", f"Couldn't fetch {name}", live=True) + run(f'"{git}" -C "{dir}" gc --aggressive --prune=now', f"Pruning {name}", f"Couldn't prune {name}", live=True) + return + + +def run_git(dir, name, command, desc=None, errdesc=None, custom_env=None, live: bool = default_command_live, autofix=True): + try: + return run(f'"{git}" -C "{dir}" {command}', desc=desc, errdesc=errdesc, custom_env=custom_env, live=live) + except RuntimeError: + if not autofix: + raise + + print(f"{errdesc}, attempting autofix...") + git_fix_workspace(dir, name) + + return run(f'"{git}" -C "{dir}" {command}', desc=desc, errdesc=errdesc, custom_env=custom_env, live=live) + + +def git_clone(url, dir, name, commithash=None, retries=3): + # TODO clone into temporary dir and move if successful + + if os.path.exists(dir): + if commithash is None: + return + + current_hash = run_git(dir, name, 'rev-parse HEAD', None, f"Couldn't determine {name}'s hash: {commithash}", live=False).strip() + if current_hash == commithash: + return + + if run_git(dir, name, 'config --get remote.origin.url', None, f"Couldn't determine {name}'s origin URL", live=False).strip() != url: + run_git(dir, name, f'remote set-url origin "{url}"', None, f"Failed to set {name}'s origin URL", live=False) + + run_git(dir, name, 'fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}", autofix=False) + + run_git(dir, name, f'checkout {commithash}', f"Checking out commit for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}", live=True) + + return + + for attempt in range(retries): + try: + run(f'"{git}" clone --config core.filemode=false "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}", live=True) + break + except RuntimeError: + if attempt < retries - 1: + print(f"Retrying clone for {name} (attempt {attempt + 1}/{retries})...") + shutil.rmtree(dir, ignore_errors=True) + else: + shutil.rmtree(dir, ignore_errors=True) + raise + + if commithash is not None: + run(f'"{git}" -C "{dir}" checkout {commithash}', None, "Couldn't checkout {name}'s hash: {commithash}") + + +def git_pull_recursive(dir): + for subdir, _, _ in os.walk(dir): + if os.path.exists(os.path.join(subdir, '.git')): + try: + output = subprocess.check_output([git, '-C', subdir, 'pull', '--autostash']) + print(f"Pulled changes for repository in '{subdir}':\n{output.decode('utf-8').strip()}\n") + except subprocess.CalledProcessError as e: + print(f"Couldn't perform 'git pull' on repository in '{subdir}':\n{e.output.decode('utf-8').strip()}\n") + + +def version_check(commit): + try: + import requests + commits = requests.get('https://api.github.com/repos/AUTOMATIC1111/stable-diffusion-webui/branches/master').json() + if commit != "" and commits['commit']['sha'] != commit: + print("--------------------------------------------------------") + print("| You are not up to date with the most recent release. |") + print("| Consider running `git pull` to update. |") + print("--------------------------------------------------------") + elif commits['commit']['sha'] == commit: + print("You are up to date with the most recent release.") + else: + print("Not a git clone, can't perform version check.") + except Exception as e: + print("version check failed", e) + + +def run_extension_installer(extension_dir): + path_installer = os.path.join(extension_dir, "install.py") + if not os.path.isfile(path_installer): + return + + try: + env = os.environ.copy() + env['PYTHONPATH'] = f"{script_path}{os.pathsep}{env.get('PYTHONPATH', '')}" + + stdout = run(f'"{python}" "{path_installer}"', errdesc=f"Error running install.py for extension {extension_dir}", custom_env=env).strip() + if stdout: + print(stdout) + except Exception as e: + errors.report(str(e)) + + +def list_extensions(settings_file): + settings = {} + + try: + with open(settings_file, "r", encoding="utf8") as file: + settings = json.load(file) + except FileNotFoundError: + pass + except Exception: + errors.report(f'\nCould not load settings\nThe config file "{settings_file}" is likely corrupted\nIt has been moved to the "tmp/config.json"\nReverting config to default\n\n''', exc_info=True) + os.replace(settings_file, os.path.join(script_path, "tmp", "config.json")) + + disabled_extensions = set(settings.get('disabled_extensions', [])) + disable_all_extensions = settings.get('disable_all_extensions', 'none') + + if disable_all_extensions != 'none' or args.disable_extra_extensions or args.disable_all_extensions or not os.path.isdir(extensions_dir): + return [] + + return [x for x in os.listdir(extensions_dir) if x not in disabled_extensions] + + +def run_extensions_installers(settings_file): + if not os.path.isdir(extensions_dir): + return + + with startup_timer.subcategory("run extensions installers"): + for dirname_extension in list_extensions(settings_file): + logging.debug(f"Installing {dirname_extension}") + + path = os.path.join(extensions_dir, dirname_extension) + + if os.path.isdir(path): + run_extension_installer(path) + startup_timer.record(dirname_extension) + + +re_requirement = re.compile(r"\s*([-_a-zA-Z0-9]+)\s*(?:==\s*([-+_.a-zA-Z0-9]+))?\s*") + + +def requirements_met(requirements_file): + """ + Does a simple parse of a requirements.txt file to determine if all rerqirements in it + are already installed. Returns True if so, False if not installed or parsing fails. + """ + + import importlib.metadata + import packaging.version + + with open(requirements_file, "r", encoding="utf8") as file: + for line in file: + if line.strip() == "": + continue + + m = re.match(re_requirement, line) + if m is None: + return False + + package = m.group(1).strip() + version_required = (m.group(2) or "").strip() + + if version_required == "": + continue + + try: + version_installed = importlib.metadata.version(package) + except Exception: + return False + + if packaging.version.parse(version_required) != packaging.version.parse(version_installed): + return False + + return True + + +def prepare_environment(): + torch_index_url = os.environ.get('TORCH_INDEX_URL', "https://download.pytorch.org/whl/cu121") + torch_command = os.environ.get('TORCH_COMMAND', f"pip install torch==2.1.2 torchvision==0.16.2 --extra-index-url {torch_index_url}") + if args.use_ipex: + if platform.system() == "Windows": + # The "Nuullll/intel-extension-for-pytorch" wheels were built from IPEX source for Intel Arc GPU: https://github.com/intel/intel-extension-for-pytorch/tree/xpu-main + # This is NOT an Intel official release so please use it at your own risk!! + # See https://github.com/Nuullll/intel-extension-for-pytorch/releases/tag/v2.0.110%2Bxpu-master%2Bdll-bundle for details. + # + # Strengths (over official IPEX 2.0.110 windows release): + # - AOT build (for Arc GPU only) to eliminate JIT compilation overhead: https://github.com/intel/intel-extension-for-pytorch/issues/399 + # - Bundles minimal oneAPI 2023.2 dependencies into the python wheels, so users don't need to install oneAPI for the whole system. + # - Provides a compatible torchvision wheel: https://github.com/intel/intel-extension-for-pytorch/issues/465 + # Limitation: + # - Only works for python 3.10 + url_prefix = "https://github.com/Nuullll/intel-extension-for-pytorch/releases/download/v2.0.110%2Bxpu-master%2Bdll-bundle" + torch_command = os.environ.get('TORCH_COMMAND', f"pip install {url_prefix}/torch-2.0.0a0+gite9ebda2-cp310-cp310-win_amd64.whl {url_prefix}/torchvision-0.15.2a0+fa99a53-cp310-cp310-win_amd64.whl {url_prefix}/intel_extension_for_pytorch-2.0.110+gitc6ea20b-cp310-cp310-win_amd64.whl") + else: + # Using official IPEX release for linux since it's already an AOT build. + # However, users still have to install oneAPI toolkit and activate oneAPI environment manually. + # See https://intel.github.io/intel-extension-for-pytorch/index.html#installation for details. + torch_index_url = os.environ.get('TORCH_INDEX_URL', "https://pytorch-extension.intel.com/release-whl/stable/xpu/us/") + torch_command = os.environ.get('TORCH_COMMAND', f"pip install torch==2.0.0a0 intel-extension-for-pytorch==2.0.110+gitba7f6c1 --extra-index-url {torch_index_url}") + requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt") + requirements_file_for_npu = os.environ.get('REQS_FILE_FOR_NPU', "requirements_npu.txt") + + xformers_package = os.environ.get('XFORMERS_PACKAGE', 'xformers==0.0.23.post1') + clip_package = os.environ.get('CLIP_PACKAGE', "https://github.com/openai/CLIP/archive/d50d76daa670286dd6cacf3bcd80b5e4823fc8e1.zip") + openclip_package = os.environ.get('OPENCLIP_PACKAGE', "https://github.com/mlfoundations/open_clip/archive/bb6e834e9c70d9c27d0dc3ecedeebeaeb1ffad6b.zip") + + assets_repo = os.environ.get('ASSETS_REPO', "https://github.com/AUTOMATIC1111/stable-diffusion-webui-assets.git") + stable_diffusion_repo = os.environ.get('STABLE_DIFFUSION_REPO', "https://github.com/Stability-AI/stablediffusion.git") + stable_diffusion_xl_repo = os.environ.get('STABLE_DIFFUSION_XL_REPO', "https://github.com/Stability-AI/generative-models.git") + k_diffusion_repo = os.environ.get('K_DIFFUSION_REPO', 'https://github.com/crowsonkb/k-diffusion.git') + blip_repo = os.environ.get('BLIP_REPO', 'https://github.com/salesforce/BLIP.git') + + assets_commit_hash = os.environ.get('ASSETS_COMMIT_HASH', "6f7db241d2f8ba7457bac5ca9753331f0c266917") + stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "cf1d67a6fd5ea1aa600c4df58e5b47da45f6bdbf") + stable_diffusion_xl_commit_hash = os.environ.get('STABLE_DIFFUSION_XL_COMMIT_HASH', "45c443b316737a4ab6e40413d7794a7f5657c19f") + k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "ab527a9a6d347f364e3d185ba6d714e22d80cb3c") + blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9") + + try: + # the existence of this file is a signal to webui.sh/bat that webui needs to be restarted when it stops execution + os.remove(os.path.join(script_path, "tmp", "restart")) + os.environ.setdefault('SD_WEBUI_RESTARTING', '1') + except OSError: + pass + + if not args.skip_python_version_check: + check_python_version() + + startup_timer.record("checks") + + commit = commit_hash() + tag = git_tag() + startup_timer.record("git version info") + + print(f"Python {sys.version}") + print(f"Version: {tag}") + print(f"Commit hash: {commit}") + + if args.reinstall_torch or not is_installed("torch") or not is_installed("torchvision"): + run(f'"{python}" -m {torch_command}', "Installing torch and torchvision", "Couldn't install torch", live=True) + startup_timer.record("install torch") + + if args.use_ipex: + args.skip_torch_cuda_test = True + if not args.skip_torch_cuda_test and not check_run_python("import torch; assert torch.cuda.is_available()"): + raise RuntimeError( + 'Torch is not able to use GPU; ' + 'add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check' + ) + startup_timer.record("torch GPU test") + + if not is_installed("clip"): + run_pip(f"install {clip_package}", "clip") + startup_timer.record("install clip") + + if not is_installed("open_clip"): + run_pip(f"install {openclip_package}", "open_clip") + startup_timer.record("install open_clip") + + if (not is_installed("xformers") or args.reinstall_xformers) and args.xformers: + run_pip(f"install -U -I --no-deps {xformers_package}", "xformers") + startup_timer.record("install xformers") + + if not is_installed("ngrok") and args.ngrok: + run_pip("install ngrok", "ngrok") + startup_timer.record("install ngrok") + + os.makedirs(os.path.join(script_path, dir_repos), exist_ok=True) + + git_clone(assets_repo, repo_dir('stable-diffusion-webui-assets'), "assets", assets_commit_hash) + git_clone(stable_diffusion_repo, repo_dir('stable-diffusion-stability-ai'), "Stable Diffusion", stable_diffusion_commit_hash) + git_clone(stable_diffusion_xl_repo, repo_dir('generative-models'), "Stable Diffusion XL", stable_diffusion_xl_commit_hash) + git_clone(k_diffusion_repo, repo_dir('k-diffusion'), "K-diffusion", k_diffusion_commit_hash) + git_clone(blip_repo, repo_dir('BLIP'), "BLIP", blip_commit_hash) + + startup_timer.record("clone repositores") + + if not os.path.isfile(requirements_file): + requirements_file = os.path.join(script_path, requirements_file) + + if not requirements_met(requirements_file): + run_pip(f"install -r \"{requirements_file}\"", "requirements") + startup_timer.record("install requirements") + + if not os.path.isfile(requirements_file_for_npu): + requirements_file_for_npu = os.path.join(script_path, requirements_file_for_npu) + + if "torch_npu" in torch_command and not requirements_met(requirements_file_for_npu): + run_pip(f"install -r \"{requirements_file_for_npu}\"", "requirements_for_npu") + startup_timer.record("install requirements_for_npu") + + if not args.skip_install: + run_extensions_installers(settings_file=args.ui_settings_file) + + if args.update_check: + version_check(commit) + startup_timer.record("check version") + + if args.update_all_extensions: + git_pull_recursive(extensions_dir) + startup_timer.record("update extensions") + + if "--exit" in sys.argv: + print("Exiting because of --exit argument") + exit(0) + + +def configure_for_tests(): + if "--api" not in sys.argv: + sys.argv.append("--api") + if "--ckpt" not in sys.argv: + sys.argv.append("--ckpt") + sys.argv.append(os.path.join(script_path, "test/test_files/empty.pt")) + if "--skip-torch-cuda-test" not in sys.argv: + sys.argv.append("--skip-torch-cuda-test") + if "--disable-nan-check" not in sys.argv: + sys.argv.append("--disable-nan-check") + + os.environ['COMMANDLINE_ARGS'] = "" + + +def start(): + print(f"Launching {'API server' if '--nowebui' in sys.argv else 'Web UI'} with arguments: {shlex.join(sys.argv[1:])}") + import webui + if '--nowebui' in sys.argv: + webui.api_only() + else: + webui.webui() + + +def dump_sysinfo(): + from modules import sysinfo + import datetime + + text = sysinfo.get() + filename = f"sysinfo-{datetime.datetime.utcnow().strftime('%Y-%m-%d-%H-%M')}.json" + + with open(filename, "w", encoding="utf8") as file: + file.write(text) + + return filename