Merge pull request #3546 from vladmandic/dev

merge dev to master
This commit is contained in:
Vladimir Mandic
2024-11-01 12:17:09 -04:00
committed by GitHub
65 changed files with 622 additions and 336 deletions
+2
View File
@@ -112,6 +112,8 @@
"idbPut": "readonly",
"idbDel": "readonly",
"idbAdd": "readonly",
// changelog.js
"initChangelog": "readonly",
// notification.js
"sendNotification": "readonly"
},
+6
View File
@@ -44,6 +44,11 @@ tunableop_results*.csv
!webui.sh
!package.json
# pyinstaller
*.spec
build/
dist/
# dynamically generated
/repositories/ip-instruct/
@@ -69,3 +74,4 @@ tunableop_results*.csv
!/models/VAE-approx/model.pt
!/models/Reference
!/models/Reference/**/*
+38
View File
@@ -1,5 +1,43 @@
# Change Log for SD.Next
## Update for 2024-11-01
Smaller release just 3 days after the last one, but with some important fixes and improvements.
This release can be considered an LTS release before we kick off the next round of major updates.
- XYZ grid:
- optional per-image time benchmark info
- UI:
- add additional [hotkeys](https://github.com/vladmandic/automatic/wiki/Hotkeys)
- Docs:
- add built-in [changelog](https://github.com/vladmandic/automatic/blob/master/CHANGELOG.md) search
since changelog is the best up-to-date source of info
go to system -> changelog and search/highligh/navigate directly in UI!
- SD3: ControlNets:
- *InstantX Canny, Pose, Depth, Tile*
- *Alimama Inpainting, SoftEdge*
- *note*: that just like with FLUX.1 or any large model, ControlNet are also large and can push your system over the limit
e.g. SD3 controlnets vary from 1GB to over 4GB in size
- SD3: all-in-one safetensors
- *examples*: [large](https://civitai.com/models/882666/sd35-large-google-flan?modelVersionId=1003031), [medium](https://civitai.com/models/900327)
- *note*: enable *bnb* on-the-fly quantization for even bigger gains
- CLI:
- refactor command line params
run `webui.sh`/`webui.bat` with `--help` to see all options
- Other:
- Repo: move screenshots to GH pages
- Update requirements
- Fixes:
- detailer min/max size as fractions of image size
- ipadapter load on-demand
- ipadapter face use correct yolo model
- list diffusers remove duplicates
- fix legacy extensions access to shared objects
- fix diffusers load from folder
- fix lora enum logging on windows
- fix xyz grid with batch count
- move dowwloads of some auxillary models to hfcache instead of models folder
## Update for 2024-10-29
### Highlights for 2024-10-29
+1 -1
View File
@@ -24,5 +24,5 @@ abstract: >-
generation
keywords:
- stablediffusion diffusers sdnext
license: AGPL-3.0
license: Apache-2.0
date-released: 2022-12-24
+2 -4
View File
@@ -1,8 +1,6 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (c) 2023 AUTOMATIC1111
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -635,8 +633,8 @@ the "copyright" line and a pointer to where the full notice is found.
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
+24 -80
View File
@@ -50,12 +50,13 @@ All individual features are not listed here, instead check [ChangeLog](CHANGELOG
<br>
*Main interface using **StandardUI***:
![Screenshot-Dark](html/screenshot-text2image.jpg)
![screenshot-text2image](https://github.com/user-attachments/assets/87ac2813-65c2-45f4-80b8-67b26ccf5cd6)
*Main interface using **ModernUI***:
![Screenshot-Dark](html/screenshot-modernui-f1.jpg)
![Screenshot-Dark](html/screenshot-modernui.jpg)
![Screenshot-Dark](html/screenshot-modernui-sd3.jpg)
![screenshot-modernui-f1](https://github.com/user-attachments/assets/b509a280-8d3b-48b5-8525-363bad8c1ed2)
![screenshot-modernui](https://github.com/user-attachments/assets/fef33127-f733-4e78-b66e-17729539512f)
![screenshot-modernui-sd3](https://github.com/user-attachments/assets/1ed02ecc-23e4-4fda-8ae5-2d7393dc530c)
For screenshots and informations on other available themes, see [Themes Wiki](https://github.com/vladmandic/automatic/wiki/Themes)
@@ -63,12 +64,13 @@ For screenshots and informations on other available themes, see [Themes Wiki](ht
## Model support
Additional models will be added as they become available and there is public interest in them
Additional models will be added as they become available and there is public interest in them
See [models overview](https://github.com/vladmandic/automatic/wiki/Models) for details on each model, including their architecture, complexity and other info
- [RunwayML Stable Diffusion](https://github.com/Stability-AI/stablediffusion/) 1.x and 2.x *(all variants)*
- [StabilityAI Stable Diffusion XL](https://github.com/Stability-AI/generative-models)
- [StabilityAI Stable Diffusion 3 Medium](https://stability.ai/news/stable-diffusion-3-medium)
- [Stable Diffusion 3.5 Large](https://huggingface.co/stabilityai/stable-diffusion-3.5-large)
- [StabilityAI Stable Diffusion](https://stability.ai/news/stable-diffusion-3-medium)
- [Stable Diffusion 3.x](https://huggingface.co/stabilityai/stable-diffusion-3.5-large) 3.0 Medium, 3.5 Medium, 3.5 Large, 3.5 Large Turbo
- [StabilityAI Stable Video Diffusion](https://huggingface.co/stabilityai/stable-video-diffusion-img2vid) Base, XT 1.0, XT 1.1
- [StabilityAI Stable Cascade](https://github.com/Stability-AI/StableCascade) *Full* and *Lite*
- [Black Forest Labs FLUX.1](https://blackforestlabs.ai/announcing-black-forest-labs/) Dev, Schnell
@@ -136,13 +138,13 @@ Also supported are modifiers such as:
## Examples
*IP Adapters*:
![Screenshot-IPAdapter](html/screenshot-ipadapter.jpg)
![screenshot-ipadapter](https://github.com/user-attachments/assets/92830894-845c-49ec-92d9-18c8a577d04f)
*Color grading*:
![Screenshot-Color](html/screenshot-color.jpg)
![screenshot-control](https://github.com/user-attachments/assets/cdad2722-ae7c-4c9c-94d6-5ea35a4b1356)
*InstantID*:
![Screenshot-InstantID](html/screenshot-instantid.jpg)
![screenshot-instantid](https://github.com/user-attachments/assets/f38a5660-32b3-4235-9da1-c79eccf5372f)
> [!IMPORTANT]
> - Loading any model other than standard SD 1.x / SD 2.x requires use of backend **Diffusers**
@@ -173,92 +175,34 @@ Also supported are modifiers such as:
Once SD.Next is installed, simply run `webui.ps1` or `webui.bat` (*Windows*) or `webui.sh` (*Linux or MacOS*)
List of available parameters, run `webui --help` for the full & up-to-date list:
For list of available command line options, run `webui --help` for the full & up-to-date list
Server options:
--config CONFIG Use specific server configuration file, default: config.json
--ui-config UI_CONFIG Use specific UI configuration file, default: ui-config.json
--medvram Split model stages and keep only active part in VRAM, default: False
--lowvram Split model components and keep only active part in VRAM, default: False
--ckpt CKPT Path to model checkpoint to load immediately, default: None
--vae VAE Path to VAE checkpoint to load immediately, default: None
--data-dir DATA_DIR Base path where all user data is stored, default:
--models-dir MODELS_DIR Base path where all models are stored, default: models
--allow-code Allow custom script execution, default: False
--share Enable UI accessible through Gradio site, default: False
--insecure Enable extensions tab regardless of other options, default: False
--use-cpu USE_CPU [USE_CPU ...] Force use CPU for specified modules, default: []
--listen Launch web server using public IP address, default: False
--port PORT Launch web server with given server port, default: 7860
--freeze Disable editing settings
--auth AUTH Set access authentication like "user:pwd,user:pwd""
--auth-file AUTH_FILE Set access authentication using file, default: None
--autolaunch Open the UI URL in the system's default browser upon launch
--docs Mount API docs, default: False
--api-only Run in API only mode without starting UI
--api-log Enable logging of all API requests, default: False
--device-id DEVICE_ID Select the default CUDA device to use, default: None
--cors-origins CORS_ORIGINS Allowed CORS origins as comma-separated list, default: None
--cors-regex CORS_REGEX Allowed CORS origins as regular expression, default: None
--tls-keyfile TLS_KEYFILE Enable TLS and specify key file, default: None
--tls-certfile TLS_CERTFILE Enable TLS and specify cert file, default: None
--tls-selfsign Enable TLS with self-signed certificates, default: False
--server-name SERVER_NAME Sets hostname of server, default: None
--no-hashing Disable hashing of checkpoints, default: False
--no-metadata Disable reading of metadata from models, default: False
--disable-queue Disable queues, default: False
--subpath SUBPATH Customize the URL subpath for usage with reverse proxy
--backend {original,diffusers} force model pipeline type
--allowed-paths ALLOWED_PATHS [ALLOWED_PATHS ...] add additional paths to paths allowed for web access
Setup options:
--reset Reset main repository to latest version, default: False
--upgrade Upgrade main repository to latest version, default: False
--requirements Force re-check of requirements, default: False
--quick Bypass version checks, default: False
--use-directml Use DirectML if no compatible GPU is detected, default: False
--use-openvino Use Intel OpenVINO backend, default: False
--use-ipex Force use Intel OneAPI XPU backend, default: False
--use-cuda Force use nVidia CUDA backend, default: False
--use-rocm Force use AMD ROCm backend, default: False
--use-zluda Force use ZLUDA, AMD GPUs only, default: False
--use-xformers Force use xFormers cross-optimization, default: False
--skip-requirements Skips checking and installing requirements, default: False
--skip-extensions Skips running individual extension installers, default: False
--skip-git Skips running all GIT operations, default: False
--skip-torch Skips running Torch checks, default: False
--skip-all Skips running all checks, default: False
--skip-env Skips setting of env variables during startup, default: False
--experimental Allow unsupported versions of libraries, default: False
--reinstall Force reinstallation of all requirements, default: False
--test Run test only and exit
--version Print version information
--ignore Ignore any errors and attempt to continue
--safe Run in safe mode with no user extensions
--uv Use uv as installer, default: False
Logging options:
--log LOG Set log file, default: None
--debug Run installer with debug logging, default: False
--profile Run profiler, default: False
> [!TIP]
> All command line options can also be set via env variable
> For example `--debug` is same as `set SD_DEBUG=true`
## Notes
> [!TIP]
> If you don't want to use built-in `venv` support and prefer to run SD.Next in your own environment such as *Docker* container, *Conda* environment or any other virtual environment, you can skip `venv` create/activate and launch SD.Next directly using `python launch.py` (command line flags noted above still apply).
### Quantization
**SD.Next** comes with broad quantization support, including support for BitsAndBytes, Optimum.Quanto, TorchAO, NNCF and GGUF
See [Quantization Wiki](https://github.com/vladmandic/automatic/wiki/Quantization)
### Control
**SD.Next** comes with built-in control for all types of text2image, image2image, video2video and batch processing
*Control interface*:
![Screenshot-Control](html/screenshot-control.jpg)
![screenshot-control](https://github.com/user-attachments/assets/cdad2722-ae7c-4c9c-94d6-5ea35a4b1356)
*Control processors*:
![Screenshot-Process](html/screenshot-processors.jpg)
![screenshot-processors](https://github.com/user-attachments/assets/7bccb82b-366e-4bdb-ae57-cc53fac95d3c)
*Masking*:
![Screenshot-Mask](html/screenshot-mask.jpg)
![screenshot-mask](https://github.com/user-attachments/assets/4b057e65-64f0-44ea-93b4-c3b69bc55532)
### Extensions
+1 -1
View File
@@ -6,7 +6,7 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma
- async lowvram: <https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14855>
- fp8: <https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14031>
- ipadapter-negative: https://github.com/huggingface/diffusers/discussions/7167
- ipadapter-negative: <https://github.com/huggingface/diffusers/discussions/7167>
- include reference styles
### Missing
+6 -9
View File
@@ -128,7 +128,7 @@ def load_diffusers(name, network_on_disk, lora_scale=shared.opts.extra_networks_
def load_network(name, network_on_disk) -> network.Network:
if not shared.sd_loaded:
return
return None
t0 = time.time()
cached = lora_cache.get(name, None)
if debug:
@@ -533,18 +533,14 @@ def network_MultiheadAttention_load_state_dict(self, *args, **kwargs):
def list_available_networks():
t0 = time.time()
available_networks.clear()
available_network_aliases.clear()
forbidden_network_aliases.clear()
available_network_hash_lookup.clear()
forbidden_network_aliases.update({"none": 1, "Addams": 1})
directories = []
if os.path.exists(shared.cmd_opts.lora_dir):
directories.append(shared.cmd_opts.lora_dir)
else:
if not os.path.exists(shared.cmd_opts.lora_dir):
shared.log.warning(f'LoRA directory not found: path="{shared.cmd_opts.lora_dir}"')
if os.path.exists(shared.cmd_opts.lyco_dir) and shared.cmd_opts.lyco_dir != shared.cmd_opts.lora_dir:
directories.append(shared.cmd_opts.lyco_dir)
def add_network(filename):
if not os.path.isfile(filename):
@@ -565,11 +561,12 @@ def list_available_networks():
except OSError as e: # should catch FileNotFoundError and PermissionError etc.
shared.log.error(f'LoRA: filename="{filename}" {e}')
candidates = list(files_cache.list_files(*directories, ext_filter=[".pt", ".ckpt", ".safetensors"]))
candidates = list(files_cache.list_files(shared.cmd_opts.lora_dir, ext_filter=[".pt", ".ckpt", ".safetensors"]))
with concurrent.futures.ThreadPoolExecutor(max_workers=shared.max_workers) as executor:
for fn in candidates:
executor.submit(add_network, fn)
shared.log.info(f'Available LoRAs: items={len(available_networks)} folders={len(forbidden_network_aliases)}')
t1 = time.time()
shared.log.info(f'Available LoRAs: path="{shared.cmd_opts.lora_dir}" items={len(available_networks)} folders={len(forbidden_network_aliases)} time={t1 - t0:.2f}')
def infotext_pasted(infotext, params): # pylint: disable=W0613
Binary file not shown.

Before

Width:  |  Height:  |  Size: 438 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

+38 -33
View File
@@ -552,7 +552,7 @@ def install_rocm_zluda():
from modules import zluda_installer
zluda_installer.set_default_agent(device)
try:
if args.reinstall_zluda:
if args.reinstall:
zluda_installer.uninstall()
zluda_path = zluda_installer.get_path()
zluda_installer.install(zluda_path)
@@ -1234,39 +1234,44 @@ def check_timestamp():
def add_args(parser):
group = parser.add_argument_group('Setup options')
group.add_argument('--reset', default = os.environ.get("SD_RESET",False), action='store_true', help = "Reset main repository to latest version, default: %(default)s")
group.add_argument('--upgrade', '--update', default = os.environ.get("SD_UPGRADE",False), action='store_true', help = "Upgrade main repository to latest version, default: %(default)s")
group.add_argument('--requirements', default = os.environ.get("SD_REQUIREMENTS",False), action='store_true', help = "Force re-check of requirements, default: %(default)s")
group.add_argument('--quick', default = os.environ.get("SD_QUICK",False), action='store_true', help = "Bypass version checks, default: %(default)s")
group.add_argument('--use-directml', default = os.environ.get("SD_USEDIRECTML",False), action='store_true', help = "Use DirectML if no compatible GPU is detected, default: %(default)s")
group.add_argument("--use-openvino", default = os.environ.get("SD_USEOPENVINO",False), action='store_true', help="Use Intel OpenVINO backend, default: %(default)s")
group.add_argument("--use-ipex", default = os.environ.get("SD_USEIPEX",False), action='store_true', help="Force use Intel OneAPI XPU backend, default: %(default)s")
group.add_argument("--use-cuda", default = os.environ.get("SD_USECUDA",False), action='store_true', help="Force use nVidia CUDA backend, default: %(default)s")
group.add_argument("--use-rocm", default = os.environ.get("SD_USEROCM",False), action='store_true', help="Force use AMD ROCm backend, default: %(default)s")
group.add_argument('--use-zluda', default=os.environ.get("SD_USEZLUDA", False), action='store_true', help = "Force use ZLUDA, AMD GPUs only, default: %(default)s")
group.add_argument("--use-xformers", default = os.environ.get("SD_USEXFORMERS",False), action='store_true', help="Force use xFormers cross-optimization, default: %(default)s")
group.add_argument('--skip-requirements', default = os.environ.get("SD_SKIPREQUIREMENTS",False), action='store_true', help = "Skips checking and installing requirements, default: %(default)s")
group.add_argument('--skip-extensions', default = os.environ.get("SD_SKIPEXTENSION",False), action='store_true', help = "Skips running individual extension installers, default: %(default)s")
group.add_argument('--skip-git', default = os.environ.get("SD_SKIPGIT",False), action='store_true', help = "Skips running all GIT operations, default: %(default)s")
group.add_argument('--skip-torch', default = os.environ.get("SD_SKIPTORCH",False), action='store_true', help = "Skips running Torch checks, default: %(default)s")
group.add_argument('--skip-all', default = os.environ.get("SD_SKIPALL",False), action='store_true', help = "Skips running all checks, default: %(default)s")
group.add_argument('--skip-env', default = os.environ.get("SD_SKIPENV",False), action='store_true', help = "Skips setting of env variables during startup, default: %(default)s")
group.add_argument('--experimental', default = os.environ.get("SD_EXPERIMENTAL",False), action='store_true', help = "Allow unsupported versions of libraries, default: %(default)s")
group.add_argument('--reinstall', default = os.environ.get("SD_REINSTALL",False), action='store_true', help = "Force reinstallation of all requirements, default: %(default)s")
group.add_argument('--reinstall-zluda', default = os.environ.get("SD_REINSTALL_ZLUDA",False), action='store_true', help = "Force reinstallation of ZLUDA, default: %(default)s")
group.add_argument('--test', default = os.environ.get("SD_TEST",False), action='store_true', help = "Run test only and exit")
group.add_argument('--version', default = False, action='store_true', help = "Print version information")
group.add_argument('--ignore', default = os.environ.get("SD_IGNORE",False), action='store_true', help = "Ignore any errors and attempt to continue")
group.add_argument('--safe', default = os.environ.get("SD_SAFE",False), action='store_true', help = "Run in safe mode with no user extensions")
group.add_argument('--uv', default = os.environ.get("SD_UV",False), action='store_true', help = "Use uv instead of pip to install the packages")
group_setup = parser.add_argument_group('Setup')
group_setup.add_argument('--reset', default = os.environ.get("SD_RESET",False), action='store_true', help = "Reset main repository to latest version, default: %(default)s")
group_setup.add_argument('--upgrade', '--update', default = os.environ.get("SD_UPGRADE",False), action='store_true', help = "Upgrade main repository to latest version, default: %(default)s")
group_setup.add_argument('--requirements', default = os.environ.get("SD_REQUIREMENTS",False), action='store_true', help = "Force re-check of requirements, default: %(default)s")
group_setup.add_argument('--reinstall', default = os.environ.get("SD_REINSTALL",False), action='store_true', help = "Force reinstallation of all requirements, default: %(default)s")
group_setup.add_argument('--uv', default = os.environ.get("SD_UV",False), action='store_true', help = "Use uv instead of pip to install the packages")
group = parser.add_argument_group('Logging options')
group.add_argument("--log", type=str, default=os.environ.get("SD_LOG", None), help="Set log file, default: %(default)s")
group.add_argument('--debug', default = os.environ.get("SD_DEBUG",False), action='store_true', help = "Run installer with debug logging, default: %(default)s")
group.add_argument("--profile", default=os.environ.get("SD_PROFILE", False), action='store_true', help="Run profiler, default: %(default)s")
group.add_argument('--docs', default=os.environ.get("SD_DOCS", False), action='store_true', help = "Mount API docs, default: %(default)s")
group.add_argument("--api-log", default=os.environ.get("SD_APILOG", False), action='store_true', help="Enable logging of all API requests, default: %(default)s")
group_startup = parser.add_argument_group('Startup')
group_startup.add_argument('--quick', default = os.environ.get("SD_QUICK",False), action='store_true', help = "Bypass version checks, default: %(default)s")
group_startup.add_argument('--skip-requirements', default = os.environ.get("SD_SKIPREQUIREMENTS",False), action='store_true', help = "Skips checking and installing requirements, default: %(default)s")
group_startup.add_argument('--skip-extensions', default = os.environ.get("SD_SKIPEXTENSION",False), action='store_true', help = "Skips running individual extension installers, default: %(default)s")
group_startup.add_argument('--skip-git', default = os.environ.get("SD_SKIPGIT",False), action='store_true', help = "Skips running all GIT operations, default: %(default)s")
group_startup.add_argument('--skip-torch', default = os.environ.get("SD_SKIPTORCH",False), action='store_true', help = "Skips running Torch checks, default: %(default)s")
group_startup.add_argument('--skip-all', default = os.environ.get("SD_SKIPALL",False), action='store_true', help = "Skips running all checks, default: %(default)s")
group_startup.add_argument('--skip-env', default = os.environ.get("SD_SKIPENV",False), action='store_true', help = "Skips setting of env variables during startup, default: %(default)s")
group_compute = parser.add_argument_group('Compute Engine')
group_compute.add_argument('--use-directml', default = os.environ.get("SD_USEDIRECTML",False), action='store_true', help = "Use DirectML if no compatible GPU is detected, default: %(default)s")
group_compute.add_argument("--use-openvino", default = os.environ.get("SD_USEOPENVINO",False), action='store_true', help="Use Intel OpenVINO backend, default: %(default)s")
group_compute.add_argument("--use-ipex", default = os.environ.get("SD_USEIPEX",False), action='store_true', help="Force use Intel OneAPI XPU backend, default: %(default)s")
group_compute.add_argument("--use-cuda", default = os.environ.get("SD_USECUDA",False), action='store_true', help="Force use nVidia CUDA backend, default: %(default)s")
group_compute.add_argument("--use-rocm", default = os.environ.get("SD_USEROCM",False), action='store_true', help="Force use AMD ROCm backend, default: %(default)s")
group_compute.add_argument('--use-zluda', default=os.environ.get("SD_USEZLUDA", False), action='store_true', help = "Force use ZLUDA, AMD GPUs only, default: %(default)s")
group_compute.add_argument("--use-xformers", default = os.environ.get("SD_USEXFORMERS",False), action='store_true', help="Force use xFormers cross-optimization, default: %(default)s")
group_diag = parser.add_argument_group('Diagnostics')
group_diag.add_argument('--safe', default = os.environ.get("SD_SAFE",False), action='store_true', help = "Run in safe mode with no user extensions")
group_diag.add_argument('--experimental', default = os.environ.get("SD_EXPERIMENTAL",False), action='store_true', help = "Allow unsupported versions of libraries, default: %(default)s")
group_diag.add_argument('--test', default = os.environ.get("SD_TEST",False), action='store_true', help = "Run test only and exit")
group_diag.add_argument('--version', default = False, action='store_true', help = "Print version information")
group_diag.add_argument('--ignore', default = os.environ.get("SD_IGNORE",False), action='store_true', help = "Ignore any errors and attempt to continue")
group_log = parser.add_argument_group('Logging')
group_log.add_argument("--log", type=str, default=os.environ.get("SD_LOG", None), help="Set log file, default: %(default)s")
group_log.add_argument('--debug', default = os.environ.get("SD_DEBUG",False), action='store_true', help = "Run installer with debug logging, default: %(default)s")
group_log.add_argument("--profile", default=os.environ.get("SD_PROFILE", False), action='store_true', help="Run profiler, default: %(default)s")
group_log.add_argument('--docs', default=os.environ.get("SD_DOCS", False), action='store_true', help = "Mount API docs, default: %(default)s")
group_log.add_argument("--api-log", default=os.environ.get("SD_APILOG", False), action='store_true', help="Enable logging of all API requests, default: %(default)s")
def parse_args(parser):
+77
View File
@@ -0,0 +1,77 @@
let changelogElements = [];
const getAllChildren = (el) => {
const elements = [];
for (let i = 0; i < el.children.length; i++) {
elements.push(el.children[i]);
if (el.children[i].children.length) elements.push(...getAllChildren(el.children[i]));
}
return elements;
};
function getText(el) {
let text = '';
el.childNodes.forEach((node) => {
if (node.nodeType === Node.TEXT_NODE) text += node.nodeValue;
});
return text.trim();
}
let currentElement = -1;
function changelogNavigate(found) {
const result = gradioApp().getElementById('changelog_result');
result.innerHTML = '';
const text = document.createElement('p');
const onPrev = () => {
if (currentElement > 0) {
currentElement--;
found[currentElement].scrollIntoView();
text.innerHTML = ` &nbsp search item ${currentElement + 1} of ${found.length}`;
}
};
const onNext = () => {
if (currentElement < found.length - 1) {
currentElement++;
found[currentElement].scrollIntoView();
text.innerHTML = ` &nbsp search item ${currentElement + 1} of ${found.length}`;
}
};
const prev = document.createElement('p');
prev.innerHTML = ' ⇦ ';
prev.className = 'changelog_arrow';
prev.onclick = onPrev;
prev.title = 'Search previous';
result.appendChild(prev);
const next = document.createElement('p');
next.innerHTML = ' ⇨ ';
next.className = 'changelog_arrow';
next.title = 'Search next';
next.onclick = onNext;
result.appendChild(next);
text.innerHTML = ` &nbsp found ${found.length} items`;
result.appendChild(text);
}
async function initChangelog() {
const search = gradioApp().querySelector('#changelog_search > label> textarea');
const md = gradioApp().getElementById('changelog_markdown');
const searchChangelog = async (e) => {
if (changelogElements.length < 100) changelogElements = getAllChildren(md);
const found = [];
for (const el of changelogElements) {
if (search.value.length > 1 && getText(el).toLowerCase().includes(search.value.toLowerCase())) {
el.classList.add('changelog_highlight');
found.push(el);
} else {
el.classList.remove('changelog_highlight');
}
}
changelogNavigate(found);
};
search.addEventListener('keyup', searchChangelog);
}
+14 -10
View File
@@ -133,19 +133,23 @@ document.addEventListener('DOMContentLoaded', () => {
});
/**
* Add a ctrl+enter as a shortcut to start a generation
* Add a listener to the document for keydown events
*/
document.addEventListener('keydown', (e) => {
let handled = false;
if (e.key !== undefined) {
if ((e.key === 'Enter' && (e.metaKey || e.ctrlKey || e.altKey))) handled = true;
} else if (e.keyCode !== undefined) {
if ((e.keyCode === 13 && (e.metaKey || e.ctrlKey || e.altKey))) handled = true;
}
if (handled) {
const button = getUICurrentTabContent().querySelector('button[id$=_generate]');
if (button) button.click();
let elem;
if (e.key === 'Escape') elem = getUICurrentTabContent().querySelector('button[id$=_interrupt]');
if (e.key === 'Enter' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id$=_generate]');
if (e.key === 'Backspace' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id$=_reprocess]');
if (e.key === ' ' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id$=_extra_networks_btn]');
if (e.key === 's' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id^=save_]');
if (e.key === 'Insert' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id^=save_]');
if (e.key === 'Delete' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id^=delete_]');
// if (e.key === 'm' && e.ctrlKey) elem = gradioApp().getElementById('setting_sd_model_checkpoint');
if (elem) {
e.preventDefault();
log('hotkey', { key: e.key, meta: e.metaKey, ctrl: e.ctrlKey, alt: e.altKey }, elem?.id, elem.nodeName);
if (elem.nodeName === 'BUTTON') elem.click();
else elem.focus();
}
});
+7
View File
@@ -319,6 +319,13 @@ div:has(>#tab-gallery-folders) { flex-grow: 0 !important; background-color: var(
.gallery-sort { background: var(--input-background-fill) !important; margin: 0 !important; padding: 6px !important; }
.gallery-sort:hover { background: var(--button-primary-background-fill-hover) !important; }
/* changelog */
#changelog_markdown { max-height: 55vh; margin-top: 1em; }
#changelog_result { display: flex; margin-left: 1em; align-items: center; }
.changelog_arrow { font-size: 2em; padding: 0.1em; cursor: pointer; height: 1em; background-color: var(--button-secondary-background-fill); }
.changelog_arrow:hover { background-color: var(--button-primary-border-color-hover); }
.changelog_highlight { background-color: var(--color-warning); }
/* loader */
.splash { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 1000; display: block; text-align: center; }
.motd { margin-top: 2em; color: var(--body-text-color-subdued); font-family: monospace; font-variant: all-petite-caps; }
+1
View File
@@ -16,6 +16,7 @@ async function initStartup() {
initImageViewer();
initGallery();
initiGenerationParams();
initChangelog();
setupControlUI();
// reconnect server session
+2 -1
View File
@@ -164,7 +164,6 @@ def start_server(immediate=True, server=None):
module_spec = importlib.util.spec_from_file_location('webui', 'webui.py')
server = importlib.util.module_from_spec(module_spec)
installer.log.debug(f'Starting module: {server}')
get_custom_args()
module_spec.loader.exec_module(server)
uvicorn = None
if args.test:
@@ -209,6 +208,7 @@ def main():
installer.log.info('Skipping GIT operations')
installer.check_version()
installer.log.info(f'Platform: {installer.print_dict(installer.get_platform())}')
installer.log.info(f'Args: {sys.argv[1:]}')
if not args.skip_env:
installer.set_environment()
if args.uv:
@@ -246,6 +246,7 @@ def main():
installer.log.warning(f'See log file for more details: {installer.log_file}')
installer.extensions_preload(parser) # adds additional args from extensions
args = installer.parse_args(parser)
get_custom_args()
uv, instance = start_server(immediate=True, server=None)
while True:
+2 -3
View File
@@ -113,10 +113,9 @@ class APIProcess():
images = []
scores = []
with self.queue_lock:
yolo.load()
faces = yolo.predict(image)
faces = yolo.predict('face-yolo8n', image)
for face in faces:
images.append(encode_pil_to_base64(face.face))
images.append(encode_pil_to_base64(face.item))
scores.append(face.score)
shared.state.end(api=False)
return ResFace(images=images, scores=scores)
+125 -91
View File
@@ -2,104 +2,134 @@ import os
import argparse
from modules.paths import data_path
parser = argparse.ArgumentParser(description="SD.Next", conflict_handler='resolve', epilog='For other options see UI Settings page', prog='', add_help=True, formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=55, indent_increment=2, width=200))
parser._optionals = parser.add_argument_group('Other options') # pylint: disable=protected-access
group = parser.add_argument_group('Server options')
# main server args
group.add_argument("--config", type=str, default=os.environ.get("SD_CONFIG", os.path.join(data_path, 'config.json')), help="Use specific server configuration file, default: %(default)s")
group.add_argument("--ui-config", type=str, default=os.environ.get("SD_UICONFIG", os.path.join(data_path, 'ui-config.json')), help="Use specific UI configuration file, default: %(default)s")
group.add_argument("--medvram", default=os.environ.get("SD_MEDVRAM", False), action='store_true', help="Split model stages and keep only active part in VRAM, default: %(default)s")
group.add_argument("--lowvram", default=os.environ.get("SD_LOWVRAM", False), action='store_true', help="Split model components and keep only active part in VRAM, default: %(default)s")
group.add_argument("--ckpt", type=str, default=os.environ.get("SD_MODEL", None), help="Path to model checkpoint to load immediately, default: %(default)s")
group.add_argument('--vae', type=str, default=os.environ.get("SD_VAE", None), help='Path to VAE checkpoint to load immediately, default: %(default)s')
group.add_argument("--data-dir", type=str, default=os.environ.get("SD_DATADIR", ''), help="Base path where all user data is stored, default: %(default)s")
group.add_argument("--models-dir", type=str, default=os.environ.get("SD_MODELSDIR", 'models'), help="Base path where all models are stored, default: %(default)s",)
group.add_argument("--allow-code", default=os.environ.get("SD_ALLOWCODE", False), action='store_true', help="Allow custom script execution, default: %(default)s")
group.add_argument("--share", default=os.environ.get("SD_SHARE", False), action='store_true', help="Enable UI accessible through Gradio site, default: %(default)s")
group.add_argument("--insecure", default=os.environ.get("SD_INSECURE", False), action='store_true', help="Enable extensions tab regardless of other options, default: %(default)s")
group.add_argument("--use-cpu", nargs='+', default=[], type=str.lower, help="Force use CPU for specified modules, default: %(default)s")
group.add_argument("--listen", default=os.environ.get("SD_LISTEN", False), action='store_true', help="Launch web server using public IP address, default: %(default)s")
group.add_argument("--port", type=int, default=os.environ.get("SD_PORT", 7860), help="Launch web server with given server port, default: %(default)s")
group.add_argument("--freeze", default=os.environ.get("SD_FREEZE", False), action='store_true', help="Disable editing settings")
group.add_argument("--auth", type=str, default=os.environ.get("SD_AUTH", None), help='Set access authentication like "user:pwd,user:pwd""')
group.add_argument("--auth-file", type=str, default=os.environ.get("SD_AUTHFILE", None), help='Set access authentication using file, default: %(default)s')
group.add_argument("--autolaunch", default=os.environ.get("SD_AUTOLAUNCH", False), action='store_true', help="Open the UI URL in the system's default browser upon launch")
group.add_argument('--docs', default=os.environ.get("SD_DOCS", False), action='store_true', help = "Mount API docs, default: %(default)s")
group.add_argument('--api-only', default=os.environ.get("SD_APIONLY", False), action='store_true', help = "Run in API only mode without starting UI")
group.add_argument("--device-id", type=str, default=os.environ.get("SD_DEVICEID", None), help="Select the default CUDA device to use, default: %(default)s")
group.add_argument("--cors-origins", type=str, default=os.environ.get("SD_CORSORIGINS", None), help="Allowed CORS origins as comma-separated list, default: %(default)s")
group.add_argument("--cors-regex", type=str, default=os.environ.get("SD_CORSREGEX", None), help="Allowed CORS origins as regular expression, default: %(default)s")
group.add_argument("--tls-keyfile", type=str, default=os.environ.get("SD_TLSKEYFILE", None), help="Enable TLS and specify key file, default: %(default)s")
group.add_argument("--tls-certfile", type=str, default=os.environ.get("SD_TLSCERTFILE", None), help="Enable TLS and specify cert file, default: %(default)s")
group.add_argument("--tls-selfsign", action="store_true", default=os.environ.get("SD_TLSSELFSIGN", False), help="Enable TLS with self-signed certificates, default: %(default)s")
group.add_argument("--server-name", type=str, default=os.environ.get("SD_SERVERNAME", None), help="Sets hostname of server, default: %(default)s")
group.add_argument("--no-hashing", default=os.environ.get("SD_NOHASHING", False), action='store_true', help="Disable hashing of checkpoints, default: %(default)s")
group.add_argument("--no-metadata", default=os.environ.get("SD_NOMETADATA", False), action='store_true', help="Disable reading of metadata from models, default: %(default)s")
group.add_argument("--profile", default=os.environ.get("SD_PROFILE", False), action='store_true', help="Run profiler, default: %(default)s")
group.add_argument("--disable-queue", default=os.environ.get("SD_DISABLEQUEUE", False), action='store_true', help="Disable queues, default: %(default)s")
group.add_argument('--debug', default=os.environ.get("SD_DEBUG", False), action='store_true', help = "Run installer with debug logging, default: %(default)s")
group.add_argument('--use-directml', default=os.environ.get("SD_USEDIRECTML", False), action='store_true', help = "Use DirectML if no compatible GPU is detected, default: %(default)s")
group.add_argument('--use-zluda', default=os.environ.get("SD_USEZLUDA", False), action='store_true', help = "Force use ZLUDA, AMD GPUs only, default: %(default)s")
group.add_argument("--use-openvino", default=os.environ.get("SD_USEOPENVINO", False), action='store_true', help="Use Intel OpenVINO backend, default: %(default)s")
group.add_argument("--use-ipex", default=os.environ.get("SD_USEIPX", False), action='store_true', help="Force use Intel OneAPI XPU backend, default: %(default)s")
group.add_argument("--use-cuda", default=os.environ.get("SD_USECUDA", False), action='store_true', help="Force use nVidia CUDA backend, default: %(default)s")
group.add_argument("--use-rocm", default=os.environ.get("SD_USEROCM", False), action='store_true', help="Force use AMD ROCm backend, default: %(default)s")
group.add_argument('--subpath', type=str, default=os.environ.get("SD_SUBPATH", None), help='Customize the URL subpath for usage with reverse proxy')
group.add_argument('--backend', type=str, default=os.environ.get("SD_BACKEND", None), choices=['original', 'diffusers'], required=False, help='force model pipeline type')
group.add_argument('--theme', type=str, default=os.environ.get("SD_THEME", None), help='Override UI theme')
# removed args are added here as hidden in fixed format for compatbility reasons
group.add_argument("-f", action='store_true', help=argparse.SUPPRESS) # allows running as root; implemented outside of webui
group.add_argument("--ui-settings-file", type=str, help=argparse.SUPPRESS, default=os.path.join(data_path, 'config.json'))
group.add_argument("--ui-config-file", type=str, help=argparse.SUPPRESS, default=os.path.join(data_path, 'ui-config.json'))
group.add_argument("--hide-ui-dir-config", action='store_true', help=argparse.SUPPRESS, default=False)
group.add_argument("--theme", type=str, help=argparse.SUPPRESS, default=None)
group.add_argument("--disable-console-progressbars", action='store_true', help=argparse.SUPPRESS, default=True)
group.add_argument("--disable-safe-unpickle", action='store_true', help=argparse.SUPPRESS, default=True)
group.add_argument("--lowram", action='store_true', help=argparse.SUPPRESS)
group.add_argument("--disable-extension-access", default=False, action='store_true', help=argparse.SUPPRESS)
group.add_argument("--allowed-paths", nargs='+', default=[], type=str, required=False, help="add additional paths to paths allowed for web access")
group.add_argument("--api", help=argparse.SUPPRESS, default=True)
group.add_argument("--api-auth", type=str, help=argparse.SUPPRESS, default=None)
def main_args():
# main server args
group_config = parser.add_argument_group('Configuration')
group_config.add_argument('--backend', type=str, default=os.environ.get("SD_BACKEND", None), choices=['original', 'diffusers'], required=False, help='force model pipeline type')
group_config.add_argument("--config", type=str, default=os.environ.get("SD_CONFIG", os.path.join(data_path, 'config.json')), help="Use specific server configuration file, default: %(default)s")
group_config.add_argument("--ui-config", type=str, default=os.environ.get("SD_UICONFIG", os.path.join(data_path, 'ui-config.json')), help="Use specific UI configuration file, default: %(default)s")
group_config.add_argument("--medvram", default=os.environ.get("SD_MEDVRAM", False), action='store_true', help="Split model stages and keep only active part in VRAM, default: %(default)s")
group_config.add_argument("--lowvram", default=os.environ.get("SD_LOWVRAM", False), action='store_true', help="Split model components and keep only active part in VRAM, default: %(default)s")
group_config.add_argument("--freeze", default=os.environ.get("SD_FREEZE", False), action='store_true', help="Disable editing settings")
group_paths = parser.add_argument_group('Paths')
group_paths.add_argument("--ckpt", type=str, default=os.environ.get("SD_MODEL", None), help="Path to model checkpoint to load immediately, default: %(default)s")
group_paths.add_argument("--data-dir", type=str, default=os.environ.get("SD_DATADIR", ''), help="Base path where all user data is stored, default: %(default)s")
group_paths.add_argument("--models-dir", type=str, default=os.environ.get("SD_MODELSDIR", 'models'), help="Base path where all models are stored, default: %(default)s",)
group_diag = parser.add_argument_group('Diagnostics')
group_diag.add_argument("--no-hashing", default=os.environ.get("SD_NOHASHING", False), action='store_true', help="Disable hashing of checkpoints, default: %(default)s")
group_diag.add_argument("--no-metadata", default=os.environ.get("SD_NOMETADATA", False), action='store_true', help="Disable reading of metadata from models, default: %(default)s")
group_diag.add_argument("--profile", default=os.environ.get("SD_PROFILE", False), action='store_true', help="Run profiler, default: %(default)s")
group_diag.add_argument("--disable-queue", default=os.environ.get("SD_DISABLEQUEUE", False), action='store_true', help="Disable queues, default: %(default)s")
group_diag.add_argument('--debug', default=os.environ.get("SD_DEBUG", False), action='store_true', help = "Run installer with debug logging, default: %(default)s")
group_compute = parser.add_argument_group('Compute Engine')
group_compute.add_argument('--use-directml', default=os.environ.get("SD_USEDIRECTML", False), action='store_true', help = "Use DirectML if no compatible GPU is detected, default: %(default)s")
group_compute.add_argument('--use-zluda', default=os.environ.get("SD_USEZLUDA", False), action='store_true', help = "Force use ZLUDA, AMD GPUs only, default: %(default)s")
group_compute.add_argument("--use-openvino", default=os.environ.get("SD_USEOPENVINO", False), action='store_true', help="Use Intel OpenVINO backend, default: %(default)s")
group_compute.add_argument("--use-ipex", default=os.environ.get("SD_USEIPX", False), action='store_true', help="Force use Intel OneAPI XPU backend, default: %(default)s")
group_compute.add_argument("--use-cuda", default=os.environ.get("SD_USECUDA", False), action='store_true', help="Force use nVidia CUDA backend, default: %(default)s")
group_compute.add_argument("--use-rocm", default=os.environ.get("SD_USEROCM", False), action='store_true', help="Force use AMD ROCm backend, default: %(default)s")
group_diag.add_argument("--device-id", type=str, default=os.environ.get("SD_DEVICEID", None), help="Select the default CUDA device to use, default: %(default)s")
group_http = parser.add_argument_group('HTTP')
group_http.add_argument('--theme', type=str, default=os.environ.get("SD_THEME", None), help='Override UI theme')
group_http.add_argument("--server-name", type=str, default=os.environ.get("SD_SERVERNAME", None), help="Sets hostname of server, default: %(default)s")
group_http.add_argument("--tls-keyfile", type=str, default=os.environ.get("SD_TLSKEYFILE", None), help="Enable TLS and specify key file, default: %(default)s")
group_http.add_argument("--tls-certfile", type=str, default=os.environ.get("SD_TLSCERTFILE", None), help="Enable TLS and specify cert file, default: %(default)s")
group_http.add_argument("--tls-selfsign", action="store_true", default=os.environ.get("SD_TLSSELFSIGN", False), help="Enable TLS with self-signed certificates, default: %(default)s")
group_http.add_argument("--cors-origins", type=str, default=os.environ.get("SD_CORSORIGINS", None), help="Allowed CORS origins as comma-separated list, default: %(default)s")
group_http.add_argument("--cors-regex", type=str, default=os.environ.get("SD_CORSREGEX", None), help="Allowed CORS origins as regular expression, default: %(default)s")
group_http.add_argument('--subpath', type=str, default=os.environ.get("SD_SUBPATH", None), help='Customize the URL subpath for usage with reverse proxy')
group_http.add_argument("--autolaunch", default=os.environ.get("SD_AUTOLAUNCH", False), action='store_true', help="Open the UI URL in the system's default browser upon launch")
group_http.add_argument('--docs', default=os.environ.get("SD_DOCS", False), action='store_true', help = "Mount API docs, default: %(default)s")
group_http.add_argument("--auth", type=str, default=os.environ.get("SD_AUTH", None), help='Set access authentication like "user:pwd,user:pwd""')
group_http.add_argument("--auth-file", type=str, default=os.environ.get("SD_AUTHFILE", None), help='Set access authentication using file, default: %(default)s')
group_http.add_argument('--api-only', default=os.environ.get("SD_APIONLY", False), action='store_true', help = "Run in API only mode without starting UI")
group_http.add_argument("--allowed-paths", nargs='+', default=[], type=str, required=False, help="add additional paths to paths allowed for web access")
group_http.add_argument("--share", default=os.environ.get("SD_SHARE", False), action='store_true', help="Enable UI accessible through Gradio site, default: %(default)s")
group_http.add_argument("--insecure", default=os.environ.get("SD_INSECURE", False), action='store_true', help="Enable extensions tab regardless of other options, default: %(default)s")
group_http.add_argument("--listen", default=os.environ.get("SD_LISTEN", False), action='store_true', help="Launch web server using public IP address, default: %(default)s")
group_http.add_argument("--port", type=int, default=os.environ.get("SD_PORT", 7860), help="Launch web server with given server port, default: %(default)s")
def compatibility_args(opts, args):
def compatibility_args():
group_compat = parser.add_argument_group('Compatibility options')
# removed args are added here as hidden in fixed format for compatbility reasons
group_compat.add_argument("--allow-code", default=os.environ.get("SD_ALLOWCODE", False), action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--use-cpu", nargs='+', default=[], type=str.lower, help=argparse.SUPPRESS)
group_compat.add_argument("-f", action='store_true', help=argparse.SUPPRESS) # allows running as root; implemented outside of webui
group_compat.add_argument('--vae', type=str, default=os.environ.get("SD_VAE", None), help=argparse.SUPPRESS)
group_compat.add_argument("--ui-settings-file", type=str, help=argparse.SUPPRESS, default=os.path.join(data_path, 'config.json'))
group_compat.add_argument("--ui-config-file", type=str, help=argparse.SUPPRESS, default=os.path.join(data_path, 'ui-config.json'))
group_compat.add_argument("--hide-ui-dir-config", action='store_true', help=argparse.SUPPRESS, default=False)
group_compat.add_argument("--theme", type=str, help=argparse.SUPPRESS, default=None)
group_compat.add_argument("--disable-console-progressbars", action='store_true', help=argparse.SUPPRESS, default=True)
group_compat.add_argument("--disable-safe-unpickle", action='store_true', help=argparse.SUPPRESS, default=True)
group_compat.add_argument("--lowram", action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--disable-extension-access", default=False, action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--api", help=argparse.SUPPRESS, default=True)
group_compat.add_argument("--api-auth", type=str, help=argparse.SUPPRESS, default=None)
def settings_args(opts, args):
group_compat = parser.add_argument_group('Compatibility options')
# removed args are added here as hidden in fixed format for compatbility reasons
group_compat.add_argument("--allow-code", default=os.environ.get("SD_ALLOWCODE", False), action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--use-cpu", nargs='+', default=[], type=str.lower, help=argparse.SUPPRESS)
group_compat.add_argument("-f", action='store_true', help=argparse.SUPPRESS) # allows running as root; implemented outside of webui
group_compat.add_argument('--vae', type=str, default=os.environ.get("SD_VAE", None), help=argparse.SUPPRESS)
group_compat.add_argument("--ui-settings-file", type=str, help=argparse.SUPPRESS, default=os.path.join(data_path, 'config.json'))
group_compat.add_argument("--ui-config-file", type=str, help=argparse.SUPPRESS, default=os.path.join(data_path, 'ui-config.json'))
group_compat.add_argument("--hide-ui-dir-config", action='store_true', help=argparse.SUPPRESS, default=False)
group_compat.add_argument("--theme", type=str, help=argparse.SUPPRESS, default=None)
group_compat.add_argument("--disable-console-progressbars", action='store_true', help=argparse.SUPPRESS, default=True)
group_compat.add_argument("--disable-safe-unpickle", action='store_true', help=argparse.SUPPRESS, default=True)
group_compat.add_argument("--lowram", action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--disable-extension-access", default=False, action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--allowed-paths", nargs='+', default=[], type=str, required=False, help="add additional paths to paths allowed for web access")
group_compat.add_argument("--api", help=argparse.SUPPRESS, default=True)
group_compat.add_argument("--api-auth", type=str, help=argparse.SUPPRESS, default=None)
# removed args that have been moved to opts are added here as hidden with default values as defined in opts
group.add_argument("--ckpt-dir", type=str, help=argparse.SUPPRESS, default=opts.ckpt_dir)
group.add_argument("--vae-dir", type=str, help=argparse.SUPPRESS, default=opts.vae_dir)
group.add_argument("--embeddings-dir", type=str, help=argparse.SUPPRESS, default=opts.embeddings_dir)
group.add_argument("--embeddings-templates-dir", type=str, help=argparse.SUPPRESS, default=opts.embeddings_templates_dir)
group.add_argument("--hypernetwork-dir", type=str, help=argparse.SUPPRESS, default=opts.hypernetwork_dir)
group.add_argument("--codeformer-models-path", type=str, help=argparse.SUPPRESS, default=opts.codeformer_models_path)
group.add_argument("--gfpgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.gfpgan_models_path)
group.add_argument("--esrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.esrgan_models_path)
group.add_argument("--bsrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.bsrgan_models_path)
group.add_argument("--realesrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.realesrgan_models_path)
group.add_argument("--scunet-models-path", help=argparse.SUPPRESS, default=opts.scunet_models_path)
group.add_argument("--swinir-models-path", help=argparse.SUPPRESS, default=opts.swinir_models_path)
group.add_argument("--ldsr-models-path", help=argparse.SUPPRESS, default=opts.ldsr_models_path)
group.add_argument("--clip-models-path", type=str, help=argparse.SUPPRESS, default=opts.clip_models_path)
group.add_argument("--opt-channelslast", help=argparse.SUPPRESS, action='store_true', default=opts.opt_channelslast)
group.add_argument("--xformers", default=(opts.cross_attention_optimization == "xFormers"), action='store_true', help=argparse.SUPPRESS)
group.add_argument("--disable-nan-check", help=argparse.SUPPRESS, action='store_true', default=opts.disable_nan_check)
group.add_argument("--rollback-vae", help=argparse.SUPPRESS, default=opts.rollback_vae)
group.add_argument("--no-half", help=argparse.SUPPRESS, action='store_true', default=opts.no_half)
group.add_argument("--no-half-vae", help=argparse.SUPPRESS, action='store_true', default=opts.no_half_vae)
group.add_argument("--precision", help=argparse.SUPPRESS, default=opts.precision)
group.add_argument("--sub-quad-q-chunk-size", help=argparse.SUPPRESS, default=opts.sub_quad_q_chunk_size)
group.add_argument("--sub-quad-kv-chunk-size", help=argparse.SUPPRESS, default=opts.sub_quad_kv_chunk_size)
group.add_argument("--sub-quad-chunk-threshold", help=argparse.SUPPRESS, default=opts.sub_quad_chunk_threshold)
group.add_argument("--lora-dir", help=argparse.SUPPRESS, default=opts.lora_dir)
group.add_argument("--lyco-dir", help=argparse.SUPPRESS, default=opts.lyco_dir)
group.add_argument("--embeddings-dir", help=argparse.SUPPRESS, default=opts.embeddings_dir)
group.add_argument("--hypernetwork-dir", help=argparse.SUPPRESS, default=opts.hypernetwork_dir)
group.add_argument("--lyco-patch-lora", help=argparse.SUPPRESS, action='store_true', default=False)
group.add_argument("--lyco-debug", help=argparse.SUPPRESS, action='store_true', default=False)
group.add_argument("--enable-console-prompts", help=argparse.SUPPRESS, action='store_true', default=False)
group.add_argument("--safe", help=argparse.SUPPRESS, action='store_true', default=False)
group.add_argument("--use-xformers", help=argparse.SUPPRESS, action='store_true', default=False)
group_compat.add_argument("--ckpt-dir", type=str, help=argparse.SUPPRESS, default=opts.ckpt_dir)
group_compat.add_argument("--vae-dir", type=str, help=argparse.SUPPRESS, default=opts.vae_dir)
group_compat.add_argument("--embeddings-dir", type=str, help=argparse.SUPPRESS, default=opts.embeddings_dir)
group_compat.add_argument("--embeddings-templates-dir", type=str, help=argparse.SUPPRESS, default=opts.embeddings_templates_dir)
group_compat.add_argument("--hypernetwork-dir", type=str, help=argparse.SUPPRESS, default=opts.hypernetwork_dir)
group_compat.add_argument("--codeformer-models-path", type=str, help=argparse.SUPPRESS, default=opts.codeformer_models_path)
group_compat.add_argument("--gfpgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.gfpgan_models_path)
group_compat.add_argument("--esrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.esrgan_models_path)
group_compat.add_argument("--bsrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.bsrgan_models_path)
group_compat.add_argument("--realesrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.realesrgan_models_path)
group_compat.add_argument("--scunet-models-path", help=argparse.SUPPRESS, default=opts.scunet_models_path)
group_compat.add_argument("--swinir-models-path", help=argparse.SUPPRESS, default=opts.swinir_models_path)
group_compat.add_argument("--ldsr-models-path", help=argparse.SUPPRESS, default=opts.ldsr_models_path)
group_compat.add_argument("--clip-models-path", type=str, help=argparse.SUPPRESS, default=opts.clip_models_path)
group_compat.add_argument("--opt-channelslast", help=argparse.SUPPRESS, action='store_true', default=opts.opt_channelslast)
group_compat.add_argument("--xformers", default=(opts.cross_attention_optimization == "xFormers"), action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--disable-nan-check", help=argparse.SUPPRESS, action='store_true', default=opts.disable_nan_check)
group_compat.add_argument("--rollback-vae", help=argparse.SUPPRESS, default=opts.rollback_vae)
group_compat.add_argument("--no-half", help=argparse.SUPPRESS, action='store_true', default=opts.no_half)
group_compat.add_argument("--no-half-vae", help=argparse.SUPPRESS, action='store_true', default=opts.no_half_vae)
group_compat.add_argument("--precision", help=argparse.SUPPRESS, default=opts.precision)
group_compat.add_argument("--sub-quad-q-chunk-size", help=argparse.SUPPRESS, default=opts.sub_quad_q_chunk_size)
group_compat.add_argument("--sub-quad-kv-chunk-size", help=argparse.SUPPRESS, default=opts.sub_quad_kv_chunk_size)
group_compat.add_argument("--sub-quad-chunk-threshold", help=argparse.SUPPRESS, default=opts.sub_quad_chunk_threshold)
group_compat.add_argument("--lora-dir", help=argparse.SUPPRESS, default=opts.lora_dir)
group_compat.add_argument("--lyco-dir", help=argparse.SUPPRESS, default=opts.lyco_dir)
group_compat.add_argument("--embeddings-dir", help=argparse.SUPPRESS, default=opts.embeddings_dir)
group_compat.add_argument("--hypernetwork-dir", help=argparse.SUPPRESS, default=opts.hypernetwork_dir)
group_compat.add_argument("--lyco-patch-lora", help=argparse.SUPPRESS, action='store_true', default=False)
group_compat.add_argument("--lyco-debug", help=argparse.SUPPRESS, action='store_true', default=False)
group_compat.add_argument("--enable-console-prompts", help=argparse.SUPPRESS, action='store_true', default=False)
group_compat.add_argument("--safe", help=argparse.SUPPRESS, action='store_true', default=False)
group_compat.add_argument("--use-xformers", help=argparse.SUPPRESS, action='store_true', default=False)
# removed opts are added here with fixed values for compatibility reasons
opts.use_old_emphasis_implementation = False
@@ -126,3 +156,7 @@ def compatibility_args(opts, args):
args = parser.parse_args()
return args
main_args()
compatibility_args()
+2 -2
View File
@@ -564,8 +564,8 @@ def control_run(state: str = '',
return [], '', '', 'Reference mode without image'
elif unit_type == 'controlnet' and has_models:
if input_type == 0: # Control only
if shared.sd_model_type == 'f1' and 'control_image' not in p.task_args:
p.task_args['control_image'] = p.init_images # flux controlnet mandates this
if shared.sd_model_type in ['f1', 'sd3'] and 'control_image' not in p.task_args:
p.task_args['control_image'] = p.init_images # some controlnets mandate this
p.task_args['strength'] = p.denoising_strength
elif input_type == 1: # Init image same as control
p.task_args['control_image'] = p.init_images # switch image and control_image
+34 -4
View File
@@ -1,7 +1,7 @@
import os
import time
from typing import Union
from diffusers import StableDiffusionPipeline, StableDiffusionXLPipeline, FluxPipeline, ControlNetModel
from diffusers import StableDiffusionPipeline, StableDiffusionXLPipeline, FluxPipeline, StableDiffusion3Pipeline, ControlNetModel
from modules.control.units import detect
from modules.shared import log, opts, listdir
from modules import errors, sd_models, devices, model_quant
@@ -50,7 +50,6 @@ predefined_sdxl = {
'Depth Zoe XL': 'diffusers/controlnet-zoe-depth-sdxl-1.0',
'Depth Mid XL': 'diffusers/controlnet-depth-sdxl-1.0-mid',
'OpenPose XL': 'thibaud/controlnet-openpose-sdxl-1.0/bin',
# 'OpenPose XL': 'thibaud/controlnet-openpose-sdxl-1.0/OpenPoseXL2.safetensors',
'Xinsir Union XL': 'xinsir/controlnet-union-sdxl-1.0',
'Xinsir OpenPose XL': 'xinsir/controlnet-openpose-sdxl-1.0',
'Xinsir Canny XL': 'xinsir/controlnet-canny-sdxl-1.0',
@@ -79,11 +78,20 @@ predefined_f1 = {
"XLabs-AI Depth": 'XLabs-AI/flux-controlnet-depth-diffusers',
"XLabs-AI HED": 'XLabs-AI/flux-controlnet-hed-diffusers'
}
predefined_sd3 = {
"InstantX Canny": 'InstantX/SD3-Controlnet-Canny',
"InstantX Pose": 'InstantX/SD3-Controlnet-Pose',
"InstantX Depth": 'InstantX/SD3-Controlnet-Depth',
"InstantX Tile": 'InstantX/SD3-Controlnet-Tile',
"Alimama Inpainting": 'alimama-creative/SD3-Controlnet-Inpainting',
"Alimama SoftEdge": 'alimama-creative/SD3-Controlnet-Softedge',
}
models = {}
all_models = {}
all_models.update(predefined_sd15)
all_models.update(predefined_sdxl)
all_models.update(predefined_f1)
all_models.update(predefined_sd3)
cache_dir = 'models/control/controlnet'
@@ -118,9 +126,11 @@ def list_models(refresh=False):
models = ['None'] + list(predefined_sd15) + sorted(find_models())
elif modules.shared.sd_model_type == 'f1':
models = ['None'] + list(predefined_f1) + sorted(find_models())
elif modules.shared.sd_model_type == 'sd3':
models = ['None'] + list(predefined_sd3) + sorted(find_models())
else:
log.warning(f'Control {what} model list failed: unknown model type')
models = ['None'] + sorted(predefined_sd15) + sorted(predefined_sdxl) + sorted(find_models())
models = ['None'] + sorted(predefined_sd15) + sorted(predefined_sdxl) + sorted(predefined_f1) + sorted(predefined_sd3) + sorted(find_models())
debug(f'Control list {what}: path={cache_dir} models={models}')
return models
@@ -151,6 +161,8 @@ class ControlNet():
from diffusers import ControlNetModel as model_class # pylint: disable=reimported # sdxl shares same model class
elif modules.shared.sd_model_type == 'f1':
from diffusers import FluxControlNetModel as model_class
elif modules.shared.sd_model_type == 'sd3':
from diffusers import SD3ControlNetModel as model_class
else:
log.error(f'Control {what}: type={modules.shared.sd_model_type} unsupported model')
return None
@@ -247,7 +259,11 @@ class ControlNet():
class ControlNetPipeline():
def __init__(self, controlnet: Union[ControlNetModel, list[ControlNetModel]], pipeline: Union[StableDiffusionXLPipeline, StableDiffusionPipeline, FluxPipeline], dtype = None):
def __init__(self,
controlnet: Union[ControlNetModel, list[ControlNetModel]],
pipeline: Union[StableDiffusionXLPipeline, StableDiffusionPipeline, FluxPipeline, StableDiffusion3Pipeline],
dtype = None,
):
t0 = time.time()
self.orig_pipeline = pipeline
self.pipeline = None
@@ -293,6 +309,20 @@ class ControlNetPipeline():
scheduler=pipeline.scheduler,
controlnet=controlnet, # can be a list
)
elif detect.is_sd3(pipeline):
from diffusers import StableDiffusion3ControlNetPipeline
self.pipeline = StableDiffusion3ControlNetPipeline(
vae=pipeline.vae,
text_encoder=pipeline.text_encoder,
text_encoder_2=pipeline.text_encoder_2,
text_encoder_3=pipeline.text_encoder_3,
tokenizer=pipeline.tokenizer,
tokenizer_2=pipeline.tokenizer_2,
tokenizer_3=pipeline.tokenizer_3,
transformer=pipeline.transformer,
scheduler=pipeline.scheduler,
controlnet=controlnet, # can be a list
)
else:
log.error(f'Control {what} pipeline: class={pipeline.__class__.__name__} unsupported model type')
return
+9 -2
View File
@@ -20,5 +20,12 @@ def is_f1(model):
if model is None:
return False
if hasattr(model, '__name__'):
return model.__name__ == p.FluxPipeline.__name__
return isinstance(model, p.FluxPipeline)
return model.__name__ == p.FluxPipeline.__name__ or model.__name__ == p.FluxImg2ImgPipeline.__name__ or model.__name__ == p.FluxInpaintPipeline.__name__
return isinstance(model, p.FluxPipeline) or isinstance(model, p.FluxImg2ImgPipeline) or isinstance(model, p.FluxInpaintPipeline)
def is_sd3(model):
if model is None:
return False
if hasattr(model, '__name__'):
return model.__name__ == p.StableDiffusion3Pipeline.__name__ or model.__name__ == p.StableDiffusion3Img2ImgPipeline.__name__ or model.__name__ == p.StableDiffusion3InpaintPipeline.__name__
return isinstance(model, p.StableDiffusion3Pipeline) or isinstance(model, p.StableDiffusion3Img2ImgPipeline) or isinstance(model, p.StableDiffusion3InpaintPipeline)
+1 -1
View File
@@ -79,7 +79,7 @@ def face_id(
ip_ckpt = FACEID_MODELS[model]
folder, filename = os.path.split(ip_ckpt)
basename, _ext = os.path.splitext(filename)
model_path = hf.hf_hub_download(repo_id=folder, filename=filename, cache_dir=shared.opts.diffusers_dir)
model_path = hf.hf_hub_download(repo_id=folder, filename=filename, cache_dir=shared.opts.hfcache_dir)
if model_path is None:
shared.log.error(f'FaceID download failed: model={model} file="{ip_ckpt}"')
return None
+1 -1
View File
@@ -32,7 +32,7 @@ def get_app(mp_name):
repo_id='vladmandic/insightface-faceanalysis',
filename=f'{mp_name}.zip',
local_dir_use_symlinks=False,
cache_dir=opts.diffusers_dir,
cache_dir=opts.hfcache_dir,
local_dir=local_dir
)
if not os.path.exists(extract_dir):
+1 -1
View File
@@ -189,7 +189,7 @@ def create_override_settings_dict(text_pairs):
def connect_paste(button, local_paste_fields, input_comp, override_settings_component, tabname):
def paste_func(prompt):
if prompt is None or len(prompt.strip()) == 0 and not shared.cmd_opts.hide_ui_dir_config:
if prompt is None or len(prompt.strip()) == 0:
filename = os.path.join(data_path, "params.txt")
if os.path.exists(filename):
with open(filename, "r", encoding="utf8") as file:
+9 -1
View File
@@ -10,7 +10,7 @@ import threading
import numpy as np
import piexif
import piexif.helper
from PIL import Image, PngImagePlugin, ExifTags
from PIL import Image, PngImagePlugin, ExifTags, ImageDraw
from modules import sd_samplers, shared, script_callbacks, errors, paths
from modules.images_grid import image_grid, get_grid_size, split_grid, combine_grid, check_grid_size, get_font, draw_grid_annotations, draw_prompt_matrix, GridAnnotation, Grid # pylint: disable=unused-import
from modules.images_resize import resize_image # pylint: disable=unused-import
@@ -361,6 +361,14 @@ def flatten(img, bgcolor):
return img.convert('RGB')
def draw_overlay(im, text):
d = ImageDraw.Draw(im)
fontsize = (im.width + im.height) // 50
font = get_font(fontsize)
d.text((fontsize//2, fontsize//2), text, font=font, fill=shared.opts.font_color)
return im
def set_watermark(image, watermark):
if shared.opts.image_watermark_position != 'none': # visible watermark
wm_image = None
+9 -9
View File
@@ -113,7 +113,7 @@ def get_font(fontsize):
return ImageFont.truetype("javascript/notosans-nerdfont-regular.ttf", fontsize)
def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0, title=None):
def draw_grid_annotations(im, width, height, x_texts, y_texts, margin=0, title=None):
def wrap(drawing, text, font, line_length):
lines = ['']
for word in text.split():
@@ -140,15 +140,15 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0, tit
line_spacing = fontsize // 2
font = get_font(fontsize)
color_inactive = (127, 127, 127)
pad_left = 0 if sum([sum([len(line.text) for line in lines]) for lines in ver_texts]) == 0 else width * 3 // 4
cols = len(hor_texts)
rows = len(ver_texts)
pad_left = 0 if sum([sum([len(line.text) for line in lines]) for lines in y_texts]) == 0 else width * 3 // 4
cols = len(x_texts)
rows = len(y_texts)
# assert cols == len(hor_texts), f'bad number of horizontal texts: {len(hor_texts)}; must be {cols}'
# assert rows == len(hor_texts), f'bad number of vertical texts: {len(ver_texts)}; must be {rows}'
calc_img = Image.new("RGB", (1, 1), shared.opts.grid_background)
calc_d = ImageDraw.Draw(calc_img)
title_texts = [title] if title else [[GridAnnotation()]]
for texts, allowed_width in zip(hor_texts + ver_texts + title_texts, [width] * len(hor_texts) + [pad_left] * len(ver_texts) + [(width+margin)*cols]):
for texts, allowed_width in zip(x_texts + y_texts + title_texts, [width] * len(x_texts) + [pad_left] * len(y_texts) + [(width+margin)*cols]):
items = [] + texts
texts.clear()
for line in items:
@@ -158,8 +158,8 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0, tit
bbox = calc_d.multiline_textbbox((0, 0), line.text, font=font)
line.size = (bbox[2] - bbox[0], bbox[3] - bbox[1])
line.allowed_width = allowed_width
hor_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing for lines in hor_texts]
ver_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing * len(lines) for lines in ver_texts]
hor_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing for lines in x_texts]
ver_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing * len(lines) for lines in y_texts]
pad_top = 0 if sum(hor_text_heights) == 0 else max(hor_text_heights) + line_spacing * 2
title_pad = 0
if title:
@@ -178,11 +178,11 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0, tit
for col in range(cols):
x = pad_left + (width + margin) * col + width / 2
y = (pad_top / 2 - hor_text_heights[col] / 2) + title_pad
draw_texts(d, x, y, hor_texts[col], font, fontsize)
draw_texts(d, x, y, x_texts[col], font, fontsize)
for row in range(rows):
x = pad_left / 2
y = (pad_top + (height + margin) * row + height / 2 - ver_text_heights[row] / 2) + title_pad
draw_texts(d, x, y, ver_texts[row], font, fontsize)
draw_texts(d, x, y, y_texts[row], font, fontsize)
return result
+5 -5
View File
@@ -36,6 +36,7 @@ ADAPTERS_SDXL = {
'Ostris Composition ViT-H SDXL': { 'name': 'ip_plus_composition_sdxl.safetensors', 'repo': 'ostris/ip-composition-adapter', 'subfolder': '' },
}
ADAPTERS = { **ADAPTERS_SD15, **ADAPTERS_SDXL }
ADAPTERS_ALL = { **ADAPTERS_SD15, **ADAPTERS_SDXL }
def get_adapters():
@@ -101,13 +102,12 @@ def crop_images(images, crops):
try:
for i in range(len(images)):
if crops[i]:
from shared import yolo # pylint: disable=no-name-in-module
yolo.load()
from modules.shared import yolo # pylint: disable=no-name-in-module
cropped = []
for image in images[i]:
faces = yolo.predict(image)
faces = yolo.predict('face-yolo8n', image)
if len(faces) > 0:
cropped.append(faces[0].face)
cropped.append(faces[0].item)
if len(cropped) == len(images[i]):
images[i] = cropped
else:
@@ -135,7 +135,7 @@ def apply(pipe, p: processing.StableDiffusionProcessing, adapter_names=[], adapt
if hasattr(p, 'ip_adapter_names'):
if isinstance(p.ip_adapter_names, str):
p.ip_adapter_names = [p.ip_adapter_names]
adapters = [ADAPTERS.get(adapter_name, None) for adapter_name in p.ip_adapter_names if adapter_name is not None and adapter_name.lower() != 'none']
adapters = [ADAPTERS_ALL.get(adapter_name, None) for adapter_name in p.ip_adapter_names if adapter_name is not None and adapter_name.lower() != 'none']
adapter_names = p.ip_adapter_names
else:
if isinstance(adapter_names, str):
+7 -3
View File
@@ -7,10 +7,10 @@ bnb = None
quanto = None
def create_bnb_config(kwargs):
def create_bnb_config(kwargs = None):
from modules import shared, devices
if len(shared.opts.bnb_quantization) > 0:
if 'Model' in shared.opts.bnb_quantization and 'transformer' not in kwargs:
if 'Model' in shared.opts.bnb_quantization and 'transformer' not in (kwargs or {}):
load_bnb()
bnb_config = diffusers.BitsAndBytesConfig(
load_in_8bit=shared.opts.bnb_quantization_type in ['fp8'],
@@ -19,8 +19,12 @@ def create_bnb_config(kwargs):
bnb_4bit_quant_type=shared.opts.bnb_quantization_type,
bnb_4bit_compute_dtype=devices.dtype
)
kwargs['quantization_config'] = bnb_config
shared.log.debug(f'Quantization: module=all type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if kwargs is None:
return bnb_config
else:
kwargs['quantization_config'] = bnb_config
return kwargs
return kwargs
+8 -4
View File
@@ -1,7 +1,7 @@
import os
import diffusers
import transformers
from modules import shared, devices, sd_models, sd_unet, model_te, model_quant
from modules import shared, devices, sd_models, sd_unet, model_te, model_quant, model_tools
def load_overrides(kwargs, cache_dir):
@@ -69,7 +69,7 @@ def load_quants(kwargs, repo_id, cache_dir):
def load_missing(kwargs, fn, cache_dir):
keys = sd_models.get_safetensor_keys(fn)
keys = model_tools.get_safetensor_keys(fn)
size = os.stat(fn).st_size // 1024 // 1024
if size > 15000:
repo_id = 'stabilityai/stable-diffusion-3.5-large'
@@ -129,7 +129,11 @@ def load_sd3(checkpoint_info, cache_dir=None, config=None):
if fn is not None and os.path.exists(fn) and os.path.isfile(fn):
if fn.endswith('.safetensors'):
loader = diffusers.StableDiffusion3Pipeline.from_single_file
kwargs = load_missing(kwargs, fn, cache_dir)
# required_modules = model_tools.get_modules(diffusers.StableDiffusion3Pipeline)
# have_modules = model_tools.get_safetensor_keys(fn)
# loaded_modules = model_tools.load_modules('stabilityai/stable-diffusion-3.5-medium', required_modules)
# kwargs = {**kwargs, **loaded_modules}
# kwargs = load_missing(kwargs, fn, cache_dir)
repo_id = fn
elif fn.endswith('.gguf'):
kwargs = load_gguf(kwargs, fn)
@@ -138,7 +142,7 @@ def load_sd3(checkpoint_info, cache_dir=None, config=None):
else:
kwargs['variant'] = 'fp16'
shared.log.debug(f'Load model: type=SD3 kwargs={list(kwargs)}')
shared.log.debug(f'Load model: type=SD3 kwargs={list(kwargs)} repo="{repo_id}"')
kwargs = model_quant.create_bnb_config(kwargs)
pipe = loader(
+49
View File
@@ -0,0 +1,49 @@
import inspect
import diffusers
import transformers
import safetensors.torch
from modules import shared, devices, model_quant
def get_safetensor_keys(filename):
keys = []
try:
with safetensors.torch.safe_open(filename, framework="pt", device="cpu") as f:
keys = f.keys()
except Exception as e:
shared.log.error(f'Load dict: path="{filename}" {e}')
return keys
def get_modules(model: callable):
signature = inspect.signature(model.__init__, follow_wrapped=True)
params = {param.name: param.annotation for param in signature.parameters.values() if param.annotation != inspect._empty and hasattr(param.annotation, 'from_pretrained')} # pylint: disable=protected-access
for name, cls in params.items():
shared.log.debug(f'Analyze: model={model} module={name} class={cls.__name__} loadable={getattr(cls, "from_pretrained", None)}')
return params
def load_modules(repo_id: str, params: dict):
cache_dir = shared.opts.hfcache_dir
modules = {}
for name, cls in params.items():
subfolder = None
kwargs = {}
if cls == diffusers.AutoencoderKL:
subfolder = 'vae'
if cls == transformers.CLIPTextModel: # clip-vit-l
subfolder = 'text_encoder'
if cls == transformers.CLIPTextModelWithProjection: # clip-vit-g
subfolder = 'text_encoder_2'
if cls == transformers.T5EncoderModel: # t5-xxl
subfolder = 'text_encoder_3'
kwargs['quantization_config'] = model_quant.create_bnb_config()
kwargs['variant'] = 'fp16'
if cls == diffusers.SD3Transformer2DModel:
subfolder = 'transformer'
kwargs['quantization_config'] = model_quant.create_bnb_config()
if subfolder is None:
continue
shared.log.debug(f'Load: module={name} class={cls.__name__} repo={repo_id} location={subfolder}')
modules[name] = cls.from_pretrained(repo_id, subfolder=subfolder, cache_dir=cache_dir, torch_dtype=devices.dtype, **kwargs)
return modules
+5
View File
@@ -273,6 +273,7 @@ def load_diffusers_models(clear=True):
place = os.path.join(models_path, 'Diffusers')
if clear:
diffuser_repos.clear()
already_found = []
try:
for folder in os.listdir(place):
try:
@@ -303,7 +304,11 @@ def load_diffusers_models(clear=True):
if (not os.path.exists(index)) and (not os.path.exists(info)) and (not os.path.exists(config)):
debug(f'Diffusers skip model no info: {name}')
continue
if name in already_found:
debug(f'Diffusers skip model already found: {name}')
continue
repo = { 'name': name, 'filename': name, 'friendly': friendly, 'folder': folder, 'path': commit, 'hash': snapshot, 'mtime': mtime, 'model_info': info, 'model_index': index, 'model_config': config }
already_found.append(name)
diffuser_repos.append(repo)
if os.path.exists(os.path.join(folder, 'hidden')):
continue
+13 -4
View File
@@ -78,6 +78,10 @@ class YoloRestorer(Detailer):
) -> list[YoloResult]:
result = []
if isinstance(model, str):
model = self.models.get(model, None)
if model is None:
_, model = self.load(model)
if model is None:
return result
args = {
@@ -124,7 +128,9 @@ class YoloRestorer(Detailer):
mask_image = None
w, h = box[2] - box[0], box[3] - box[1]
size = w * h / (image.width * image.height)
if (min(w, h) > shared.opts.detailer_min_size if shared.opts.detailer_min_size > 0 else True) and (max(w, h) < shared.opts.detailer_max_size if shared.opts.detailer_max_size > 0 else True):
min_size = (shared.opts.detailer_min_size if shared.opts.detailer_min_size > 0 else 0) * min(w, h)
max_size = (shared.opts.detailer_max_size if shared.opts.detailer_max_size > 0 else 1) * max(w, h)
if (min(w, h) > min_size) and (max(w, h) < max_size):
if mask:
mask_image = image.copy()
mask_image = Image.new('L', image.size, 0)
@@ -138,6 +144,7 @@ class YoloRestorer(Detailer):
def load(self, model_name: str = None):
from modules import modelloader
model = None
self.dependencies()
if model_name is None:
model_name = list(self.list)[0]
@@ -158,7 +165,7 @@ class YoloRestorer(Detailer):
return model_name, model
except Exception as e:
shared.log.error(f'Load: type=Detailer name="{model_name}" error="{e}"')
return None
return None, None
def restore(self, np_image, p: processing.StableDiffusionProcessing = None):
if hasattr(p, 'recursion'):
@@ -323,8 +330,10 @@ class YoloRestorer(Detailer):
min_confidence = gr.Slider(label="Min confidence", elem_id=f"{tab}_detailer_conf", value=shared.opts.detailer_conf, minimum=0.0, maximum=1.0, step=0.05)
iou = gr.Slider(label="Max overlap", elem_id=f"{tab}_detailer_iou", value=shared.opts.detailer_iou, minimum=0, maximum=1.0, step=0.05)
with gr.Row():
min_size = gr.Slider(label="Min size", elem_id=f"{tab}_detailer_min_size", value=shared.opts.detailer_min_size, minimum=0, maximum=1024, step=1)
max_size = gr.Slider(label="Max size", elem_id=f"{tab}_detailer_max_size", value=shared.opts.detailer_max_size, minimum=0, maximum=1024, step=1)
min_size = shared.opts.detailer_min_size if shared.opts.detailer_min_size < 1 else 0.0
min_size = gr.Slider(label="Min size", elem_id=f"{tab}_detailer_min_size", value=min_size, minimum=0.1, maximum=1.0, step=0.05)
max_size = shared.opts.detailer_min_size if shared.opts.detailer_min_size < 1 and shared.opts.detailer_min_size > 0 else 1.0
max_size = gr.Slider(label="Max size", elem_id=f"{tab}_detailer_max_size", value=max_size, minimum=0.1, maximum=1.0, step=0.05)
detailers.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[])
classes.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[])
strength.change(fn=ui_settings_change, inputs=[detailers, classes, strength, padding, blur, min_confidence, max_detected, min_size, max_size, iou], outputs=[])
-1
View File
@@ -37,7 +37,6 @@ def run_postprocessing(extras_mode, image, image_folder: List[tempfile.NamedTemp
image_ext.append(ext)
shared.log.debug(f'Process: mode=batch inputs={len(image_folder)} images={len(image_data)}')
elif extras_mode == 2:
assert not shared.cmd_opts.hide_ui_dir_config, '--hide-ui-dir-config option must be disabled'
assert input_dir, 'input directory not selected'
image_list = os.listdir(input_dir)
for filename in image_list:
+1 -1
View File
@@ -14,7 +14,7 @@ def load_module(path):
module_spec = importlib.util.spec_from_file_location(os.path.basename(path), path)
module = importlib.util.module_from_spec(module_spec)
try:
if '/sd-extension-' in path or '/Lora' in path: # safe extensions without stdout intercept
if 'sd-extension-' in path or 'Lora' in path: # safe extensions without stdout intercept
module_spec.loader.exec_module(module)
else:
if debug:
+2
View File
@@ -84,6 +84,8 @@ def detect_pipeline(f: str, op: str = 'model', warning=True, quiet=False):
if 'omnigen' in f.lower():
guess = 'OmniGen'
pipeline = 'custom'
if 'sd3' in f.lower():
guess = 'Stable Diffusion 3'
if 'flux' in f.lower():
guess = 'FLUX'
if size > 11000 and size < 20000:
+11 -12
View File
@@ -19,7 +19,7 @@ from modules import paths, shared, shared_state, modelloader, devices, script_ca
from modules.timer import Timer
from modules.memstats import memory_stats
from modules.modeldata import model_data
from modules.sd_checkpoint import CheckpointInfo, select_checkpoint, list_models, checkpoints_list, checkpoint_titles, get_closet_checkpoint_match, update_model_hashes, setup_model, write_metadata, read_metadata_from_safetensors # pylint: disable=unused-import
from modules.sd_checkpoint import CheckpointInfo, select_checkpoint, list_models, checkpoints_list, checkpoint_titles, get_closet_checkpoint_match, model_hash, update_model_hashes, setup_model, write_metadata, read_metadata_from_safetensors # pylint: disable=unused-import
model_dir = "Stable-diffusion"
@@ -75,16 +75,6 @@ def read_state_dict(checkpoint_file, map_location=None, what:str='model'): # pyl
return sd
def get_safetensor_keys(filename):
keys = []
try:
with safetensors.torch.safe_open(filename, framework="pt", device="cpu") as f:
keys = f.keys()
except Exception as e:
shared.log.error(f'Load dict: path="{filename}" {e}')
return keys
def get_state_dict_from_checkpoint(pl_sd):
checkpoint_dict_replacements = {
'cond_stage_model.transformer.embeddings.': 'cond_stage_model.transformer.text_model.embeddings.',
@@ -1052,6 +1042,15 @@ def clean_diffuser_pipe(pipe):
def set_diffuser_pipe(pipe, new_pipe_type):
exclude = [
'StableDiffusionReferencePipeline',
'StableDiffusionAdapterPipeline',
'AnimateDiffPipeline',
'AnimateDiffSDXLPipeline',
'OmniGenPipeline',
'StableDiffusion3ControlNetPipeline',
]
n = getattr(pipe.__class__, '__name__', '')
if new_pipe_type == DiffusersTaskType.TEXT_2_IMAGE:
clean_diffuser_pipe(pipe)
@@ -1060,7 +1059,7 @@ def set_diffuser_pipe(pipe, new_pipe_type):
return pipe
# skip specific pipelines
if n in ['StableDiffusionReferencePipeline', 'StableDiffusionAdapterPipeline', 'AnimateDiffPipeline', 'AnimateDiffSDXLPipeline', 'OmniGenPipeline']:
if n in exclude:
return pipe
if 'Onnx' in pipe.__class__.__name__:
return pipe
+3 -3
View File
@@ -821,8 +821,8 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), {
"detailer_conf": OptionInfo(0.6, "Min confidence", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.05, "visible": False}),
"detailer_max": OptionInfo(2, "Max detected", gr.Slider, {"minimum": 1, "maximum": 10, "step": 1, "visible": False}),
"detailer_iou": OptionInfo(0.5, "Max overlap", gr.Slider, {"minimum": 0, "maximum": 1.0, "step": 0.05, "visible": False}),
"detailer_min_size": OptionInfo(0, "Min object size", gr.Slider, {"minimum": 0, "maximum": 1024, "step": 1, "visible": False}),
"detailer_max_size": OptionInfo(0, "Max object size", gr.Slider, {"minimum": 0, "maximum": 1024, "step": 1, "visible": False}),
"detailer_min_size": OptionInfo(0.0, "Min object size", gr.Slider, {"minimum": 0.1, "maximum": 1, "step": 0.05, "visible": False}),
"detailer_max_size": OptionInfo(1.0, "Max object size", gr.Slider, {"minimum": 0.1, "maximum": 1, "step": 0.05, "visible": False}),
"detailer_padding": OptionInfo(20, "Item padding", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1, "visible": False}),
"detailer_blur": OptionInfo(10, "Item edge blur", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1, "visible": False}),
"detailer_strength": OptionInfo(0.5, "Detailer strength", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01, "visible": False}),
@@ -1101,7 +1101,7 @@ profiler = None
opts = Options()
config_filename = cmd_opts.config
opts.load(config_filename)
cmd_opts = cmd_args.compatibility_args(opts, cmd_opts)
cmd_opts = cmd_args.settings_args(opts, cmd_opts)
if cmd_opts.use_xformers:
opts.data['cross_attention_optimization'] = 'xFormers'
opts.data['uni_pc_lower_order_final'] = opts.schedulers_use_loworder # compatibility
+13 -6
View File
@@ -355,13 +355,20 @@ def create_ui(startup_timer = None):
ui_onnx.create_ui()
with gr.TabItem("Change log", id="change_log", elem_id="system_tab_changelog"):
with open('CHANGELOG.md', 'r', encoding='utf-8') as f:
md = f.read()
gr.Markdown(md)
def get_changelog():
with open('CHANGELOG.md', 'r', encoding='utf-8') as f:
content = f.read()
content = content.replace('# Change Log for SD.Next', ' ')
return content
with gr.TabItem("Licenses", id="system_licenses", elem_id="system_tab_licenses"):
gr.HTML(shared.html("licenses.html"), elem_id="licenses", elem_classes="licenses")
create_dirty_indicator("tab_licenses", [], interactive=False)
with gr.Column():
get_changelog_btn = gr.Button(value='Get changelog', elem_id="get_changelog")
with gr.Column():
_changelog_search = gr.Textbox(label="Search", elem_id="changelog_search")
_changelog_result = gr.HTML(elem_id="changelog_result")
changelog_markdown = gr.Markdown('', elem_id="changelog_markdown")
get_changelog_btn.click(fn=get_changelog, outputs=[changelog_markdown], show_progress=True)
def unload_sd_weights():
modules.sd_models.unload_model_weights(op='model')
+1 -1
View File
@@ -7,7 +7,7 @@
"url": "https://github.com/vladmandic/automatic/issues"
},
"homepage": "https://github.com/vladmandic/automatic",
"license": "AGPLv3",
"license": "Apache-2.0",
"engines": {
"node": ">=14.0.0"
},
+1 -1
View File
@@ -50,7 +50,7 @@ pandas
protobuf==4.25.3
pytorch_lightning==1.9.4
tokenizers==0.20.1
transformers==4.46.0
transformers==4.46.1
urllib3==1.26.19
Pillow==10.4.0
timm==0.9.16
+2 -2
View File
@@ -32,10 +32,10 @@ class Script(scripts.Script):
def load(self):
if self.tokenizer is None:
self.tokenizer = AutoTokenizer.from_pretrained('gokaygokay/Flux-Prompt-Enhance', cache_dir=shared.opts.diffusers_dir)
self.tokenizer = AutoTokenizer.from_pretrained('gokaygokay/Flux-Prompt-Enhance', cache_dir=shared.opts.hfcache_dir)
if self.model is None:
shared.log.info(f'Prompt enhance: model="{repo_id}"')
self.model = AutoModelForSeq2SeqLM.from_pretrained('gokaygokay/Flux-Prompt-Enhance', cache_dir=shared.opts.diffusers_dir).to(device=devices.cpu, dtype=devices.dtype)
self.model = AutoModelForSeq2SeqLM.from_pretrained('gokaygokay/Flux-Prompt-Enhance', cache_dir=shared.opts.hfcache_dir).to(device=devices.cpu, dtype=devices.dtype)
def enhance(self, prompt, auto_apply: bool = False, temperature: float = 0.7, repetition_penalty: float = 1.2, max_length: int = 128):
self.load()
+18 -18
View File
@@ -48,10 +48,11 @@ class Script(scripts.Script):
csv_mode = gr.Checkbox(label='Text inputs', value=False, elem_id=self.elem_id("csv_mode"), container=False)
draw_legend = gr.Checkbox(label='Legend', value=True, elem_id=self.elem_id("draw_legend"), container=False)
no_fixed_seeds = gr.Checkbox(label='Random seeds', value=False, elem_id=self.elem_id("no_fixed_seeds"), container=False)
include_time = gr.Checkbox(label='Add time info', value=False, elem_id=self.elem_id("include_time"), container=False)
with gr.Column():
no_grid = gr.Checkbox(label='Skip grid', value=False, elem_id=self.elem_id("no_xyz_grid"), container=False)
include_lone_images = gr.Checkbox(label='Sub-images', value=False, elem_id=self.elem_id("include_lone_images"), container=False)
include_sub_grids = gr.Checkbox(label='Sub-grids', value=False, elem_id=self.elem_id("include_sub_grids"), container=False)
include_grid = gr.Checkbox(label='Include main grid', value=True, elem_id=self.elem_id("no_xyz_grid"), container=False)
include_subgrids = gr.Checkbox(label='Include sub grids', value=False, elem_id=self.elem_id("include_sub_grids"), container=False)
include_images = gr.Checkbox(label='Include images', value=False, elem_id=self.elem_id("include_lone_images"), container=False)
with gr.Row():
margin_size = gr.Slider(label="Grid margins", minimum=0, maximum=500, value=0, step=2, elem_id=self.elem_id("margin_size"))
with gr.Row():
@@ -130,10 +131,9 @@ class Script(scripts.Script):
(z_values_dropdown, lambda params:get_dropdown_update_from_params("Z",params)),
)
return [x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, csv_mode, draw_legend, no_fixed_seeds, no_grid, include_lone_images, include_sub_grids, margin_size]
return [x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, csv_mode, draw_legend, no_fixed_seeds, include_grid, include_subgrids, include_images, include_time, margin_size]
def run(self, p, x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, csv_mode, draw_legend, no_fixed_seeds, no_grid, include_lone_images, include_sub_grids, margin_size): # pylint: disable=W0221
shared.log.debug(f'xyzgrid: x_type={x_type}|x_values={x_values}|x_values_dropdown={x_values_dropdown}|y_type={y_type}|{y_values}={y_values}|{y_values_dropdown}={y_values_dropdown}|z_type={z_type}|z_values={z_values}|z_values_dropdown={z_values_dropdown}|draw_legend={draw_legend}|include_lone_images={include_lone_images}|include_sub_grids={include_sub_grids}|no_grid={no_grid}|margin_size={margin_size}')
def run(self, p, x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, csv_mode, draw_legend, no_fixed_seeds, include_grid, include_subgrids, include_images, include_time, margin_size): # pylint: disable=W0221
if not no_fixed_seeds:
processing.fix_seed(p)
if not shared.opts.return_grid:
@@ -307,38 +307,38 @@ class Script(scripts.Script):
z_labels=[z_opt.format_value(p, z_opt, z) for z in zs],
cell=cell,
draw_legend=draw_legend,
include_lone_images=include_lone_images,
include_sub_grids=include_sub_grids,
include_lone_images=include_images,
include_sub_grids=include_subgrids,
first_axes_processed=first_axes_processed,
second_axes_processed=second_axes_processed,
margin_size=margin_size,
no_grid=no_grid,
no_grid=not include_grid,
include_time=include_time,
)
if not processed.images:
return processed # It broke, no further handling needed.
return processed # something broke, no further handling needed.
z_count = len(zs)
processed.infotexts[:1+z_count] = grid_infotext[:1+z_count] # Set the grid infotexts to the real ones with extra_generation_params (1 main grid + z_count sub-grids)
if not include_lone_images:
# Don't need sub-images anymore, drop from list:
if no_grid and include_sub_grids:
processed.infotexts[:1+z_count] = grid_infotext[:1+z_count] # set the grid infotexts to the real ones with extra_generation_params (1 main grid + z_count sub-grids)
if not include_images: # dont need sub-images anymore, drop from list:
if not include_grid and include_subgrids:
processed.images = processed.images[:z_count] # we don't have the main grid image, and need zero additional sub-images
else:
processed.images = processed.images[:z_count+1] # we either have the main grid image, or need one sub-images
if shared.opts.grid_save: # Auto-save main and sub-grids:
grid_count = z_count + ( 1 if not no_grid and z_count > 1 else 0 )
if shared.opts.grid_save: # auto-save main and sub-grids:
grid_count = z_count + ( 1 if include_grid and z_count > 1 else 0 )
for g in range(grid_count):
adj_g = g-1 if g > 0 else g
info = processed.infotexts[g]
prompt = processed.all_prompts[adj_g]
seed = processed.all_seeds[adj_g]
images.save_image(processed.images[g], p.outpath_grids, "grid", info=info, extension=shared.opts.grid_format, prompt=prompt, seed=seed, grid=True, p=processed)
if not include_sub_grids: # Done with sub-grids, drop all related information:
if not include_subgrids: # done with sub-grids, drop all related information:
for _sg in range(z_count):
del processed.images[1]
del processed.all_prompts[1]
del processed.all_seeds[1]
del processed.infotexts[1]
elif no_grid:
elif include_grid:
del processed.infotexts[0]
return processed
+8 -8
View File
@@ -84,13 +84,13 @@ class SharedSettingsStackHelper(object):
axis_options = [
AxisOption("Nothing", str, do_nothing, fmt=format_nothing),
AxisOption("[Model] Model", str, apply_checkpoint, cost=1.0, fmt=format_value, choices=lambda: sorted(sd_models.checkpoints_list)),
AxisOption("[Model] Model", str, apply_checkpoint, cost=1.0, fmt=format_value_add_label, choices=lambda: sorted(sd_models.checkpoints_list)),
AxisOption("[Model] UNET", str, apply_unet, cost=0.8, choices=lambda: ['None'] + list(sd_unet.unet_dict)),
AxisOption("[Model] VAE", str, apply_vae, cost=0.6, choices=lambda: ['None'] + list(sd_vae.vae_dict)),
AxisOption("[Model] Refiner", str, apply_refiner, cost=0.8, fmt=format_value, choices=lambda: ['None'] + sorted(sd_models.checkpoints_list)),
AxisOption("[Model] Refiner", str, apply_refiner, cost=0.8, fmt=format_value_add_label, choices=lambda: ['None'] + sorted(sd_models.checkpoints_list)),
AxisOption("[Model] Text encoder", str, apply_te, cost=0.7, choices=shared_items.sd_te_items),
AxisOption("[Model] Dictionary", str, apply_dict, fmt=format_value, cost=0.9, choices=lambda: ['None'] + list(sd_models.checkpoints_list)),
AxisOption("[Prompt] Search & replace", str, apply_prompt, fmt=format_value),
AxisOption("[Model] Dictionary", str, apply_dict, fmt=format_value_add_label, cost=0.9, choices=lambda: ['None'] + list(sd_models.checkpoints_list)),
AxisOption("[Prompt] Search & replace", str, apply_prompt, fmt=format_value_add_label),
AxisOption("[Prompt] Prompt order", str_permutations, apply_order, fmt=format_value_join_list),
AxisOption("[Network] LoRA", str, apply_lora, cost=0.5, choices=list_lora),
AxisOption("[Network] LoRA strength", float, apply_setting('extra_networks_default_multiplier')),
@@ -109,8 +109,8 @@ axis_options = [
AxisOption("[Process] Model args", str, apply_task_args),
AxisOption("[Process] Processing args", str, apply_processing),
AxisOption("[Process] Server options", str, apply_options),
AxisOptionTxt2Img("[Sampler] Name", str, apply_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]),
AxisOptionImg2Img("[Sampler] Name", str, apply_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers_for_img2img]),
AxisOptionTxt2Img("[Sampler] Name", str, apply_sampler, fmt=format_value_add_label, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]),
AxisOptionImg2Img("[Sampler] Name", str, apply_sampler, fmt=format_value_add_label, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers_for_img2img]),
AxisOption("[Sampler] Sigma method", str, apply_setting("schedulers_sigma"), choices=lambda: ['default', 'karras', 'beta', 'exponential']),
AxisOption("[Sampler] Timestep spacing", str, apply_setting("schedulers_timestep_spacing"), choices=lambda: ['default', 'linspace', 'leading', 'trailing']),
AxisOption("[Sampler] Timestep range", int, apply_setting("schedulers_timesteps_range")),
@@ -122,7 +122,7 @@ axis_options = [
AxisOption("[Sampler] eta delta", float, apply_setting("eta_noise_seed_delta")),
AxisOption("[Sampler] eta multiplier", float, apply_setting("scheduler_eta")),
AxisOption("[Refine] Upscaler", str, apply_field("hr_upscaler"), cost=0.3, choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]),
AxisOption("[Refine] Sampler", str, apply_hr_sampler_name, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]),
AxisOption("[Refine] Sampler", str, apply_hr_sampler_name, fmt=format_value_add_label, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]),
AxisOption("[Refine] Denoising strength", float, apply_field("denoising_strength")),
AxisOption("[Refine] Hires steps", int, apply_field("hr_second_pass_steps")),
AxisOption("[Refine] Guidance scale", float, apply_field("image_cfg_scale")),
@@ -131,7 +131,7 @@ axis_options = [
AxisOption("[Refine] Refiner steps", float, apply_field("refiner_steps")),
AxisOption("[Postprocess] Upscaler", str, apply_upscaler, cost=0.4, choices=lambda: [x.name for x in shared.sd_upscalers][1:]),
AxisOption("[Postprocess] Context", str, apply_context, choices=lambda: ["Add with forward", "Remove with forward", "Add with backward", "Remove with backward"]),
AxisOption("[Postprocess] Detailer", str, apply_detailer, fmt=format_value),
AxisOption("[Postprocess] Detailer", str, apply_detailer, fmt=format_value_add_label),
AxisOption("[HDR] Mode", int, apply_field("hdr_mode")),
AxisOption("[HDR] Brightness", float, apply_field("hdr_brightness")),
AxisOption("[HDR] Color", float, apply_field("hdr_color")),
+16 -6
View File
@@ -4,23 +4,28 @@ from PIL import Image
from modules import shared, images, processing
def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend, include_lone_images, include_sub_grids, first_axes_processed, second_axes_processed, margin_size, no_grid): # pylint: disable=unused-argument
hor_texts = [[images.GridAnnotation(x)] for x in x_labels]
ver_texts = [[images.GridAnnotation(y)] for y in y_labels]
title_texts = [[images.GridAnnotation(z)] for z in z_labels]
def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend, include_lone_images, include_sub_grids, first_axes_processed, second_axes_processed, margin_size, no_grid: False, include_time: False): # pylint: disable=unused-argument
x_texts = [[images.GridAnnotation(x)] for x in x_labels]
y_texts = [[images.GridAnnotation(y)] for y in y_labels]
z_texts = [[images.GridAnnotation(z)] for z in z_labels]
list_size = (len(xs) * len(ys) * len(zs))
processed_result = None
shared.state.job_count = list_size * p.n_iter
t0 = time.time()
i = 0
def process_cell(x, y, z, ix, iy, iz):
nonlocal processed_result
nonlocal processed_result, i
i += 1
shared.log.debug(f'XYZ grid process: x={ix+1}/{len(xs)} y={iy+1}/{len(ys)} z={iz+1}/{len(zs)} total={i/list_size:.2f}')
def index(ix, iy, iz):
return ix + iy * len(xs) + iz * len(xs) * len(ys)
shared.state.job = 'grid'
p0 = time.time()
processed: processing.Processed = cell(x, y, z, ix, iy, iz)
p1 = time.time()
if processed_result is None:
processed_result = copy(processed)
if processed_result is None:
@@ -30,13 +35,17 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend
processed_result.all_prompts = [None] * list_size
processed_result.all_seeds = [None] * list_size
processed_result.infotexts = [None] * list_size
processed_result.time = [0] * list_size
processed_result.index_of_first_image = 1
idx = index(ix, iy, iz)
if processed is not None and processed.images:
processed_result.images[idx] = processed.images[0]
if include_time:
processed_result.images[idx] = images.draw_overlay(processed_result.images[idx], f'time: {p1 - p0:.2f}')
processed_result.all_prompts[idx] = processed.prompt
processed_result.all_seeds[idx] = processed.seed
processed_result.infotexts[idx] = processed.infotexts[0]
processed_result.time[idx] = round(p1 - p0, 2)
else:
cell_mode = "P"
cell_size = (processed_result.width, processed_result.height)
@@ -44,6 +53,7 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend
cell_mode = processed_result.images[0].mode
cell_size = processed_result.images[0].size
processed_result.images[idx] = Image.new(cell_mode, cell_size)
return
if first_axes_processed == 'x':
for ix, x in enumerate(xs):
@@ -93,7 +103,7 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend
if (not no_grid or include_sub_grids) and images.check_grid_size(to_process):
grid = images.image_grid(to_process, rows=len(ys))
if draw_legend:
grid = images.draw_grid_annotations(grid, w, h, hor_texts, ver_texts, margin_size, title=title_texts[i])
grid = images.draw_grid_annotations(grid, w, h, x_texts, y_texts, margin_size, title=z_texts[i])
processed_result.images.insert(i, grid)
processed_result.all_prompts.insert(i, processed_result.all_prompts[idx0])
processed_result.all_seeds.insert(i, processed_result.all_seeds[idx0])
+45 -5
View File
@@ -57,9 +57,10 @@ class Script(scripts.Script):
draw_legend = gr.Checkbox(label='Draw legend', value=True, elem_id=self.elem_id("draw_legend"), container=False)
csv_mode = gr.Checkbox(label='Use text inputs', value=False, elem_id=self.elem_id("csv_mode"), container=False)
no_fixed_seeds = gr.Checkbox(label='Use random seeds', value=False, elem_id=self.elem_id("no_fixed_seeds"), container=False)
include_time = gr.Checkbox(label='Add time info', value=False, elem_id=self.elem_id("include_time"), container=False)
with gr.Column():
include_grid = gr.Checkbox(label='Create main grid', value=True, elem_id=self.elem_id("no_xyz_grid"), container=False)
include_subgrids = gr.Checkbox(label='Create partial grids', value=False, elem_id=self.elem_id("include_sub_grids"), container=False)
include_grid = gr.Checkbox(label='Include main grid', value=True, elem_id=self.elem_id("no_xyz_grid"), container=False)
include_subgrids = gr.Checkbox(label='Include sub grids', value=False, elem_id=self.elem_id("include_sub_grids"), container=False)
include_images = gr.Checkbox(label='Include images', value=False, elem_id=self.elem_id("include_lone_images"), container=False)
with gr.Row():
margin_size = gr.Slider(label="Grid margins", minimum=0, maximum=500, value=0, step=2, elem_id=self.elem_id("margin_size"))
@@ -139,9 +140,9 @@ class Script(scripts.Script):
(z_values_dropdown, lambda params:get_dropdown_update_from_params("Z",params)),
)
return [enabled, x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, csv_mode, draw_legend, no_fixed_seeds, include_grid, include_subgrids, include_images, margin_size]
return [enabled, x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, csv_mode, draw_legend, no_fixed_seeds, include_grid, include_subgrids, include_images, include_time, margin_size]
def process(self, p, enabled, x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, csv_mode, draw_legend, no_fixed_seeds, include_grid, include_subgrids, include_images, margin_size): # pylint: disable=W0221
def process(self, p, enabled, x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, csv_mode, draw_legend, no_fixed_seeds, include_grid, include_subgrids, include_images, include_time, margin_size): # pylint: disable=W0221
global active, cache # pylint: disable=W0603
cache = None
if not enabled or active:
@@ -327,8 +328,10 @@ class Script(scripts.Script):
second_axes_processed=second_axes_processed,
margin_size=margin_size,
no_grid=not include_grid,
include_time=include_time,
)
"""
if not processed.images:
active = False
return processed # It broke, no further handling needed.
@@ -354,6 +357,43 @@ class Script(scripts.Script):
active = False
cache = processed
return processed
"""
def process_images(self, p, enabled, x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, csv_mode, draw_legend, no_fixed_seeds, include_grid, include_subgrids, include_images, margin_size): # pylint: disable=W0221, W0613
if not processed.images:
return processed # It broke, no further handling needed.
z_count = len(zs)
processed.infotexts[:1+z_count] = grid_infotext[:1+z_count] # set the grid infotexts to the real ones with extra_generation_params (1 main grid + z_count sub-grids)
if not include_images: # dont need sub-images anymore, drop from list:
if not include_grid and include_subgrids:
processed.images = processed.images[:z_count] # we don't have the main grid image, and need zero additional sub-images
else:
processed.images = processed.images[:z_count+1] # we either have the main grid image, or need one sub-images
if shared.opts.grid_save: # auto-save main and sub-grids:
grid_count = z_count + ( 1 if include_grid and z_count > 1 else 0 )
for g in range(grid_count):
adj_g = g-1 if g > 0 else g
info = processed.infotexts[g]
prompt = processed.all_prompts[adj_g]
seed = processed.all_seeds[adj_g]
images.save_image(processed.images[g], p.outpath_grids, "grid", info=info, extension=shared.opts.grid_format, prompt=prompt, seed=seed, grid=True, p=processed)
if not include_subgrids: # done with sub-grids, drop all related information:
for _sg in range(z_count):
del processed.images[1]
del processed.all_prompts[1]
del processed.all_seeds[1]
del processed.infotexts[1]
elif include_grid:
del processed.infotexts[0]
p.do_not_save_grid = True
p.do_not_save_samples = True
active = False
cache = processed
return processed
def process_images(self, p, *args): # pylint: disable=W0221, W0613
if p.iteration > 0 and cache is not None and len(cache.images) > 0:
cache.images = [] # avoid returning same images multiple items
return cache
+1 -1
Submodule wiki updated: 4360bc7fcf...a64e3776fd