diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e5765563..47ffc4781 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,35 @@
# Change Log for SD.Next
+## Update for 2023-10-18
+
+Service release addressing all zero-day issues reported so far...
+
+**Fixes**
+- fix freeu for backend original and add it to xyz grid
+- fix loading diffuser models in huggingface format from non-standard location
+- fix default styles looking in wrong location
+- fix missing upscaler folder on initial startup
+- fix handling of relative path for models
+- fix simple live preview device mismatch
+- fix batch img2img
+- fix diffusers dpm++ 2m and 1s samplers
+- fix new style filename template
+- fix image name template using model name
+- fix model path using relative path
+- fix torch-rocm version detection (thanks @xangelix)
+- force second requirements check on startup
+- remove lyco, multiple_tqdm
+- enhance extension compatibility for exensions directly importing codeformers
+- enhance extension compatibility for exensions directly accessing processing params
+- update `openvino` (thanks @disty0)
+- update `typing-extensions`
+
+**Themes**
+- all built-in themes are fully supported:
+ - *black-teal (default), light-teal, black-orange, invoked, amethyst-nightfall, midnight-barbie*
+- if you're using any **gradio default** themes or a **3rd party** theme or that are not optimized for SD.Next, you may experience issues
+ default minimal style has been updated for compatibility, but actual styling is completely outside of SD.Next control
+
## Update for 2023-10-17
This is a major release, with many changes and new functionality...
diff --git a/README.md b/README.md
index bb3b34e94..13e53421a 100644
--- a/README.md
+++ b/README.md
@@ -175,7 +175,7 @@ General goals:
### **Sponsors**
-
+
diff --git a/beautiful girl sitting on an edge of a.jpg b/beautiful girl sitting on an edge of a.jpg
new file mode 100644
index 000000000..1c5e7382f
Binary files /dev/null and b/beautiful girl sitting on an edge of a.jpg differ
diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py
index 4edcf986b..2132c8ed5 100644
--- a/extensions-builtin/Lora/networks.py
+++ b/extensions-builtin/Lora/networks.py
@@ -374,8 +374,13 @@ def list_available_networks():
available_network_hash_lookup.clear()
forbidden_network_aliases.update({"none": 1, "Addams": 1})
os.makedirs(shared.cmd_opts.lora_dir, exist_ok=True)
- candidates = list(shared.walk_files(shared.cmd_opts.lora_dir, allowed_extensions=[".pt", ".ckpt", ".safetensors"]))
- candidates += list(shared.walk_files(shared.cmd_opts.lyco_dir, allowed_extensions=[".pt", ".ckpt", ".safetensors"]))
+ candidates = []
+ if os.path.exists(shared.cmd_opts.lora_dir):
+ candidates += list(shared.walk_files(shared.cmd_opts.lora_dir, allowed_extensions=[".pt", ".ckpt", ".safetensors"]))
+ else:
+ shared.log.warning('LoRA directory not found: path={shared.cmd_opts.lora_dir}')
+ if os.path.exists(shared.cmd_opts.lyco_dir):
+ candidates += list(shared.walk_files(shared.cmd_opts.lyco_dir, allowed_extensions=[".pt", ".ckpt", ".safetensors"]))
for filename in candidates:
if os.path.isdir(filename):
continue
diff --git a/html/locale_en.json b/html/locale_en.json
index 92b41bf39..de35d33ec 100644
--- a/html/locale_en.json
+++ b/html/locale_en.json
@@ -59,7 +59,7 @@
{"id":"","label":"Skip","localized":"","hint":"Stop processing current job and continue processing"},
{"id":"","label":"Interrupt","localized":"","hint":"Interrupt current processing job"},
{"id":"","label":"Pause","localized":"","hint":"Pause processing"},
- {"id":"","label":"Apply","localized":"","hint":"Apply parameters from last known generated image"},
+ {"id":"","label":"Restore","localized":"","hint":"Restore parameters from last known generated image"},
{"id":"","label":"Clear","localized":"","hint":"Clear prompts"},
{"id":"","label":"Networks","localized":"","hint":"Open extra network interface"},
{"id":"","label":"Interrogate\nCLIP","localized":"","hint":"Run interrogate using CLIP model"},
@@ -79,26 +79,23 @@
{"id":"","label":"Do not automatically build extra network pages","localized":"","hint":""},
{"id":"","label":"Use LyCoris handler for all Lora types","localized":"","hint":""},
{"id":"","label":"Use Kohya method for handling multiple LoRA","localized":"","hint":""},
- {"id":"","label":"Multiplier for extra networks","localized":"","hint":"When adding extra network such as Hypernetwork or Lora to prompt, use this multiplier for it"},
+ {"id":"","label":"Default multiplier for extra networks","localized":"","hint":"When adding extra network such as Lora to prompt, use this multiplier for it"},
{"id":"","label":"Add hypernetwork to prompt","localized":"","hint":""},
{"id":"","label":"Add Lora to prompt","localized":"","hint":""},
{"id":"","label":"shuffle tags by ',' when creating prompts.","localized":"","hint":""},
{"id":"","label":"When adding to prompt, refer to Lora by","localized":"","hint":""},
{"id":"","label":"add lora hashes to infotext","localized":"","hint":""},
- {"id":"","label":"Checkpoints","localized":"","hint":"Trained model checkpoints"},
+ {"id":"","label":"Model","localized":"","hint":"Trained model checkpoints"},
+ {"id":"","label":"Style","localized":"","hint":"Additional styles to be applied on selected generation paramters"},
{"id":"","label":"Styles","localized":"","hint":"Additional styles to be applied on selected generation paramters"},
{"id":"","label":"Lora","localized":"","hint":"LoRA: Low-Rank Adaptation. Fine-tuned model that is applied on top of a loaded model"},
{"id":"","label":"LyCORIS","localized":"","hint":"LyCORIS: Lora beYond Conventional methods. Fine-tuned model that is applied on top of a loaded model"},
- {"id":"","label":"Textual Inversion","localized":"","hint":"Textual inversion embedding is a trained embedded information about the subject"},
- {"id":"","label":"Hypernetworks","localized":"","hint":"Small trained neural network that modifies behavior of the loaded model"},
- {"id":"","label":"Save preview","localized":"","hint":"Save current image as extra network preview"},
- {"id":"","label":"Save description","localized":"","hint":"Save current text as extra network description"},
- {"id":"","label":"Read description","localized":"","hint":"Read stored extra network description"}
+ {"id":"","label":"Embedding","localized":"","hint":"Textual inversion embedding is a trained embedded information about the subject"},
+ {"id":"","label":"Hypernetwork","localized":"","hint":"Small trained neural network that modifies behavior of the loaded model"}
],
"gallery buttons": [
{"id":"","label":"show","localized":"","hint":"Show image location"},
{"id":"","label":"save","localized":"","hint":"Save image"},
- {"id":"","label":"zip","localized":"","hint":"Create zip archive from images"},
{"id":"","label":"delete","localized":"","hint":"Delete image"},
{"id":"","label":"replace","localized":"","hint":"Replace image"},
{"id":"","label":"➠ text","localized":"","hint":"Transfer image to text interface"},
@@ -118,8 +115,8 @@
{"id":"","label":"Specific branch name","localized":"","hint":"Specify extension branch name, leave blank for default"},
{"id":"","label":"Local directory name","localized":"","hint":"Directory where to install extension, leave blank for default"},
{"id":"","label":"Refresh extension list","localized":"","hint":"Refresh list of available extensions"},
- {"id":"","label":"Update installed extensions","localized":"","hint":"Update installed extensions to their latest available version"},
- {"id":"","label":"Apply changes & restart server","localized":"","hint":"Apply all changes and restart server"},
+ {"id":"","label":"Update all installed","localized":"","hint":"Update installed extensions to their latest available version"},
+ {"id":"","label":"Apply changes","localized":"","hint":"Apply all changes and restart server"},
{"id":"","label":"install","localized":"","hint":"install this extension"},
{"id":"","label":"uninstall","localized":"","hint":"uninstall this extension"},
{"id":"","label":"User interface","localized":"","hint":"Review and set current values as default values for the user interface"},
@@ -135,13 +132,15 @@
{"id":"","label":"Advanced","localized":"","hint":"Additional advanced options"},
{"id":"","label":"Sampling method","localized":"","hint":"Which algorithm to use to produce the image"},
{"id":"","label":"Sampling steps","localized":"","hint":"How many times to improve the generated image iteratively; higher values take longer; very low values can produce bad results"},
+ {"id":"","label":"Sampler options","localized":"","hint":"Advanced sampler options"},
+ {"id":"","label":"Sigma algorithm","localized":"","hint":"Algorithm to progress noise resolution on each sampler step"},
{"id":"","label":"Restore faces","localized":"","hint":"Use a pre-trained model to correct the generated faces. See GFPGAN or Codeformer."},
{"id":"","label":"Tiling","localized":"","hint":"Produce an image that can be tiled"},
{"id":"","label":"full quality","localized":"","hint":"Use full quality VAE to decode latent samples"},
{"id":"","label":"face restore","localized":"","hint":"Run processed image through additional face restoration model"},
{"id":"","label":"denoise","localized":"","hint":"Denoising details for img2img"},
{"id":"","label":"remove background","localized":"","hint":"Run processed image through additional background removal model"},
- {"id":"","label":"Second pass","localized":"","hint":"Use a similar process as image to image to upscale and/or add detail to the final image. Optionally uses refiner model to enhance image details."},
+ {"id":"","label":"Enable second pass","localized":"","hint":"Use a similar process as image to image to upscale and/or add detail to the final image. Optionally uses refiner model to enhance image details."},
{"id":"","label":"Denoising strength","localized":"","hint":"Determines how little respect the algorithm should have for image's content. At 0, nothing will change, and at 1 you'll get an unrelated image. With values below 1.0, processing will take less steps than the Sampling Steps slider specifies"},
{"id":"","label":"Denoise start","localized":"","hint":"Override denoise strength by stating how early base model should finish and when refiner should start. Only applicable to refiner usage. If set to 0 or 1, denoising strength will be used"},
{"id":"","label":"Hires steps","localized":"","hint":"Number of sampling steps for upscaled picture. If 0, uses same as for original"},
@@ -163,7 +162,7 @@
{"id":"","label":"Batch size","localized":"","hint":"How many image to create in a single batch (increases generation performance at cost of higher VRAM usage)"},
{"id":"","label":"cfg scale","localized":"","hint":"Classifier Free Guidance scale: how strongly the image should conform to prompt. Lower values produce more creative results, higher values make it follow the prompt more strictly; recommended values between 5-10"},
{"id":"","label":"CLIP skip","localized":"","hint":"Clip skip is a feature that allows users to control the level of specificity of the prompt, the higher the CLIP skip value, the less deep the prompt will be interpreted. CLIP Skip 1 is typical while some anime models produce better results at CLIP skip 2"},
- {"id":"","label":"Seed","localized":"","hint":"A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result"},
+ {"id":"","label":"Initial seed","localized":"","hint":"A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result"},
{"id":"","label":"Extra","localized":"","hint":"Show additional options"},
{"id":"","label":"Variation seed","localized":"","hint":"Seed of a different picture to be mixed into the generation"},
{"id":"","label":"Variation strength","localized":"","hint":"How strong of a variation to produce. At 0, there will be no effect. At 1, you will get the complete picture with variation seed (except for ancestral samplers, where you will just get something)"},
@@ -183,10 +182,7 @@
{"id":"","label":"Resize","localized":"","hint":"Resizing details. Higher resolutions require additional processing memory."},
{"id":"","label":"Crop to fit","localized":"","hint":"If the dimensions of your source image (e.g. 512x510) deviate from your target dimensions (e.g. 1024x768) this function will fit your upscaled image into your target size image. Excess will be cropped"},
{"id":"","label":"Secondary Upscaler","localized":"","hint":"Select secondary upscaler to run after initial upscaler"},
- {"id":"","label":"Upscaler 2 visibility","localized":"","hint":"Strength of the secondary upscaler"},
- {"id":"","label":"GFPGAN visibility","localized":"","hint":"Strength of GFPGAN face restore network, 0=disabled"},
- {"id":"","label":"CodeFormer visibility","localized":"","hint":"Strength of CodeFormer face restore network, 0=disabled"},
- {"id":"","label":"CodeFormer weight","localized":"","hint":"0=maximum strength, 1=minimum strength"}
+ {"id":"","label":"Upscaler 2 visibility","localized":"","hint":"Strength of the secondary upscaler"}
],
"settings menu": [
{"id":"settings_submit","label":"Apply settings","localized":"","hint":"Save current settings, server restart is recommended"},
@@ -251,7 +247,7 @@
{"id":"","label":"Merge","localized":"","hint":""},
{"id":"","label":"Validate","localized":"","hint":""},
{"id":"","label":"List model details","localized":"","hint":""},
- {"id":"","label":"Calculate hash for all models (may take a long time)","localized":"","hint":""},
+ {"id":"","label":"Calculate hash for all models","localized":"","hint":"Calculates hash for all available models which may take a very long time"},
{"id":"","label":"search models","localized":"","hint":""},
{"id":"","label":"select model","localized":"","hint":""},
{"id":"","label":"specify model variant","localized":"","hint":""},
@@ -492,8 +488,8 @@
{"id":"","label":"Path to notification sound","localized":"","hint":""},
{"id":"","label":"Live preview display period","localized":"","hint":""},
{"id":"","label":"Full VAE","localized":"","hint":""},
- {"id":"","label":"Approximate NN","localized":"","hint":"Cheap neural network approximation. Very fast compared to VAE, but produces pictures with 4 times smaller horizontal/vertical resolution and lower quality"},
- {"id":"","label":"Approximate simple","localized":"","hint":"Very cheap approximation. Very fast compared to VAE, but produces pictures with 8 times smaller horizontal/vertical resolution and extremely low quality"},
+ {"id":"","label":"Approximate","localized":"","hint":"Cheap neural network approximation. Very fast compared to VAE, but produces pictures with 4 times smaller horizontal/vertical resolution and lower quality"},
+ {"id":"","label":"Simple","localized":"","hint":"Very cheap approximation. Very fast compared to VAE, but produces pictures with 8 times smaller horizontal/vertical resolution and extremely low quality"},
{"id":"","label":"TAESD","localized":"","hint":""},
{"id":"","label":"Combined","localized":"","hint":""},
{"id":"","label":"Progress update period","localized":"","hint":"Update period for UI progress bar and preview checks, in miliseconds"},
@@ -546,8 +542,6 @@
{"id":"","label":"Filename word regex","localized":"","hint":"This regular expression will be used extract words from filename, and they will be joined using the option below into label text used for training. Leave empty to keep filename text as it is"},
{"id":"","label":"Filename join string","localized":"","hint":"This string will be used to join split words into a single line if the option above is enabled"},
{"id":"","label":"Embeddings train templates directory","localized":"","hint":""},
- {"id":"","label":"Number of repeats for a single input image per epoch","localized":"","hint":"Used only for displaying epoch number"},
- {"id":"","label":"Save CSV file containing the loss to log directory","localized":"","hint":"Save CSV file containing the loss to log directory every N steps, 0 to disable"},
{"id":"","label":"Enable tensorboard logging","localized":"","hint":""},
{"id":"","label":"Save generated images within tensorboard","localized":"","hint":""},
{"id":"","label":"Tensorboard flush period","localized":"","hint":"How often, in seconds, to flush the pending Tensorboard events and summaries to disk"},
@@ -567,10 +561,8 @@
{"id":"","label":"Escape brackets in deepbooru","localized":"","hint":"Escape (\\) brackets in deepbooru so they are used as literal brackets and not for emphasis"},
{"id":"","label":"Filter out tags from deepbooru output","localized":"","hint":"Filter out those tags from deepbooru output (separated by comma)"},
{"id":"","label":"Default upscaler for image resize operations","localized":"","hint":""},
- {"id":"","label":"Tile size for ESRGAN upscalers","localized":"","hint":"0 = no tiling"},
- {"id":"","label":"Tile overlap in pixels for ESRGAN upscalers","localized":"","hint":"Low values = visible seam"},
- {"id":"","label":"Tile size for SCUNET upscalers","localized":"","hint":"0 = no tiling"},
- {"id":"","label":"Tile overlap for SCUNET upscalers","localized":"","hint":" Low values = visible seam"},
+ {"id":"","label":"Upscaler tile size","localized":"","hint":"0 = no tiling"},
+ {"id":"","label":"Upscaler tile overlap","localized":"","hint":"Low values = visible seam"},
{"id":"","label":"Do not fix prompt schedule for second order samplers","localized":"","hint":""},
{"id":"","label":"CodeFormer","localized":"","hint":""},
{"id":"","label":"GFPGAN","localized":"","hint":"Restore low quality faces using GFPGAN neural network"},
diff --git a/installer.py b/installer.py
index 36121cdba..e93ae9b01 100644
--- a/installer.py
+++ b/installer.py
@@ -410,9 +410,9 @@ def check_torch():
rocm_ver = None
if rocm_ver in {"5.7"}:
# install torch nightly via torchvision to avoid wasting bandwidth when torchvision depends on torch from yesterday
- torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --pre --index-url https://download.pytorch.org/whl/nightly/rocm{rocm_ver}')
+ torch_command = os.environ.get('TORCH_COMMAND', f'torch torchvision --pre --index-url https://download.pytorch.org/whl/nightly/rocm{rocm_ver}')
elif rocm_ver in {"5.5", "5.6"}:
- torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/nightly/rocm{rocm_ver}')
+ torch_command = os.environ.get('TORCH_COMMAND', f'torch torchvision --index-url https://download.pytorch.org/whl/nightly/rocm{rocm_ver}')
else:
# ROCm 5.5 is oldest for PyTorch 2.1
torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/rocm5.5')
@@ -431,9 +431,38 @@ def check_torch():
ipex_pip = 'https://github.com/Nuullll/intel-extension-for-pytorch/releases/download/v2.0.110%2Bxpu-master%2Bdll-bundle/intel_extension_for_pytorch-2.0.110+gitc6ea20b-cp310-cp310-win_amd64.whl'
torch_command = os.environ.get('TORCH_COMMAND', f'{pytorch_pip} {torchvision_pip} {ipex_pip}')
elif allow_openvino and args.use_openvino:
- #Remove this after 2.1.0 releases
log.info('Using OpenVINO')
- torch_command = os.environ.get('TORCH_COMMAND', '--pre torch==2.1.0.dev20230820+cpu torchvision==0.16.0.dev20230820+cpu -f https://download.pytorch.org/whl/nightly/cpu/torch_nightly.html')
+ if "linux" in sys.platform:
+ if sys.version_info[1] == 11:
+ pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp311-cp311-linux_x86_64.whl'
+ torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp311-cp311-linux_x86_64.whl'
+ elif sys.version_info[1] == 10:
+ pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp310-cp310-linux_x86_64.whl'
+ torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp310-cp310-linux_x86_64.whl'
+ elif sys.version_info[1] == 8:
+ pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp38-cp38-linux_x86_64.whl'
+ torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp38-cp38-linux_x86_64.whl'
+ else:
+ log.error('Unsupported Python version')
+ #Will error when generating an image:
+ pytorch_pip = 'torch==2.1.0'
+ torchvision_pip = 'torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cpu'
+ else:
+ if sys.version_info[1] == 11:
+ pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp311-cp311-win_amd64.whl'
+ torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp311-cp311-win_amd64.whl'
+ elif sys.version_info[1] == 10:
+ pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp310-cp310-win_amd64.whl'
+ torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp310-cp310-win_amd64.whl'
+ elif sys.version_info[1] == 8:
+ pytorch_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torch-2.1.0.dev20230820+cpu-cp38-cp38-win_amd64.whl'
+ torchvision_pip = 'https://github.com/Disty0/automatic/releases/download/openvino_pre_release_pytorch/torchvision-0.16.0.dev20230820+cpu-cp38-cp38-win_amd64.whl'
+ else:
+ log.error('Unsupported Python version')
+ #Will error when generating an image:
+ pytorch_pip = 'torch==2.1.0'
+ torchvision_pip = 'torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cpu'
+ torch_command = os.environ.get('TORCH_COMMAND', f'{pytorch_pip} {torchvision_pip}')
else:
machine = platform.machine()
if sys.platform == 'darwin':
@@ -447,7 +476,7 @@ def check_torch():
log.info('Using CPU-only Torch')
torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision')
if 'torch' in torch_command and not args.version:
- log.info('Installing torch - this may take a while')
+ # log.info('Installing torch - this may take a while')
install(torch_command, 'torch torchvision')
else:
try:
@@ -505,7 +534,7 @@ def check_torch():
if opts.get('cuda_compile_backend', '') == 'hidet':
install('hidet', 'hidet')
if args.use_openvino or opts.get('cuda_compile_backend', '') == 'openvino_fx':
- install('openvino==2023.1.0', 'openvino')
+ install('openvino==2023.2.0.dev20230922', 'openvino')
os.environ.setdefault('PYTORCH_TRACING_MODE', 'TORCHFX')
os.environ.setdefault('NEOReadDebugKeys', '1')
os.environ.setdefault('ClDeviceGlobalMemSizeAvailablePercent', '100')
@@ -757,6 +786,7 @@ def set_environment():
os.environ.setdefault('HF_HUB_DISABLE_EXPERIMENTAL_WARNING', '1')
os.environ.setdefault('UVICORN_TIMEOUT_KEEP_ALIVE', '60')
os.environ.setdefault('K_DIFFUSION_USE_COMPILE', '0')
+ os.environ.setdefault('TF_ENABLE_ONEDNN_OPTS', '0')
if sys.platform == 'darwin':
os.environ.setdefault('PYTORCH_ENABLE_MPS_FALLBACK', '1')
diff --git a/javascript/base.css b/javascript/base.css
new file mode 100644
index 000000000..86ef0f2a7
--- /dev/null
+++ b/javascript/base.css
@@ -0,0 +1,125 @@
+/* toolbutton */
+.gradio-button.tool { max-width: min-content; min-width: min-content !important; align-self: end; font-size: 1.4em; color: var(--body-text-color) !important; margin-bottom: var(--spacing-md); }
+
+/* token counters */
+.block.token-counter{ position: absolute; display: inline-block; right: 0; min-width: 0 !important; width: auto; z-index: 100; top: 0; }
+.block.token-counter span{ background: var(--input-background-fill) !important; box-shadow: 0 0 0.0 0.3em rgba(192,192,192,0.15), inset 0 0 0.6em rgba(192,192,192,0.075); border: 2px solid rgba(192,192,192,0.4) !important; }
+.block.token-counter.error span{ box-shadow: 0 0 0.0 0.3em rgba(255,0,0,0.15), inset 0 0 0.6em rgba(255,0,0,0.075); border: 2px solid rgba(255,0,0,0.4) !important; }
+.block.token-counter div{ display: inline; }
+.block.token-counter span{ padding: 0.1em 0.75em; }
+
+/* live preview */
+.progressDiv{ position: relative; height: 20px; background: #b4c0cc; margin-bottom: -3px; }
+.dark .progressDiv{ background: #424c5b; }
+.progressDiv .progress{ width: 0%; height: 20px; background: #0060df; color: white; font-weight: bold; line-height: 20px; padding: 0 8px 0 0; text-align: right; overflow: visible; white-space: nowrap; padding: 0 0.5em; }
+.livePreview { position: absolute; z-index: 50; background-color: transparent; width: -moz-available; width: -webkit-fill-available; }
+.livePreview img { position: absolute; object-fit: contain; width: 100%; height: 100%; }
+.dark .livePreview { background-color: rgb(17 24 39 / var(--tw-bg-opacity)); }
+.popup-metadata { color: white; background: #0000; display: inline-block; white-space: pre-wrap; font-size: 0.75em; }
+.global-popup{ display: flex; position: fixed; z-index: 10001; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(20, 20, 20, 0.95);}
+.global-popup-close:before { content: "×"; }
+.global-popup-close{ position: fixed; right: 0.5em; top: 0; cursor: pointer; color: white; font-size: 32pt; }
+.global-popup-inner{ display: inline-block; margin: auto; padding: 2em; }
+
+/* fullpage image viewer */
+#lightboxModal{ display: none; position: fixed; z-index: 1001; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(20, 20, 20, 0.75); backdrop-filter: blur(6px);
+ user-select: none; -webkit-user-select: none; flex-direction: row; }
+.modalControls { display: flex; justify-content: space-evenly; background-color: transparent; position: absolute; width: 99%; z-index: 1; }
+.modalControls:hover { background-color: #50505050; }
+.modalControls span { color: white; font-size: 2em; font-weight: bold; cursor: pointer; filter: grayscale(100%); }
+.modalControls span:hover, .modalControls span:focus { color: var(--highlight-color); filter: none; }
+.lightboxModalPreviewZone { display: flex; width: 100%; height: 100%; }
+.lightboxModalPreviewZone:focus-visible { outline: none; }
+.lightboxModalPreviewZone > img { display: block; margin: auto; width: auto; }
+.lightboxModalPreviewZone > img.modalImageFullscreen{ object-fit: contain; height: 100%; width: 100%; min-height: 0; background: transparent; }
+table.settings-value-table { background: white; border-collapse: collapse; margin: 1em; border: var(--spacing-sm) solid white; }
+table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-width: 36em; }
+.modalPrev, .modalNext { cursor: pointer; position: relative; z-index: 1; top: 0; width: auto; height: 100vh; line-height: 100vh; text-align: center; padding: 16px;
+ margin-top: -50px; color: white; font-weight: bold; font-size: 20px; transition: 0.6s ease; user-select: none; -webkit-user-select: none; }
+.modalNext { right: 0; }
+.modalPrev:hover, .modalNext:hover { background-color: rgba(0, 0, 0, 0.8); }
+#imageARPreview { position: absolute; top: 0px; left: 0px; border: 2px solid red; background: rgba(255, 0, 0, 0.3); z-index: 900; pointer-events: none; display: none; }
+
+/* context menu (ie for the generate button) */
+#context-menu { z-index: 9999; position: absolute; display: block; padding: var(--spacing-md); border: 2px solid var(--highlight-color); background: var(--background-fill-primary); color: var(--body-text-color); }
+.context-menu-items { list-style: none; margin: 0; padding: 0; }
+.context-menu-items a { display: block; padding: var(--spacing-md); cursor: pointer; font-weight: normal; }
+.context-menu-items a:hover { background: var(--highlight-color) }
+
+/* log monitor */
+.log-monitor { display: none; justify-content: unset !important; overflow: hidden; padding: 0; margin-top: auto; font-family: monospace; font-size: 0.85em; }
+.log-monitor td, .log-monitor th { padding-left: 1em; }
+
+/* changelog */
+.md h2 { background-color: var(--background-fill-primary); padding: 0.5em; }
+.md ul { list-style-type: square !important; text-indent: 1em; margin-left: 4em; }
+.md li { list-style-position: outside !important; text-indent: 0; }
+.md p { margin-left: 2em; }
+
+/* extensions */
+#tab_extensions table, #tab_config table{ border-collapse: collapse; }
+#tab_extensions table td, #tab_extensions table th, #tab_config table td, #tab_config table th { border: 1px solid #ccc; padding: 0.25em 0.5em; }
+#tab_extensions table input[type="checkbox"] { margin-right: 0.5em; appearance: checkbox; }
+#tab_extensions button{ max-width: 16em; }
+#tab_extensions input[disabled="disabled"]{ opacity: 0.5; }
+.extension-tag{ font-weight: bold; font-size: 95%; }
+.extension-button { font-size: 95% !important; width: 6em; }
+#extensions .name{ font-size: 1.1rem }
+#extensions .type{ opacity: 0.5; font-size: 90%; text-align: center; }
+#extensions .version{ opacity: 0.7; }
+#extensions .info{ margin: 0; }
+#extensions .date{ opacity: 0.85; font-size: 90%; }
+
+/* extra networks */
+.extra-networks > div { margin: 0; gap: 0.2em; border-bottom: none !important; }
+.extra-networks .second-line { display: flex; width: -moz-available; width: -webkit-fill-available; gap: 0.3em; box-shadow: var(--input-shadow); }
+.extra-networks .search { flex: 1; }
+.extra-networks .description { flex: 3; }
+.extra-networks .tab-nav > button { margin-right: 0; height: 24px; padding: 2px 4px 2px 4px; }
+.extra-networks .buttons { position: absolute; right: 0; margin: -4px; background: var(--background-color); }
+.extra-networks .buttons>button { height: 1.2em; margin-top: var(--spacing-md); }
+.extra-networks .custom-button { width: 120px; width: 100%; background: none; justify-content: left; text-align: left; padding: 2px 8px 2px 16px; text-indent: -8px; box-shadow: none; line-break: auto; }
+.extra-networks .custom-button:hover { background: var(--button-primary-background-fill) }
+.extra-networks-tab { padding: 0 !important; }
+.extra-network-subdirs { background: var(--input-background-fill); overflow-x: hidden; overflow-y: auto; min-width: max(15%, 120px); padding-top: 0.5em; margin-top: -4px !important; }
+.extra-networks-page { display: flex }
+.extra-network-cards { display: flex; flex-wrap: wrap; overflow-y: auto; overflow-x: hidden; align-content: flex-start; width: -moz-available; width: -webkit-fill-available; }
+.extra-network-cards .card { height: fit-content; margin: 0 0 0.5em 0.5em; position: relative; scroll-snap-align: start; scroll-margin-top: 0; }
+.extra-network-cards .card .overlay { position: absolute; bottom: 0; padding: 0.2em; z-index: 10; width: 100%; background: none; }
+.extra-network-cards .card .overlay .name { font-size: 1.1em; font-weight: bold; text-shadow: 1px 1px black; color: white; overflow-wrap: break-word; }
+.extra-network-cards .card .preview { box-shadow: var(--button-shadow); min-height: 30px; }
+.extra-network-cards .card:hover .overlay { background: rgba(0, 0, 0, 0.40); }
+.extra-network-cards .card:hover .preview { box-shadow: none; filter: grayscale(100%); }
+.extra-network-cards .card:hover .overlay { background: rgba(0, 0, 0, 0.40); }
+.extra-network-cards .card .overlay .tags { margin: 4px; display: none; overflow-wrap: break-word; }
+.extra-network-cards .card .overlay .tag { padding: 2px; margin: 2px; background: var(--neutral-700); cursor: pointer; display: inline-block; }
+.extra-network-cards .card .actions > span { padding: 4px; }
+.extra-network-cards .card:hover .actions { display: block; }
+.extra-network-cards .card:hover .overlay .tags { display: block; }
+.extra-network-cards .card .actions { font-size: 3em; display: none; text-align-last: right; cursor: pointer; font-variant: unicase; position: absolute; z-index: 100; right: 0; height: 0.7em; width: 100%; background: rgba(0, 0, 0, 0.40); }
+#txt2img_description, #img2img_description { max-height: 63px; overflow-y: auto !important; }
+#txt2img_description > label > textarea, #img2img_description > label > textarea { font-size: 0.9em }
+
+#txt2img_extra_details > div, #img2img_extra_details > div { overflow-y: auto; min-height: 40vh; max-height: 80vh; align-self: flex-start; }
+#txt2img_extra_details, #img2img_extra_details { position: fixed; bottom: 50%; left: 50%; transform: translate(-50%, 50%); padding: 0.8em; border: var(--block-border-width) solid var(--highlight-color) !important;
+ z-index: 100; box-shadow: var(--button-shadow); }
+#txt2img_extra_details td:first-child, #img2img_extra_details td:first-child { font-weight: bold; vertical-align: top; }
+#txt2img_extra_details .gradio-image, #img2img_extra_details .gradio-image { max-height: 70vh; }
+
+/* custom component */
+.folder-selector textarea { height: 2em !important; padding: 6px !important; }
+.nvml { position: fixed; bottom: 10px; right: 10px; background: var(--background-fill-primary); border: 1px solid var(--button-primary-border-color); padding: 6px; color: var(--button-primary-text-color);
+ font-size: 0.7em; z-index: 50; font-family: monospace; display: none; }
+
+/* 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; }
+.splash-img { margin: 10% auto 0 auto; width: 512px; background-repeat: no-repeat; height: 512px; animation: color 10s infinite alternate; }
+.loading { color: white; position: absolute; top: 20%; left: 50%; transform: translateX(-50%); }
+.loader { width: 300px; height: 300px; border: var(--spacing-md) solid transparent; border-radius: 50%; border-top: var(--spacing-md) solid var(--primary-600); animation: spin 4s linear infinite; position: relative; }
+.loader::before, .loader::after { content: ""; position: absolute; top: 6px; bottom: 6px; left: 6px; right: 6px; border-radius: 50%; border: var(--spacing-md) solid transparent; }
+.loader::before { border-top-color: var(--primary-900); animation: 3s spin linear infinite; }
+.loader::after { border-top-color: var(--primary-300); animation: spin 1.5s linear infinite; }
+@keyframes move { from { background-position-x: 0, -40px; } to { background-position-x: 0, 40px; } }
+@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
+@keyframes color { from { filter: hue-rotate(0deg) } to { filter: hue-rotate(360deg) } }
diff --git a/javascript/style.css b/javascript/sdnext.css
similarity index 98%
rename from javascript/style.css
rename to javascript/sdnext.css
index 217796950..fb6a198f3 100644
--- a/javascript/style.css
+++ b/javascript/sdnext.css
@@ -1,4 +1,4 @@
-:root { --checkbox-label-gap: 0.25em 0.1em; --section-header-text-size: 12pt; --block-background-fill: transparent;}
+:root { --left-column: 490px; }
a { font-weight: bold; cursor: pointer; }
h2 { margin-top: 1em !important; font-size: 1.4em !important; }
footer { display: none; }
diff --git a/javascript/setHints.js b/javascript/setHints.js
index 1ce221723..726d83dfa 100644
--- a/javascript/setHints.js
+++ b/javascript/setHints.js
@@ -30,20 +30,15 @@ async function tooltipHide(e) {
async function validateHints(elements, data) {
let original = elements.map((e) => e.textContent.toLowerCase().trim()).sort((a, b) => a > b);
- original = [...new Set(original)];
- log('all hints:', original);
- log('hints-differences', { elements: original.length, hints: data.length });
+ original = [...new Set(original)]; // remove duplicates
const current = data.map((e) => e.label.toLowerCase().trim()).sort((a, b) => a > b);
- let missing = [];
- for (let i = 0; i < original.length; i++) {
- if (!current.includes(original[i])) missing.push(original[i]);
- }
- log('missing in locale:', missing);
- missing = [];
- for (let i = 0; i < current.length; i++) {
- if (!original.includes(current[i])) missing.push(current[i]);
- }
- log('in locale but not ui:', missing);
+ log('all elements:', original);
+ log('all hints:', current);
+ log('hints-differences', { elements: original.length, hints: current.length });
+ const missingLocale = original.filter((e) => !current.includes(e));
+ log('missing in locale:', missingLocale);
+ const missingUI = current.filter((e) => !original.includes(e));
+ log('in locale but not ui:', missingUI);
}
async function setHints() {
diff --git a/launch.py b/launch.py
index d5fe9a7d1..b725961f9 100644
--- a/launch.py
+++ b/launch.py
@@ -199,7 +199,7 @@ if __name__ == "__main__":
installer.install_repositories()
installer.install_submodules()
installer.install_extensions()
- installer.install_packages() # redo packages since extensions may change them
+ installer.install_requirements() # redo requirements since extensions may change them
installer.update_wiki()
if installer.errors == 0:
installer.log.debug(f'Setup complete without errors: {round(time.time())}')
diff --git a/modules/api/api.py b/modules/api/api.py
index 163e11881..6cdb362d5 100644
--- a/modules/api/api.py
+++ b/modules/api/api.py
@@ -182,7 +182,8 @@ class Api:
if shared.opts.motd:
res = requests.get('https://vladmandic.github.io/automatic/motd', timeout=10)
if res.status_code == 200:
- shared.log.info(f'MOTD: {res.text}')
+ msg = (res.text or '').strip()
+ shared.log.info(f'MOTD: {msg if len(msg) > 0 else "N/A"}')
motd += res.text
return motd
diff --git a/modules/cmd_args.py b/modules/cmd_args.py
index 6459204d1..ef2074f1e 100644
--- a/modules/cmd_args.py
+++ b/modules/cmd_args.py
@@ -94,7 +94,7 @@ def compatibility_args(opts, args):
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, default=opts.lyco_patch_lora)
+ group.add_argument("--lyco-patch-lora", help=argparse.SUPPRESS, 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)
@@ -114,7 +114,7 @@ def compatibility_args(opts, args):
opts.sd_vae_as_default = True
opts.enable_emphasis = True
opts.enable_batch_seeds = True
- opts.multiple_tqdm = False
+ # opts.multiple_tqdm = False
opts.print_hypernet_extra = False
opts.dimensions_and_batch_together = True
opts.enable_pnginfo = True
diff --git a/modules/images.py b/modules/images.py
index 299eaa4d9..4b0d198a2 100644
--- a/modules/images.py
+++ b/modules/images.py
@@ -294,8 +294,8 @@ class FilenameGenerator:
'job_timestamp': lambda self: getattr(self.p, "job_timestamp", shared.state.job_timestamp),
'model': lambda self: shared.sd_model.sd_checkpoint_info.title,
- 'model_shortname': lambda self: shared.sd_model.sd_checkpoint_info.name,
- 'model_name': lambda self: shared.sd_model.sd_checkpoint_info.name,
+ 'model_shortname': lambda self: shared.sd_model.sd_checkpoint_info.model_name,
+ 'model_name': lambda self: shared.sd_model.sd_checkpoint_info.model_name,
'model_hash': lambda self: shared.sd_model.sd_checkpoint_info.shorthash,
'prompt': lambda self: self.prompt,
@@ -351,7 +351,7 @@ class FilenameGenerator:
return shorthash
def prompt_words(self):
- if self.p is None or self.prompt is None:
+ if self.prompt is None:
return ''
no_attention = re_attention.sub(r'\1', self.prompt)
no_network = re_network.sub(r'\1', no_attention)
diff --git a/modules/intel/openvino/__init__.py b/modules/intel/openvino/__init__.py
index 61bb32921..b4294f9ee 100644
--- a/modules/intel/openvino/__init__.py
+++ b/modules/intel/openvino/__init__.py
@@ -8,6 +8,7 @@ from openvino.runtime import Core, Type, PartialShape, serialize
from torch._dynamo.backends.common import fake_tensor_unsupported
from torch._dynamo.backends.registry import register_backend
from torch.fx.experimental.proxy_tensor import make_fx
+from torch.fx import GraphModule
from torch.utils._pytree import tree_flatten
from types import MappingProxyType
from hashlib import sha256
@@ -132,7 +133,7 @@ def cached_model_name(model_hash_str, device, args, cache_root, reversed = False
return file_name
-def check_fully_supported(self, graph_module):
+def check_fully_supported(self, graph_module: GraphModule) -> bool:
num_fused = 0
for node in graph_module.graph.nodes:
if node.op == "call_module" and "fused_" in node.name:
@@ -178,7 +179,7 @@ def openvino_clear_caches():
compiled_cache.clear()
partitioned_modules.clear()
-def openvino_compile(gm, *args, model_hash_str: str = None, file_name=""):
+def openvino_compile(gm: GraphModule, *args, model_hash_str: str = None, file_name=""):
core = Core()
device = get_device()
@@ -259,7 +260,7 @@ def openvino_compile_cached_model(cached_model_path, *example_inputs):
return compiled_model
-def openvino_execute(gm, *args, executor_parameters=None, partition_id, file_name=""):
+def openvino_execute(gm: GraphModule, *args, executor_parameters=None, partition_id, file_name=""):
executor_parameters = executor_parameters or DEFAULT_OPENVINO_PYTHON_CONFIG
use_cache = executor_parameters.get(
@@ -292,7 +293,7 @@ def openvino_execute(gm, *args, executor_parameters=None, partition_id, file_nam
return results1[0]
return results1
-def openvino_execute_partitioned(gm, *args, executor_parameters=None, file_name=""):
+def openvino_execute_partitioned(gm: GraphModule, *args, executor_parameters=None, file_name=""):
executor_parameters = executor_parameters or DEFAULT_OPENVINO_PYTHON_CONFIG
global partitioned_modules
@@ -316,7 +317,7 @@ def openvino_execute_partitioned(gm, *args, executor_parameters=None, file_name=
return partitioned_modules[signature](*args)
-def partition_graph(gm, use_python_fusion_cache: bool, model_hash_str: str = None, file_name=""):
+def partition_graph(gm: GraphModule, use_python_fusion_cache: bool, model_hash_str: str = None, file_name=""):
global max_openvino_partitions
for node in gm.graph.nodes:
if node.op == "call_module" and "fused_" in node.name:
diff --git a/modules/loader.py b/modules/loader.py
index c0cc8dea3..6353ee1bb 100644
--- a/modules/loader.py
+++ b/modules/loader.py
@@ -9,7 +9,11 @@ initialized = False
logging.getLogger("DeepSpeed").disabled = True
# os.environ.setdefault('OMP_NUM_THREADS', 1)
# os.environ.setdefault('MKL_NUM_THREADS', 1)
+
+# import tensorflow as tf # pylint: disable=C0411
+
import torch # pylint: disable=C0411
+
# torch.set_num_threads(1)
try:
import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import
@@ -19,14 +23,14 @@ except Exception:
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
import torchvision # pylint: disable=W0611,C0411
import pytorch_lightning # pytorch_lightning should be imported after torch, but it re-enables warnings on import so import once to disable them # pylint: disable=W0611,C0411
-if ".dev" in torch.__version__ or "+git" in torch.__version__:
- torch.__long_version__ = torch.__version__
- torch.__version__ = re.search(r'[\d.]+[\d]', torch.__version__).group(0)
logging.getLogger("xformers").addFilter(lambda record: 'A matching Triton is not available' not in record.getMessage())
logging.getLogger("pytorch_lightning").disabled = True
warnings.filterwarnings(action="ignore", category=DeprecationWarning)
warnings.filterwarnings(action="ignore", category=FutureWarning)
warnings.filterwarnings(action="ignore", category=UserWarning, module="torchvision")
+if ".dev" in torch.__version__ or "+git" in torch.__version__:
+ torch.__long_version__ = torch.__version__
+ torch.__version__ = re.search(r'[\d.]+[\d]', torch.__version__).group(0)
timer.startup.record("torch")
from fastapi import FastAPI # pylint: disable=W0611,C0411
diff --git a/modules/paths.py b/modules/paths.py
index 6baed946c..0fd7b87b5 100644
--- a/modules/paths.py
+++ b/modules/paths.py
@@ -1,17 +1,18 @@
import os
import sys
-import modules.paths_internal
+from modules import paths_internal, errors
-data_path = modules.paths_internal.data_path
-script_path = modules.paths_internal.script_path
-models_path = modules.paths_internal.models_path
-sd_configs_path = modules.paths_internal.sd_configs_path
-sd_default_config = modules.paths_internal.sd_default_config
-sd_model_file = modules.paths_internal.sd_model_file
-default_sd_model_file = modules.paths_internal.default_sd_model_file
-extensions_dir = modules.paths_internal.extensions_dir
-extensions_builtin_dir = modules.paths_internal.extensions_builtin_dir
+debug = errors.log.info if os.environ.get('SD_PATH_DEBUG', None) is not None else lambda *args, **kwargs: None
+data_path = paths_internal.data_path
+script_path = paths_internal.script_path
+models_path = paths_internal.models_path
+sd_configs_path = paths_internal.sd_configs_path
+sd_default_config = paths_internal.sd_default_config
+sd_model_file = paths_internal.sd_model_file
+default_sd_model_file = paths_internal.default_sd_model_file
+extensions_dir = paths_internal.extensions_dir
+extensions_builtin_dir = paths_internal.extensions_builtin_dir
# data_path = cmd_opts_pre.data
sys.path.insert(0, script_path)
@@ -39,14 +40,14 @@ paths = {}
for d, must_exist, what, _options in path_dirs:
must_exist_path = os.path.abspath(os.path.join(script_path, d, must_exist))
if not os.path.exists(must_exist_path):
- print(f"Warning: {what} not found at path {must_exist_path}", file=sys.stderr)
+ errors.log.error(f'Required path not found: path={must_exist_path} item={what}')
else:
d = os.path.abspath(d)
sys.path.append(d)
paths[what] = d
-def create_paths(opts, log=None):
+def create_paths(opts):
def create_path(folder):
if folder is None or folder == '':
return
@@ -54,26 +55,22 @@ def create_paths(opts, log=None):
return
try:
os.makedirs(folder, exist_ok=True)
- if log is not None:
- log.debug(f'Create folder={folder}')
+ errors.log.info(f'Create folder={folder}')
except Exception as e:
- if log is not None:
- log.error(f'Create Failed folder={folder} {e}')
+ errors.log.error(f'Create Failed folder={folder} {e}')
def fix_path(folder):
tgt = opts.data.get(folder, None) or opts.data_labels[folder].default
if tgt is None or tgt == '':
return tgt
- if os.path.isabs(tgt):
- return tgt
- if len(data_path) > 0 and tgt.startswith(data_path): # path is already relative to data_path
- return tgt
- else:
- tgt = os.path.join(data_path, tgt)
- if os.path.isabs(tgt):
- return tgt
- tgt = os.path.relpath(tgt, script_path)
- opts.data[folder] = tgt
+ fix = tgt
+ if not os.path.isabs(tgt) and len(data_path) > 0 and not tgt.startswith(data_path): # path is already relative to data_path
+ fix = os.path.join(data_path, fix)
+ if fix.startswith('..'):
+ fix = os.path.abspath(fix)
+ fix = fix if os.path.isabs(fix) else os.path.relpath(fix, script_path)
+ opts.data[folder] = fix
+ debug(f'Paths: folder={folder} original="{tgt}" target="{fix}"')
return opts.data[folder]
create_path(data_path)
@@ -83,11 +80,12 @@ def create_paths(opts, log=None):
create_path(extensions_dir)
create_path(extensions_builtin_dir)
create_path(fix_path('temp_dir'))
- create_path(fix_path('hypernetwork_dir'))
create_path(fix_path('ckpt_dir'))
- create_path(fix_path('vae_dir'))
create_path(fix_path('diffusers_dir'))
+ create_path(fix_path('vae_dir'))
+ create_path(fix_path('lora_dir'))
create_path(fix_path('embeddings_dir'))
+ create_path(fix_path('hypernetwork_dir'))
create_path(fix_path('outdir_samples'))
create_path(fix_path('outdir_txt2img_samples'))
create_path(fix_path('outdir_img2img_samples'))
diff --git a/modules/postprocess/codeformer_model.py b/modules/postprocess/codeformer_model.py
index e11747018..3f959b6b8 100644
--- a/modules/postprocess/codeformer_model.py
+++ b/modules/postprocess/codeformer_model.py
@@ -1,9 +1,6 @@
import os
-import sys
-
import cv2
import torch
-
import modules.face_restoration
from modules import shared, devices, modelloader, errors
from modules.paths import models_path
@@ -88,7 +85,7 @@ def setup_model(dirname):
cropped_face_t = cropped_face_t.unsqueeze(0).to(devices.device_codeformer)
try:
with devices.inference_context():
- output = self.net(cropped_face_t, w=w if w is not None else shared.opts.code_former_weight, adain=True)[0]
+ output = self.net(cropped_face_t, w=w if w is not None else shared.opts.code_former_weight, adain=True)[0] # pylint: disable=not-callable
restored_face = tensor2img(output, rgb2bgr=True, min_max=(-1, 1))
del output
devices.torch_gc()
diff --git a/modules/processing.py b/modules/processing.py
index aa0bfafc8..0b3e461da 100644
--- a/modules/processing.py
+++ b/modules/processing.py
@@ -163,6 +163,7 @@ class StableDiffusionProcessing:
self.refiner_steps = 5
self.refiner_start = 0
self.ops = []
+ self.resize_mode: int = 0
self.ddim_discretize = shared.opts.ddim_discretize
self.s_min_uncond = shared.opts.s_min_uncond
self.s_churn = shared.opts.s_churn
@@ -171,11 +172,15 @@ class StableDiffusionProcessing:
self.s_max = shared.opts.s_max
self.s_tmin = shared.opts.s_tmin
self.s_tmax = float('inf') # not representable as a standard ui option
- self.refiner_switch_at = 0 # a1111 compatibility item
+ shared.opts.data['clip_skip'] = clip_skip
+ # TODO a1111 compatibility items
+ self.refiner_switch_at = 0
+ self.hr_prompt = ''
+ self.all_hr_prompts = []
+ self.hr_negative_prompt = ''
+ self.all_hr_negative_prompts = []
self.comments = {}
self.is_api = False
- self.resize_mode: int = 0
- shared.opts.data['clip_skip'] = clip_skip
@property
def sd_model(self):
@@ -1180,6 +1185,8 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
crop_region = None
image_mask = self.image_mask
if image_mask is not None:
+ if type(image_mask) == list:
+ image_mask = image_mask[0]
image_mask = image_mask.convert('L')
if self.inpainting_mask_invert:
image_mask = ImageOps.invert(image_mask)
diff --git a/modules/sd_hijack_freeu.py b/modules/sd_hijack_freeu.py
index 4d21601d4..ef893d2f3 100644
--- a/modules/sd_hijack_freeu.py
+++ b/modules/sd_hijack_freeu.py
@@ -1,7 +1,7 @@
import math
import functools
import torch
-from modules.shared import state, log, opts
+from modules import shared
from modules.sd_hijack_unet import th
# based on
@@ -23,7 +23,7 @@ cat_original = None
def to_denoising_step(number, steps=None) -> int:
if steps is None:
- steps = state.sampling_steps
+ steps = shared.state.sampling_steps
if isinstance(number, float):
return int(number * steps)
return number
@@ -34,11 +34,11 @@ def get_schedule_ratio():
stop_step = to_denoising_step(stop_ratio)
if start_step == stop_step:
smooth_schedule_ratio = 0.0
- elif state.sampling_step < start_step:
- smooth_schedule_ratio = min(1.0, max(0.0, state.sampling_step / start_step))
+ elif shared.state.sampling_step < start_step:
+ smooth_schedule_ratio = min(1.0, max(0.0, shared.state.sampling_step / start_step))
else:
- smooth_schedule_ratio = min(1.0, max(0.0, 1 + (state.sampling_step - start_step) / (start_step - stop_step)))
- flat_schedule_ratio = 1.0 if start_step <= state.sampling_step < stop_step else 0.0
+ smooth_schedule_ratio = min(1.0, max(0.0, 1 + (shared.state.sampling_step - start_step) / (start_step - stop_step)))
+ flat_schedule_ratio = 1.0 if start_step <= shared.state.sampling_step < stop_step else 0.0
return lerp(flat_schedule_ratio, smooth_schedule_ratio, transition_smoothness)
@@ -47,7 +47,7 @@ def lerp(a, b, r):
def free_u_cat_hijack(hs, *args, original_function, **kwargs):
- if not opts.freeu_enabled:
+ if not shared.opts.freeu_enabled:
return original_function(hs, *args, **kwargs)
schedule_ratio = get_schedule_ratio()
if schedule_ratio == 0:
@@ -67,8 +67,8 @@ def free_u_cat_hijack(hs, *args, original_function, **kwargs):
mask = (region_begin <= mask) & (mask <= region_end)
if region_inverted:
mask = ~mask
- backbone_factor = opts.freeu_b1 if index == 0 else opts.freeu_b2
- skip_factor = opts.freeu_s1 if index == 0 else opts.freeu_s2
+ backbone_factor = shared.opts.freeu_b1 if index == 0 else shared.opts.freeu_b2
+ skip_factor = shared.opts.freeu_s1 if index == 0 else shared.opts.freeu_s2
h[:, mask] *= lerp(1, backbone_factor, schedule_ratio)
h_skip = filter_skip(h_skip, threshold=skip_cutoff, scale=lerp(1, skip_factor, schedule_ratio), scale_high=lerp(1, skip_high_end_factor, schedule_ratio))
return original_function([h, h_skip], *args, **kwargs)
@@ -130,8 +130,8 @@ def apply_freeu(p, backend_original):
global state_enabled # pylint: disable=global-statement
global cat_original # pylint: disable=global-statement
if backend_original:
- if opts.freeu_enabled:
- p.extra_generation_params['FreeU'] = f'b1={opts.freeu_b1} b2={opts.freeu_b2} s1={opts.freeu_s1} s2={opts.freeu_s2}'
+ if shared.opts.freeu_enabled:
+ p.extra_generation_params['FreeU'] = f'b1={shared.opts.freeu_b1} b2={shared.opts.freeu_b2} s1={shared.opts.freeu_s1} s2={shared.opts.freeu_s2}'
if not state_enabled: # otherwise already patched
cat_original = th.cat
th.cat = functools.partial(free_u_cat_hijack, original_function=th.cat)
@@ -141,12 +141,12 @@ def apply_freeu(p, backend_original):
th.cat = cat_original
state_enabled = False
elif hasattr(p.sd_model, 'enable_freeu'):
- if opts.freeu_enabled:
- p.extra_generation_params['FreeU'] = f'b1={opts.freeu_b1} b2={opts.freeu_b2} s1={opts.freeu_s1} s2={opts.freeu_s2}'
- p.sd_model.enable_freeu(s1=opts.freeu_s1, s2=opts.freeu_s2, b1=opts.freeu_b1, b2=opts.freeu_b2)
+ if shared.opts.freeu_enabled:
+ p.extra_generation_params['FreeU'] = f'b1={shared.opts.freeu_b1} b2={shared.opts.freeu_b2} s1={shared.opts.freeu_s1} s2={shared.opts.freeu_s2}'
+ p.sd_model.enable_freeu(s1=shared.opts.freeu_s1, s2=shared.opts.freeu_s2, b1=shared.opts.freeu_b1, b2=shared.opts.freeu_b2)
state_enabled = True
elif state_enabled:
p.sd_model.disable_freeu()
state_enabled = False
- if opts.freeu_enabled:
- log.info(f'Applying free-u: b1={opts.freeu_b1} b2={opts.freeu_b2} s1={opts.freeu_s1} s2={opts.freeu_s2}')
+ if shared.opts.freeu_enabled:
+ shared.log.info(f'Applying free-u: b1={shared.opts.freeu_b1} b2={shared.opts.freeu_b2} s1={shared.opts.freeu_s1} s2={shared.opts.freeu_s2}')
diff --git a/modules/sd_models.py b/modules/sd_models.py
index 6aad35ea0..ff95ee7a8 100644
--- a/modules/sd_models.py
+++ b/modules/sd_models.py
@@ -50,21 +50,29 @@ class CheckpointInfo:
self.hash = None
self.filename = filename
self.type = ''
- filename = os.path.abspath(filename)
relname = filename
- if relname.startswith(script_path):
+ app_path = os.path.abspath(script_path)
+
+ def rel(fn, path):
try:
- relname = os.path.relpath(filename, script_path)
- except:
- pass
- try:
- relname = os.path.relpath(filename, model_path)
- except:
- pass
- try:
- relname = os.path.relpath(filename, shared.cmd_opts.ckpt_dir)
- except:
- pass
+ return os.path.relpath(fn, path)
+ except Exception:
+ return fn
+
+ if relname.startswith('..'):
+ relname = os.path.abspath(relname)
+ if relname.startswith(shared.opts.ckpt_dir):
+ relname = rel(filename, shared.opts.ckpt_dir)
+ elif relname.startswith(shared.opts.diffusers_dir):
+ relname = rel(filename, shared.opts.diffusers_dir)
+ elif relname.startswith(model_path):
+ relname = rel(filename, model_path)
+ elif relname.startswith(script_path):
+ relname = rel(filename, script_path)
+ elif relname.startswith(app_path):
+ relname = rel(filename, app_path)
+ else:
+ relname = os.path.abspath(relname)
relname, ext = os.path.splitext(relname)
ext = ext.lower()[1:]
@@ -87,9 +95,6 @@ class CheckpointInfo:
self.sha256 = repo[0]['hash']
self.type = 'diffusers'
- # info = shared.readfile(self.filename, silent=True)
- # if 'tags' in info:
- # self.tags = info['tags']
self.shorthash = self.sha256[0:10] if self.sha256 else None
self.title = self.name if self.shorthash is None else f'{self.name} [{self.shorthash}]'
self.path = self.filename
@@ -264,7 +269,8 @@ def select_checkpoint(op='model'):
return checkpoint_info
if len(checkpoints_list) == 0 and not shared.cmd_opts.no_download:
shared.log.error("Cannot generate without a checkpoint")
- shared.log.error("Use --ckpt to force using existing checkpoint")
+ shared.log.info("Set system paths to use existing folders in a different location")
+ shared.log.info("Or use --ckpt to force using existing checkpoint")
return None
checkpoint_info = next(iter(checkpoints_list.values()))
if model_checkpoint is not None:
@@ -705,6 +711,9 @@ def compile_diffusers(sd_model):
def set_diffuser_options(sd_model, vae, op: str):
+ if sd_model is None:
+ shared.log.warning(f'{op} is not loaded')
+ return
if (shared.opts.diffusers_model_cpu_offload or shared.cmd_opts.medvram) and (shared.opts.diffusers_seq_cpu_offload or shared.cmd_opts.lowvram):
shared.log.warning(f'Setting {op}: Model CPU offload and Sequential CPU offload are not compatible')
shared.log.debug(f'Setting {op}: disabling model CPU offload')
diff --git a/modules/sd_samplers_diffusers.py b/modules/sd_samplers_diffusers.py
index 6dfd2c73c..e7067c1fd 100644
--- a/modules/sd_samplers_diffusers.py
+++ b/modules/sd_samplers_diffusers.py
@@ -29,8 +29,8 @@ config = {
'DDIM': { 'clip_sample': True, 'set_alpha_to_one': True, 'steps_offset': 0, 'clip_sample_range': 1.0, 'sample_max_value': 1.0, 'timestep_spacing': 'linspace', 'rescale_betas_zero_snr': False },
'DDPM': { 'variance_type': "fixed_small", 'clip_sample': True, 'thresholding': False, 'clip_sample_range': 1.0, 'sample_max_value': 1.0, 'timestep_spacing': 'linspace'},
'DEIS': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "deis", 'solver_type': "logrho", 'lower_order_final': True },
- 'DPM 1S++': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False },
- 'DPM 2M++': { 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False },
+ 'DPM++ 1S': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False },
+ 'DPM++ 2M': { 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False },
'DPM SDE': { 'use_karras_sigmas': False },
'Euler a': { },
'Euler': { 'interpolation_type': "linear", 'use_karras_sigmas': False },
@@ -66,9 +66,10 @@ class DiffusionSampler:
return
self.name = name
self.config = {}
- self.config = config['All'].copy() # apply global defaults
if not hasattr(model, 'scheduler'):
return
+ for key, value in config.get('All', {}).items(): # apply global defaults
+ self.config[key] = value
for key, value in config.get(name, {}).items(): # apply diffusers per-scheduler defaults
self.config[key] = value
if hasattr(model.scheduler, 'scheduler_config'): # find model defaults
diff --git a/modules/sd_vae_approx.py b/modules/sd_vae_approx.py
index f5c577458..3e4b93ddd 100644
--- a/modules/sd_vae_approx.py
+++ b/modules/sd_vae_approx.py
@@ -5,8 +5,6 @@ from modules import devices, paths, shared
sd_vae_approx_model = None
-simple_weights = None
-simple_bias = None
class VAEApprox(nn.Module):
@@ -58,24 +56,22 @@ def nn_approximation(sample): # Approximate NN
def cheap_approximation(sample): # Approximate simple
# https://discuss.huggingface.co/t/decoding-latents-to-rgb-without-upscaling/23204/2
- global simple_weights, simple_bias # pylint: disable=global-statement
- if simple_weights is None or simple_bias is None:
- if shared.sd_model_type == "sdxl":
- simple_weights = torch.tensor([
- [0.4543,-0.2868, 0.1566,-0.4748],
- [0.5008, 0.0952, 0.2155,-0.3268],
- [0.5294, 0.1625,-0.0624,-0.3793]
- ]).reshape(3, 4, 1, 1).to(sample.device)
- simple_bias = torch.tensor([0.1375, 0.0144, -0.0675]).to(sample.device)
- else:
- simple_weights = torch.tensor([
- [0.298, 0.187,-0.158,-0.184],
- [0.207, 0.286, 0.189,-0.271],
- [0.208, 0.173, 0.264,-0.473],
- ]).reshape(3, 4, 1, 1).to(sample.device)
- simple_bias = None
+ if shared.sd_model_type == "sdxl":
+ simple_weights = torch.tensor([
+ [0.4543,-0.2868, 0.1566,-0.4748],
+ [0.5008, 0.0952, 0.2155,-0.3268],
+ [0.5294, 0.1625,-0.0624,-0.3793]
+ ]).reshape(3, 4, 1, 1)
+ simple_bias = torch.tensor([0.1375, 0.0144, -0.0675])
+ else:
+ simple_weights = torch.tensor([
+ [0.298, 0.187,-0.158,-0.184],
+ [0.207, 0.286, 0.189,-0.271],
+ [0.208, 0.173, 0.264,-0.473],
+ ]).reshape(3, 4, 1, 1)
+ simple_bias = None
try:
- x_sample = nn.functional.conv2d(sample, simple_weights, simple_bias) # pylint: disable=not-callable
+ x_sample = nn.functional.conv2d(sample, simple_weights.to(sample.device, sample.dtype), simple_bias.to(sample.device, sample.dtype)) # pylint: disable=not-callable
return x_sample
except Exception as e:
shared.log.error(f'Decode simple: {e}')
diff --git a/modules/shared.py b/modules/shared.py
index 0b2d3f41c..9c0b8058e 100644
--- a/modules/shared.py
+++ b/modules/shared.py
@@ -4,7 +4,6 @@ import sys
import time
import json
import contextlib
-import urllib.request
from types import SimpleNamespace
from urllib.parse import urlparse
from enum import Enum
@@ -12,7 +11,7 @@ import requests
import gradio as gr
import fasteners
from rich.console import Console
-from modules import errors, shared_items, shared_state, cmd_args, ui_components
+from modules import errors, shared_items, shared_state, cmd_args, ui_components, theme
from modules.paths_internal import models_path, script_path, data_path, sd_configs_path, sd_default_config, sd_model_file, default_sd_model_file, extensions_dir, extensions_builtin_dir # pylint: disable=W0611
from modules.dml import memory_providers, default_memory_provider, directml_do_hijack
import modules.interrogate
@@ -42,7 +41,6 @@ extra_networks = []
options_templates = {}
hypernetworks = {}
loaded_hypernetworks = []
-gradio_theme = gr.themes.Base()
settings_components = None
latent_upscale_default_mode = "None"
latent_upscale_modes = {
@@ -162,7 +160,7 @@ def list_samplers():
def temp_disable_extensions():
disabled = []
if cmd_opts.safe:
- for ext in ['sd-webui-controlnet', 'multidiffusion-upscaler-for-automatic1111', 'a1111-sd-webui-lycoris', 'sd-webui-agent-scheduler', 'clip-interrogator-ext', 'stable-diffusion-webui-rembg', 'sd-extension-chainner']:
+ for ext in ['sd-webui-controlnet', 'multidiffusion-upscaler-for-automatic1111', 'a1111-sd-webui-lycoris', 'sd-webui-agent-scheduler', 'clip-interrogator-ext', 'stable-diffusion-webui-rembg', 'sd-extension-chainner', 'stable-diffusion-webui-images-browser']:
if ext not in opts.disabled_extensions:
disabled.append(ext)
log.info(f'Safe mode disabling extensions: {disabled}')
@@ -171,50 +169,10 @@ def temp_disable_extensions():
if ext not in opts.disabled_extensions:
disabled.append(ext)
log.info(f'Diffusers disabling uncompatible extensions: {disabled}')
- if opts.lyco_patch_lora and backend != Backend.DIFFUSERS:
- cmd_opts.lyco_dir = opts.lora_dir
- if 'Lora' not in opts.disabled_extensions:
- disabled.append('Lora')
cmd_opts.controlnet_loglevel = 'WARNING'
return disabled
-def list_builtin_themes():
- files = [os.path.splitext(f)[0] for f in os.listdir('javascript') if f.endswith('.css')]
- return files
-
-
-def list_themes():
- fn = os.path.join('html', 'themes.json')
- if not os.path.exists(fn):
- refresh_themes()
- if os.path.exists(fn):
- with open(fn, mode='r', encoding='utf=8') as f:
- res = json.loads(f.read())
- else:
- res = []
- builtin = list_builtin_themes()
- default = ["gradio/default", "gradio/base", "gradio/glass", "gradio/monochrome", "gradio/soft"]
- external = {x['id'] for x in res if x['status'] == 'RUNNING' and 'test' not in x['id'].lower()}
- log.debug(f'Themes: builtin={len(builtin)} default={len(default)} external={len(external)}')
- themes = sorted(builtin) + sorted(default) + sorted(external, key=str.casefold)
- return themes
-
-
-def refresh_themes():
- try:
- r = req('https://huggingface.co/datasets/freddyaboulton/gradio-theme-subdomains/resolve/main/subdomains.json')
- if r.status_code == 200:
- res = r.json()
- fn = os.path.join('html', 'themes.json')
- writefile(res, fn)
- list_themes()
- else:
- log.error('Error refreshing UI themes')
- except Exception:
- log.error('Exception refreshing UI themes')
-
-
def readfile(filename, silent=False):
data = {}
try:
@@ -339,7 +297,7 @@ options_templates.update(options_section(('advanced', "Inference Settings"), {
"token_merging_sep": OptionInfo("