diff --git a/.github/workflows/run_tests.yaml b/.github/workflows/run_tests.yaml
index be7ffa23..9a0b8d22 100644
--- a/.github/workflows/run_tests.yaml
+++ b/.github/workflows/run_tests.yaml
@@ -18,7 +18,7 @@ jobs:
cache-dependency-path: |
**/requirements*txt
- name: Run tests
- run: python launch.py --tests --no-half --disable-opt-split-attention --use-cpu all --skip-torch-cuda-test
+ run: python launch.py --tests test --no-half --disable-opt-split-attention --use-cpu all --skip-torch-cuda-test
- name: Upload main app stdout-stderr
uses: actions/upload-artifact@v3
if: always()
diff --git a/README.md b/README.md
index 1aee9809..bee26613 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Stable Diffusion web UI-UX
+# Stable Diffusion web UI-UX
Not just a browser interface based on Gradio library for Stable Diffusion.
A pixel perfect design, mobile friendly, customizable interface that adds accessibility, ease of use and extended functionallity to the stable diffusion web ui.
This project is hoping to merge with the main branch at some point in the future.
@@ -6,9 +6,8 @@ Unfortunately this is going to take some time as the main author of the project
It is unsure how many of these changes will make it to the main branch
Until then you can use this repo enjoy!
-I will not upgrade to an unstable release from the master until major issues are resolved.
-You can find the latest experimental version in the dev branch.
-I will do my best to keep it up to date
+This is the latest and greatest experimental version please don't submit bugs for this release if it doesn't work for you use the stable release from master branch
+
Default theme
diff --git a/extensions-builtin/Lora/lora.py b/extensions-builtin/Lora/lora.py
index 8937b585..d3eb0d3b 100644
--- a/extensions-builtin/Lora/lora.py
+++ b/extensions-builtin/Lora/lora.py
@@ -2,20 +2,34 @@ import glob
import os
import re
import torch
+from typing import Union
from modules import shared, devices, sd_models, errors
metadata_tags_order = {"ss_sd_model_name": 1, "ss_resolution": 2, "ss_clip_skip": 3, "ss_num_train_images": 10, "ss_tag_frequency": 20}
re_digits = re.compile(r"\d+")
-re_unet_down_blocks = re.compile(r"lora_unet_down_blocks_(\d+)_attentions_(\d+)_(.+)")
-re_unet_mid_blocks = re.compile(r"lora_unet_mid_block_attentions_(\d+)_(.+)")
-re_unet_up_blocks = re.compile(r"lora_unet_up_blocks_(\d+)_attentions_(\d+)_(.+)")
-re_text_block = re.compile(r"lora_te_text_model_encoder_layers_(\d+)_(.+)")
+re_x_proj = re.compile(r"(.*)_([qkv]_proj)$")
+re_compiled = {}
+
+suffix_conversion = {
+ "attentions": {},
+ "resnets": {
+ "conv1": "in_layers_2",
+ "conv2": "out_layers_3",
+ "time_emb_proj": "emb_layers_1",
+ "conv_shortcut": "skip_connection",
+ }
+}
-def convert_diffusers_name_to_compvis(key):
- def match(match_list, regex):
+def convert_diffusers_name_to_compvis(key, is_sd2):
+ def match(match_list, regex_text):
+ regex = re_compiled.get(regex_text)
+ if regex is None:
+ regex = re.compile(regex_text)
+ re_compiled[regex_text] = regex
+
r = re.match(regex, key)
if not r:
return False
@@ -26,16 +40,33 @@ def convert_diffusers_name_to_compvis(key):
m = []
- if match(m, re_unet_down_blocks):
- return f"diffusion_model_input_blocks_{1 + m[0] * 3 + m[1]}_1_{m[2]}"
+ if match(m, r"lora_unet_down_blocks_(\d+)_(attentions|resnets)_(\d+)_(.+)"):
+ suffix = suffix_conversion.get(m[1], {}).get(m[3], m[3])
+ return f"diffusion_model_input_blocks_{1 + m[0] * 3 + m[2]}_{1 if m[1] == 'attentions' else 0}_{suffix}"
- if match(m, re_unet_mid_blocks):
- return f"diffusion_model_middle_block_1_{m[1]}"
+ if match(m, r"lora_unet_mid_block_(attentions|resnets)_(\d+)_(.+)"):
+ suffix = suffix_conversion.get(m[0], {}).get(m[2], m[2])
+ return f"diffusion_model_middle_block_{1 if m[0] == 'attentions' else m[1] * 2}_{suffix}"
- if match(m, re_unet_up_blocks):
- return f"diffusion_model_output_blocks_{m[0] * 3 + m[1]}_1_{m[2]}"
+ if match(m, r"lora_unet_up_blocks_(\d+)_(attentions|resnets)_(\d+)_(.+)"):
+ suffix = suffix_conversion.get(m[1], {}).get(m[3], m[3])
+ return f"diffusion_model_output_blocks_{m[0] * 3 + m[2]}_{1 if m[1] == 'attentions' else 0}_{suffix}"
+
+ if match(m, r"lora_unet_down_blocks_(\d+)_downsamplers_0_conv"):
+ return f"diffusion_model_input_blocks_{3 + m[0] * 3}_0_op"
+
+ if match(m, r"lora_unet_up_blocks_(\d+)_upsamplers_0_conv"):
+ return f"diffusion_model_output_blocks_{2 + m[0] * 3}_{2 if m[0]>0 else 1}_conv"
+
+ if match(m, r"lora_te_text_model_encoder_layers_(\d+)_(.+)"):
+ if is_sd2:
+ if 'mlp_fc1' in m[1]:
+ return f"model_transformer_resblocks_{m[0]}_{m[1].replace('mlp_fc1', 'mlp_c_fc')}"
+ elif 'mlp_fc2' in m[1]:
+ return f"model_transformer_resblocks_{m[0]}_{m[1].replace('mlp_fc2', 'mlp_c_proj')}"
+ else:
+ return f"model_transformer_resblocks_{m[0]}_{m[1].replace('self_attn', 'attn')}"
- if match(m, re_text_block):
return f"transformer_text_model_encoder_layers_{m[0]}_{m[1]}"
return key
@@ -101,15 +132,22 @@ def load_lora(name, filename):
sd = sd_models.read_state_dict(filename)
- keys_failed_to_match = []
+ keys_failed_to_match = {}
+ is_sd2 = 'model_transformer_resblocks' in shared.sd_model.lora_layer_mapping
for key_diffusers, weight in sd.items():
- fullkey = convert_diffusers_name_to_compvis(key_diffusers)
- key, lora_key = fullkey.split(".", 1)
+ key_diffusers_without_lora_parts, lora_key = key_diffusers.split(".", 1)
+ key = convert_diffusers_name_to_compvis(key_diffusers_without_lora_parts, is_sd2)
sd_module = shared.sd_model.lora_layer_mapping.get(key, None)
+
if sd_module is None:
- keys_failed_to_match.append(key_diffusers)
+ m = re_x_proj.match(key)
+ if m:
+ sd_module = shared.sd_model.lora_layer_mapping.get(m.group(1), None)
+
+ if sd_module is None:
+ keys_failed_to_match[key_diffusers] = key
continue
lora_module = lora.modules.get(key, None)
@@ -123,15 +161,21 @@ def load_lora(name, filename):
if type(sd_module) == torch.nn.Linear:
module = torch.nn.Linear(weight.shape[1], weight.shape[0], bias=False)
+ elif type(sd_module) == torch.nn.modules.linear.NonDynamicallyQuantizableLinear:
+ module = torch.nn.Linear(weight.shape[1], weight.shape[0], bias=False)
+ elif type(sd_module) == torch.nn.MultiheadAttention:
+ module = torch.nn.Linear(weight.shape[1], weight.shape[0], bias=False)
elif type(sd_module) == torch.nn.Conv2d:
module = torch.nn.Conv2d(weight.shape[1], weight.shape[0], (1, 1), bias=False)
else:
+ print(f'Lora layer {key_diffusers} matched a layer with unsupported type: {type(sd_module).__name__}')
+ continue
assert False, f'Lora layer {key_diffusers} matched a layer with unsupported type: {type(sd_module).__name__}'
with torch.no_grad():
module.weight.copy_(weight)
- module.to(device=devices.device, dtype=devices.dtype)
+ module.to(device=devices.cpu, dtype=devices.dtype)
if lora_key == "lora_up.weight":
lora_module.up = module
@@ -177,28 +221,120 @@ def load_loras(names, multipliers=None):
loaded_loras.append(lora)
-def lora_forward(module, input, res):
- if len(loaded_loras) == 0:
- return res
+def lora_calc_updown(lora, module, target):
+ with torch.no_grad():
+ up = module.up.weight.to(target.device, dtype=target.dtype)
+ down = module.down.weight.to(target.device, dtype=target.dtype)
- lora_layer_name = getattr(module, 'lora_layer_name', None)
- for lora in loaded_loras:
- module = lora.modules.get(lora_layer_name, None)
- if module is not None:
- if shared.opts.lora_apply_to_outputs and res.shape == input.shape:
- res = res + module.up(module.down(res)) * lora.multiplier * (module.alpha / module.up.weight.shape[1] if module.alpha else 1.0)
+ if up.shape[2:] == (1, 1) and down.shape[2:] == (1, 1):
+ updown = (up.squeeze(2).squeeze(2) @ down.squeeze(2).squeeze(2)).unsqueeze(2).unsqueeze(3)
+ else:
+ updown = up @ down
+
+ updown = updown * lora.multiplier * (module.alpha / module.up.weight.shape[1] if module.alpha else 1.0)
+
+ return updown
+
+
+def lora_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.MultiheadAttention]):
+ """
+ Applies the currently selected set of Loras to the weights of torch layer self.
+ If weights already have this particular set of loras applied, does nothing.
+ If not, restores orginal weights from backup and alters weights according to loras.
+ """
+
+ lora_layer_name = getattr(self, 'lora_layer_name', None)
+ if lora_layer_name is None:
+ return
+
+ current_names = getattr(self, "lora_current_names", ())
+ wanted_names = tuple((x.name, x.multiplier) for x in loaded_loras)
+
+ weights_backup = getattr(self, "lora_weights_backup", None)
+ if weights_backup is None:
+ if isinstance(self, torch.nn.MultiheadAttention):
+ weights_backup = (self.in_proj_weight.to(devices.cpu, copy=True), self.out_proj.weight.to(devices.cpu, copy=True))
+ else:
+ weights_backup = self.weight.to(devices.cpu, copy=True)
+
+ self.lora_weights_backup = weights_backup
+
+ if current_names != wanted_names:
+ if weights_backup is not None:
+ if isinstance(self, torch.nn.MultiheadAttention):
+ self.in_proj_weight.copy_(weights_backup[0])
+ self.out_proj.weight.copy_(weights_backup[1])
else:
- res = res + module.up(module.down(input)) * lora.multiplier * (module.alpha / module.up.weight.shape[1] if module.alpha else 1.0)
+ self.weight.copy_(weights_backup)
- return res
+ for lora in loaded_loras:
+ module = lora.modules.get(lora_layer_name, None)
+ if module is not None and hasattr(self, 'weight'):
+ self.weight += lora_calc_updown(lora, module, self.weight)
+ continue
+
+ module_q = lora.modules.get(lora_layer_name + "_q_proj", None)
+ module_k = lora.modules.get(lora_layer_name + "_k_proj", None)
+ module_v = lora.modules.get(lora_layer_name + "_v_proj", None)
+ module_out = lora.modules.get(lora_layer_name + "_out_proj", None)
+
+ if isinstance(self, torch.nn.MultiheadAttention) and module_q and module_k and module_v and module_out:
+ updown_q = lora_calc_updown(lora, module_q, self.in_proj_weight)
+ updown_k = lora_calc_updown(lora, module_k, self.in_proj_weight)
+ updown_v = lora_calc_updown(lora, module_v, self.in_proj_weight)
+ updown_qkv = torch.vstack([updown_q, updown_k, updown_v])
+
+ self.in_proj_weight += updown_qkv
+ self.out_proj.weight += lora_calc_updown(lora, module_out, self.out_proj.weight)
+ continue
+
+ if module is None:
+ continue
+
+ print(f'failed to calculate lora weights for layer {lora_layer_name}')
+
+ setattr(self, "lora_current_names", wanted_names)
+
+
+def lora_reset_cached_weight(self: Union[torch.nn.Conv2d, torch.nn.Linear]):
+ setattr(self, "lora_current_names", ())
+ setattr(self, "lora_weights_backup", None)
def lora_Linear_forward(self, input):
- return lora_forward(self, input, torch.nn.Linear_forward_before_lora(self, input))
+ lora_apply_weights(self)
+
+ return torch.nn.Linear_forward_before_lora(self, input)
+
+
+def lora_Linear_load_state_dict(self, *args, **kwargs):
+ lora_reset_cached_weight(self)
+
+ return torch.nn.Linear_load_state_dict_before_lora(self, *args, **kwargs)
def lora_Conv2d_forward(self, input):
- return lora_forward(self, input, torch.nn.Conv2d_forward_before_lora(self, input))
+ lora_apply_weights(self)
+
+ return torch.nn.Conv2d_forward_before_lora(self, input)
+
+
+def lora_Conv2d_load_state_dict(self, *args, **kwargs):
+ lora_reset_cached_weight(self)
+
+ return torch.nn.Conv2d_load_state_dict_before_lora(self, *args, **kwargs)
+
+
+def lora_MultiheadAttention_forward(self, *args, **kwargs):
+ lora_apply_weights(self)
+
+ return torch.nn.MultiheadAttention_forward_before_lora(self, *args, **kwargs)
+
+
+def lora_MultiheadAttention_load_state_dict(self, *args, **kwargs):
+ lora_reset_cached_weight(self)
+
+ return torch.nn.MultiheadAttention_load_state_dict_before_lora(self, *args, **kwargs)
def list_available_loras():
@@ -211,7 +347,7 @@ def list_available_loras():
glob.glob(os.path.join(shared.cmd_opts.lora_dir, '**/*.safetensors'), recursive=True) + \
glob.glob(os.path.join(shared.cmd_opts.lora_dir, '**/*.ckpt'), recursive=True)
- for filename in sorted(candidates):
+ for filename in sorted(candidates, key=str.lower):
if os.path.isdir(filename):
continue
diff --git a/extensions-builtin/Lora/scripts/lora_script.py b/extensions-builtin/Lora/scripts/lora_script.py
index 2e860160..0adab225 100644
--- a/extensions-builtin/Lora/scripts/lora_script.py
+++ b/extensions-builtin/Lora/scripts/lora_script.py
@@ -9,7 +9,11 @@ from modules import script_callbacks, ui_extra_networks, extra_networks, shared
def unload():
torch.nn.Linear.forward = torch.nn.Linear_forward_before_lora
+ torch.nn.Linear._load_from_state_dict = torch.nn.Linear_load_state_dict_before_lora
torch.nn.Conv2d.forward = torch.nn.Conv2d_forward_before_lora
+ torch.nn.Conv2d._load_from_state_dict = torch.nn.Conv2d_load_state_dict_before_lora
+ torch.nn.MultiheadAttention.forward = torch.nn.MultiheadAttention_forward_before_lora
+ torch.nn.MultiheadAttention._load_from_state_dict = torch.nn.MultiheadAttention_load_state_dict_before_lora
def before_ui():
@@ -20,11 +24,27 @@ def before_ui():
if not hasattr(torch.nn, 'Linear_forward_before_lora'):
torch.nn.Linear_forward_before_lora = torch.nn.Linear.forward
+if not hasattr(torch.nn, 'Linear_load_state_dict_before_lora'):
+ torch.nn.Linear_load_state_dict_before_lora = torch.nn.Linear._load_from_state_dict
+
if not hasattr(torch.nn, 'Conv2d_forward_before_lora'):
torch.nn.Conv2d_forward_before_lora = torch.nn.Conv2d.forward
+if not hasattr(torch.nn, 'Conv2d_load_state_dict_before_lora'):
+ torch.nn.Conv2d_load_state_dict_before_lora = torch.nn.Conv2d._load_from_state_dict
+
+if not hasattr(torch.nn, 'MultiheadAttention_forward_before_lora'):
+ torch.nn.MultiheadAttention_forward_before_lora = torch.nn.MultiheadAttention.forward
+
+if not hasattr(torch.nn, 'MultiheadAttention_load_state_dict_before_lora'):
+ torch.nn.MultiheadAttention_load_state_dict_before_lora = torch.nn.MultiheadAttention._load_from_state_dict
+
torch.nn.Linear.forward = lora.lora_Linear_forward
+torch.nn.Linear._load_from_state_dict = lora.lora_Linear_load_state_dict
torch.nn.Conv2d.forward = lora.lora_Conv2d_forward
+torch.nn.Conv2d._load_from_state_dict = lora.lora_Conv2d_load_state_dict
+torch.nn.MultiheadAttention.forward = lora.lora_MultiheadAttention_forward
+torch.nn.MultiheadAttention._load_from_state_dict = lora.lora_MultiheadAttention_load_state_dict
script_callbacks.on_model_loaded(lora.assign_lora_names_to_compvis_modules)
script_callbacks.on_script_unloaded(unload)
@@ -33,6 +53,4 @@ script_callbacks.on_before_ui(before_ui)
shared.options_templates.update(shared.options_section(('extra_networks', "Extra Networks"), {
"sd_lora": shared.OptionInfo("None", "Add Lora to prompt", gr.Dropdown, lambda: {"choices": [""] + [x for x in lora.available_loras]}, refresh=lora.list_available_loras),
- "lora_apply_to_outputs": shared.OptionInfo(False, "Apply Lora to outputs rather than inputs when possible (experimental)"),
-
}))
diff --git a/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js b/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js
index 4a85c8eb..f0918e26 100644
--- a/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js
+++ b/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js
@@ -89,22 +89,15 @@ function checkBrackets(evt, textArea, counterElt) {
function setupBracketChecking(id_prompt, id_counter){
var textarea = gradioApp().querySelector("#" + id_prompt + " > label > textarea");
var counter = gradioApp().getElementById(id_counter)
+
textarea.addEventListener("input", function(evt){
checkBrackets(evt, textarea, counter)
});
}
-var shadowRootLoaded = setInterval(function() {
- var shadowRoot = document.querySelector('gradio-app').shadowRoot;
- if(! shadowRoot) return false;
-
- var shadowTextArea = shadowRoot.querySelectorAll('#txt2img_prompt > label > textarea');
- if(shadowTextArea.length < 1) return false;
-
- clearInterval(shadowRootLoaded);
-
+onUiLoaded(function(){
setupBracketChecking('txt2img_prompt', 'txt2img_token_counter')
setupBracketChecking('txt2img_neg_prompt', 'txt2img_negative_token_counter')
- setupBracketChecking('img2img_prompt', 'imgimg_token_counter')
+ setupBracketChecking('img2img_prompt', 'img2img_token_counter')
setupBracketChecking('img2img_neg_prompt', 'img2img_negative_token_counter')
-}, 1000);
+})
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/javascript/ui_theme.js b/extensions-builtin/sd_theme_editor/javascript/ui_theme.js
index 484b0f9b..9a42527d 100644
--- a/extensions-builtin/sd_theme_editor/javascript/ui_theme.js
+++ b/extensions-builtin/sd_theme_editor/javascript/ui_theme.js
@@ -177,8 +177,8 @@ function offsetColorsHSV(ohsl){
isColorsInv = false;
const preview_styles = gradioApp().querySelector('#preview-styles');
- preview_styles.innerHTML = ':host {'+ inner_styles +'}';
- preview_styles.innerHTML +='@media only screen and (max-width: 860px) {:host{--outside-gap-size: var(--mobile-outside-gap-size);--inside-padding-size: var(--mobile-inside-padding-size);}}';
+ preview_styles.innerHTML = ':root {'+ inner_styles +'}';
+ preview_styles.innerHTML +='@media only screen and (max-width: 860px) {:root{--ae-outside-gap-size: var(--ae-mobile-outside-gap-size);--ae-inside-padding-size: var(--ae-mobile-inside-padding-size);}}';
const vars_textarea = gradioApp().querySelector('#theme_vars textarea');
@@ -216,15 +216,15 @@ function updateTheme(vars){
const preview_styles = gradioApp().querySelector('#preview-styles');
if(preview_styles){
- preview_styles.innerHTML = ':host {'+ inner_styles +'}';
- preview_styles.innerHTML +='@media only screen and (max-width: 860px) {:host{--outside-gap-size: var(--mobile-outside-gap-size);--inside-padding-size: var(--mobile-inside-padding-size);}}';
+ preview_styles.innerHTML = ':root {'+ inner_styles +'}';
+ preview_styles.innerHTML +='@media only screen and (max-width: 860px) {:root{--ae-outside-gap-size: var(--ae-mobile-outside-gap-size);--ae-inside-padding-size: var(--ae-mobile-inside-padding-size);}}';
}else{
const r = gradioApp();
const style = document.createElement('style');
style.id="preview-styles";
- style.innerHTML = ':host {'+ inner_styles +'}';
- style.innerHTML +='@media only screen and (max-width: 860px) {:host{--outside-gap-size: var(--mobile-outside-gap-size);--inside-padding-size: var(--mobile-inside-padding-size);}}';
+ style.innerHTML = ':root {'+ inner_styles +'}';
+ style.innerHTML +='@media only screen and (max-width: 860px) {:root{--ae-outside-gap-size: var(--ae-mobile-outside-gap-size);--ae-inside-padding-size: var(--ae-mobile-inside-padding-size);}}';
r.appendChild(style);
}
@@ -246,11 +246,17 @@ function updateTheme(vars){
}
-
+function applyTheme(){
+ console.log("apply");
+}
function initTheme() {
- const current_style = gradioApp().querySelector('style');
+
+ const current_style = gradioApp().querySelector('.gradio-container > style');
+ //console.log(current_style);
+ //const head = document.head;
+ //head.appendChild(current_style);
const css_styles = current_style.innerHTML.split("/*BREAKPOINT_CSS_CONTENT*/");
let init_css_vars = css_styles[0].split("}")[0].split("{")[1];
@@ -282,6 +288,7 @@ function initTheme() {
let intervalChange;
+
gradioApp().querySelectorAll('#ui_theme_settings input').forEach((elem) => {
elem.addEventListener("input", function(e) {
@@ -309,7 +316,7 @@ function initTheme() {
//console.log(styleobj);
-
+
if(intervalChange != null) clearInterval(intervalChange);
intervalChange = setTimeout(() => {
let inner_styles = "";
@@ -319,8 +326,8 @@ function initTheme() {
}
vars = inner_styles.split(";");
- preview_styles.innerHTML = ':host {'+ inner_styles +'}';
- preview_styles.innerHTML +='@media only screen and (max-width: 860px) {:host{--outside-gap-size: var(--mobile-outside-gap-size);--inside-padding-size: var(--mobile-inside-padding-size);}}';
+ preview_styles.innerHTML = ':root {'+ inner_styles +'}';
+ preview_styles.innerHTML +='@media only screen and (max-width: 860px) {:root{--ae-outside-gap-size: var(--ae-mobile-outside-gap-size);--ae-inside-padding-size: var(--ae-mobile-inside-padding-size);}}';
vars_textarea.value = inner_styles;
const vEvent = new Event("input");
@@ -328,7 +335,7 @@ function initTheme() {
vars_textarea.dispatchEvent(vEvent);
offsetColorsHSV(hsloffset);
- }, 500)
+ }, 1000)
})
})
@@ -373,17 +380,20 @@ function initTheme() {
}
}
+
- const drop_down = gradioApp().getElementById('themes_drop_down');
- drop_down.addEventListener("change", function(e) {
+
+ const drop_down = gradioApp().querySelector('#themes_drop_down');
+ drop_down.addEventListener("click", function(e) {
if(intervalCheck != null) clearInterval(intervalCheck);
intervalCheck = setInterval(dropDownOnChange, 100);
+ console.log("ok");
})
let hsloffset = [0,0,0];
const hue = gradioApp().querySelectorAll('#theme_hue input').forEach((elem) => {
- elem.addEventListener("input", function(e) {
+ elem.addEventListener("change", function(e) {
e.preventDefault();
e.stopPropagation();
hsloffset[0] = e.currentTarget.value;
@@ -392,7 +402,7 @@ function initTheme() {
})
const sat = gradioApp().querySelectorAll('#theme_sat input').forEach((elem) => {
- elem.addEventListener("input", function(e) {
+ elem.addEventListener("change", function(e) {
e.preventDefault();
e.stopPropagation();
hsloffset[1] = e.currentTarget.value;
@@ -401,7 +411,7 @@ function initTheme() {
})
const brt = gradioApp().querySelectorAll('#theme_brt input').forEach((elem) => {
- elem.addEventListener("input", function(e) {
+ elem.addEventListener("change", function(e) {
e.preventDefault();
e.stopPropagation();
hsloffset[2] = e.currentTarget.value;
diff --git a/extensions-builtin/sd_theme_editor/scripts/ui_theme.py b/extensions-builtin/sd_theme_editor/scripts/ui_theme.py
index f249c90c..3a2c8a2b 100644
--- a/extensions-builtin/sd_theme_editor/scripts/ui_theme.py
+++ b/extensions-builtin/sd_theme_editor/scripts/ui_theme.py
@@ -33,8 +33,8 @@ def on_ui_tabs():
#with gr.Accordion(label="Debug View", open=True):
with gr.Row(elem_id="theme_hidden"):
- vars_text = gr.Textbox(label="Vars", elem_id="theme_vars", show_label=True, lines=7, interactive=False, visible=False)
- css_text = gr.Textbox(label="Css", elem_id="theme_css", show_label=True, lines=7, interactive=False, visible=False)
+ vars_text = gr.Textbox(label="Vars", elem_id="theme_vars", show_label=True, lines=7, interactive=False, visible=True)
+ css_text = gr.Textbox(label="Css", elem_id="theme_css", show_label=True, lines=7, interactive=False, visible=True)
#result_text = gr.Text(elem_id="theme_result", interactive=False, visible=False)
with gr.Column(elem_id="theme_overflow_container"):
with gr.Accordion(label="Theme Color adjustments", open=True):
@@ -51,69 +51,69 @@ def on_ui_tabs():
with gr.Column():
with gr.Column():
with gr.Accordion(label="Main", open=True):
- gr.ColorPicker(elem_id="--main-bg-color", interactive=True, label="Background color")
- gr.ColorPicker(elem_id="--primary-color", label="Primary color")
+ gr.ColorPicker(elem_id="--ae-main-bg-color", interactive=True, label="Background color")
+ gr.ColorPicker(elem_id="--ae-primary-color", label="Primary color")
with gr.Accordion(label="Focus", open=True):
- gr.ColorPicker(elem_id="--textarea-focus-color", label="Textarea color")
- gr.ColorPicker(elem_id="--input-focus-color", label="Input color")
+ gr.ColorPicker(elem_id="--ae-textarea-focus-color", label="Textarea color")
+ gr.ColorPicker(elem_id="--ae-input-focus-color", label="Input color")
with gr.Accordion(label="Spacing", open=True):
- gr.Slider(elem_id="--outside-gap-size", label='Gap size', minimum=1, maximum=16, step=1, interactive=True)
- gr.Slider(elem_id="--inside-padding-size", label='Padding size', minimum=1, maximum=16, step=1, interactive=True)
+ gr.Slider(elem_id="--ae-outside-gap-size", label='Gap size', minimum=1, maximum=16, step=1, interactive=True)
+ gr.Slider(elem_id="--ae-inside-padding-size", label='Padding size', minimum=1, maximum=16, step=1, interactive=True)
- with gr.Accordion(label="Spacing (Modile)", open=True):
- gr.Slider(elem_id="--mobile-outside-gap-size", label='Mobile Gap size', minimum=1, maximum=16, step=1, interactive=True)
- gr.Slider(elem_id="--mobile-inside-padding-size", label='Mobile Padding size', minimum=1, maximum=16, step=1, interactive=True)
+ with gr.Accordion(label="Spacing (Mobile)", open=True):
+ gr.Slider(elem_id="--ae-mobile-outside-gap-size", label='Mobile Gap size', minimum=1, maximum=16, step=1, interactive=True)
+ gr.Slider(elem_id="--ae-mobile-inside-padding-size", label='Mobile Padding size', minimum=1, maximum=16, step=1, interactive=True)
with gr.Accordion(label="Panel", open=True):
- gr.ColorPicker(elem_id="--label-color", label="Label color")
- gr.ColorPicker(elem_id="--frame-bg-color", label="Frame Background color")
- gr.ColorPicker(elem_id="--panel-bg-color", label="Background color")
- gr.ColorPicker(elem_id="--panel-border-color", label="Border color")
- gr.Slider(elem_id="--panel-border-radius", label='Border radius', minimum=0, maximum=16, step=1)
+ gr.ColorPicker(elem_id="--ae-label-color", label="Label color")
+ gr.ColorPicker(elem_id="--ae-frame-bg-color", label="Frame Background color")
+ gr.ColorPicker(elem_id="--ae-panel-bg-color", label="Background color")
+ gr.ColorPicker(elem_id="--ae-panel-border-color", label="Border color")
+ gr.Slider(elem_id="--ae-panel-border-radius", label='Border radius', minimum=0, maximum=16, step=1)
- gr.ColorPicker(elem_id="--input-color", label="Input text color")
- gr.ColorPicker(elem_id="--input-bg-color", label="Input background color")
- gr.ColorPicker(elem_id="--input-border-color", label="Input border color")
+ gr.ColorPicker(elem_id="--ae-input-color", label="Input text color")
+ gr.ColorPicker(elem_id="--ae-input-bg-color", label="Input background color")
+ gr.ColorPicker(elem_id="--ae-input-border-color", label="Input border color")
with gr.Column():
- with gr.Row(elem_id="theme_sub-group-collapse"):
+ with gr.Row(elem_id="theme_sub-panel"):
with gr.Accordion(label="SubPanel", open=True):
- gr.ColorPicker(elem_id="--subgroup-bg-color", label="Subgoup background color")
- #gr.ColorPicker(elem_id="--subgroup-label-color", label="Label color", value="#000000")
- gr.ColorPicker(elem_id="--subpanel-bg-color", label="Background color")
- gr.ColorPicker(elem_id="--subpanel-border-color", label="Border color")
- gr.Slider(elem_id="--subpanel-border-radius", label='Border radius', minimum=0, maximum=16, step=1)
+ gr.ColorPicker(elem_id="--ae-subgroup-bg-color", label="Subgoup background color")
+ #gr.ColorPicker(elem_id="--ae-subgroup-label-color", label="Label color", value="#000000")
+ gr.ColorPicker(elem_id="--ae-subpanel-bg-color", label="Background color")
+ gr.ColorPicker(elem_id="--ae-subpanel-border-color", label="Border color")
+ gr.Slider(elem_id="--ae-subpanel-border-radius", label='Border radius', minimum=0, maximum=16, step=1)
- gr.ColorPicker(elem_id="--subgroup-input-color", label="Input text color")
- gr.ColorPicker(elem_id="--subgroup-input-bg-color", label="Input background color")
- gr.ColorPicker(elem_id="--subgroup-input-border-color", label="Input border color")
+ gr.ColorPicker(elem_id="--ae-subgroup-input-color", label="Input text color")
+ gr.ColorPicker(elem_id="--ae-subgroup-input-bg-color", label="Input background color")
+ gr.ColorPicker(elem_id="--ae-subgroup-input-border-color", label="Input border color")
with gr.Row():
with gr.Column():
with gr.Accordion(label="Navigation menu", open=True):
- gr.ColorPicker(elem_id="--nav-bg-color", label="Background color")
- gr.ColorPicker(elem_id="--nav-color", label="Text color")
- gr.ColorPicker(elem_id="--nav-hover-color", label="Hover color")
+ gr.ColorPicker(elem_id="--ae-nav-bg-color", label="Background color")
+ gr.ColorPicker(elem_id="--ae-nav-color", label="Text color")
+ gr.ColorPicker(elem_id="--ae-nav-hover-color", label="Hover color")
with gr.Accordion(label="Icon", open=True):
- gr.ColorPicker(elem_id="--icon-color", label="Text color")
- gr.ColorPicker(elem_id="--icon-hover-color", label="Hover color")
+ gr.ColorPicker(elem_id="--ae-icon-color", label="Color")
+ gr.ColorPicker(elem_id="--ae-icon-hover-color", label="Hover color")
with gr.Accordion(label="Other", open=True):
- gr.ColorPicker(elem_id="--text-color", label="Text color")
- gr.ColorPicker(elem_id="--placeholder-color", label="Placeholder color")
- gr.ColorPicker(elem_id="--cancel-color", label="Cancel/Interrupt color")
+ gr.ColorPicker(elem_id="--ae-text-color", label="Text color")
+ gr.ColorPicker(elem_id="--ae-placeholder-color", label="Placeholder color")
+ gr.ColorPicker(elem_id="--ae-cancel-color", label="Cancel/Interrupt color")
with gr.Accordion(label="Modal", open=True):
- gr.ColorPicker(elem_id="--modal-bg-color", label="Background color")
- gr.ColorPicker(elem_id="--modal-icon-color", label="Icon color")
+ gr.ColorPicker(elem_id="--ae-modal-bg-color", label="Background color")
+ gr.ColorPicker(elem_id="--ae-modal-icon-color", label="Icon color")
def save_theme( vars_text, css_text, filename):
- style_data= ":host{" + vars_text + "}" + css_text
+ style_data= ":root{" + vars_text + "}" + css_text
with open(os.path.join(themes_folder, f"{filename}.css"), 'w', encoding="utf-8") as file:
file.write(vars_text)
file.close()
diff --git a/extensions-builtin/sd_theme_editor/style.css b/extensions-builtin/sd_theme_editor/style.css
index 5c0d44c5..e7d70385 100644
--- a/extensions-builtin/sd_theme_editor/style.css
+++ b/extensions-builtin/sd_theme_editor/style.css
@@ -1,7 +1,7 @@
#theme_menu
{
z-index: 9999;
- background-color: var(--input-bg-color);
+ background-color: var(--ae-input-bg-color);
position: relative;
width: 38px;
height: 38px;
@@ -18,9 +18,9 @@
display: inline-block;
-webkit-mask-size: cover;
mask-size: cover;
- background-color: var(--icon-color);
- width: var(--icon-size);
- height: var(--icon-size);
+ background-color: var(--ae-icon-color);
+ width: var(--ae-icon-size);
+ height: var(--ae-icon-size);
-webkit-mask: url(./file=html/svg/contrast-drop-2-line.svg) no-repeat 50% 50%;
mask: url(./file=html/svg/contrast-drop-2-line.svg) no-repeat 50% 50%;
cursor: pointer;
@@ -30,20 +30,19 @@
transform: translate(-50%, -50%) scale(1.0);
}
-#theme_menu.fixed,
-#theme_menu:hover
-{
- background-color: var(--primary-color);
+#theme_menu.fixed, #theme_menu:hover {
+ background-color: var(--ae-icon-color);
}
+
#theme_menu.fixed::before,
#theme_menu:hover::before
{
- background-color: var(--main-bg-color);
+ background-color: var(--ae-icon-hover-color);
}
#theme_overflow_container{
overflow-y: auto;
- height: calc(100vh - var(--top-header-height) - ( var(--outside-gap-size) * 2 ) - ( var(--inside-padding-size) * 4 ) - 96px );
+ height: calc(100vh - var(--ae-top-header-height) - ( var(--ae-outside-gap-size) * 2 ) - ( var(--ae-inside-padding-size) * 4 ) - 96px );
}
#tab_ui_theme.open
@@ -59,17 +58,18 @@
#tab_ui_theme.aside
{
position: fixed;
- top: var(--top-header-height);
+ top: var(--ae-top-header-height);
width: 90%;
right: 0;
- height: calc(100% - var(--top-header-height));
+ height: calc(100% - var(--ae-top-header-height));
max-width: 480px;
z-index: 9999;
transform: translateX(100%);
transition: all 0.25s ease 0s;
box-shadow: rgba(0,0,0,0) -30px 0 30px -30px;
- padding: calc(1rem - var(--outside-gap-size));
- background-color: var(--main-bg-color) !important;
+ padding: calc(1rem - var(--ae-outside-gap-size));
+ background-color: var(--ae-main-bg-color) !important;
+
}
#tab_ui_theme.aside.open
{
@@ -106,5 +106,9 @@
#tab_ui_theme > div{
padding:16px !important;
+ padding-top:0!important;
}
+#ui_theme_hsv + button{
+ min-width:unset;
+}
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/Golde.css b/extensions-builtin/sd_theme_editor/themes/Golde.css
index 81cbc802..55250596 100644
--- a/extensions-builtin/sd_theme_editor/themes/Golde.css
+++ b/extensions-builtin/sd_theme_editor/themes/Golde.css
@@ -1 +1 @@
---main-bg-color:hsl(99deg 11% 8%);--primary-color:hsl(44deg 63% 55%);--input-bg-color:hsl(106deg 8% 12%);--input-border-color:hsl(104deg 9% 32%);--panel-bg-color:hsl(104deg 9% 20%);--panel-border-color:hsl(104deg 9% 32%);--panel-border-radius:4px;--subgroup-bg-color:hsl(99deg 11% 8%);--subgroup-input-bg-color:hsl(99deg 11% 8%);--subgroup-input-border-color:hsl(104deg 9% 32%);--subpanel-bg-color:hsl(106deg 8% 12%);--subpanel-border-color:hsl(104deg 9% 32%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(56deg 30% 36%);--input-focus-color:hsl(44deg 63% 55%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(104deg 9% 32%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(105deg 9% 77%);--icon-hover-color:hsl(99deg 11% 8%);--icon-size:22px;--nav-bg-color:hsl(98deg 9% 4%);--nav-color:hsl(105deg 9% 77%);--nav-hover-color:hsl(98deg 9% 4%);--input-color:hsl(44deg 63% 55%);--label-color:hsl(105deg 9% 77%);--subgroup-input-color:hsl(206deg 67% 100%);--placeholder-color:hsl(104deg 9% 32%);--text-color:hsl(105deg 9% 77%);--mobile-outside-gap-size:2px;--mobile-inside-padding-size:2px;--frame-bg-color:hsl(108deg 8% 12%);--modal-bg-color:hsl(96deg 12% 8%);--modal-icon-color:hsl(44deg 63% 55%);
\ No newline at end of file
+--ae-main-bg-color:hsl(99deg 11% 8%);--ae-primary-color:hsl(44deg 63% 55%);--ae-input-bg-color:hsl(106deg 8% 12%);--ae-input-border-color:hsl(104deg 9% 32%);--ae-panel-bg-color:hsl(104deg 9% 20%);--ae-panel-border-color:hsl(104deg 9% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(99deg 11% 8%);--ae-subgroup-input-bg-color:hsl(99deg 11% 8%);--ae-subgroup-input-border-color:hsl(104deg 9% 32%);--ae-subpanel-bg-color:hsl(106deg 8% 12%);--ae-subpanel-border-color:hsl(104deg 9% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(56deg 30% 36%);--ae-input-focus-color:hsl(44deg 63% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(104deg 9% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(105deg 9% 77%);--ae-icon-hover-color:hsl(99deg 11% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(98deg 9% 4%);--ae-nav-color:hsl(105deg 9% 77%);--ae-nav-hover-color:hsl(98deg 9% 4%);--ae-input-color:hsl(44deg 63% 55%);--ae-label-color:hsl(105deg 9% 77%);--ae-subgroup-input-color:hsl(44deg 63% 55%);--ae-placeholder-color:hsl(104deg 9% 32%);--ae-text-color:hsl(105deg 9% 77%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(108deg 8% 12%);--ae-modal-bg-color:hsl(96deg 12% 8%);--ae-modal-icon-color:hsl(44deg 63% 55%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/backup.css b/extensions-builtin/sd_theme_editor/themes/backup.css
index a6953f26..f2537ed3 100644
--- a/extensions-builtin/sd_theme_editor/themes/backup.css
+++ b/extensions-builtin/sd_theme_editor/themes/backup.css
@@ -1 +1 @@
---main-bg-color:hsl(0deg 0% 10%);--primary-color:hsl(168deg 96% 42%);--input-bg-color:hsl(225deg 6% 13%);--input-border-color:hsl(214deg 5% 30%);--panel-bg-color:hsl(225deg 5% 17%);--panel-border-color:hsl(214deg 5% 30%);--panel-border-radius:0px;--subgroup-bg-color:hsl(0deg 0% 10%);--subgroup-input-bg-color:hsl(225deg 6% 13%);--subgroup-input-border-color:hsl(214deg 5% 30%);--subpanel-bg-color:hsl(220deg 4% 14%);--subpanel-border-color:hsl(214deg 5% 30%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(210deg 3% 36%);--input-focus-color:hsl(168deg 97% 41%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(0deg 84% 60%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(210deg 4% 80%);--icon-hover-color:hsl(0deg 0% 10%);--icon-size:22px;--nav-bg-color:hsl(0deg 0% 4%);--nav-color:hsl(210deg 4% 80%);--nav-hover-color:hsl(0deg 0% 4%);--input-color:hsl(210deg 4% 80%);--label-color:hsl(210deg 4% 80%);--subgroup-input-color:hsl(0deg 100% 100%);--placeholder-color:hsl(214deg 5% 30%);--text-color:hsl(210deg 4% 80%);--mobile-outside-gap-size:3px;--mobile-inside-padding-size:3px;
\ No newline at end of file
+--ae-main-bg-color:hsl(0deg 0% 10%);--ae-primary-color:hsl(168deg 96% 42%);--ae-input-bg-color:hsl(225deg 6% 13%);--ae-input-border-color:hsl(214deg 5% 30%);--ae-panel-bg-color:hsl(225deg 5% 17%);--ae-panel-border-color:hsl(214deg 5% 30%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(0deg 0% 10%);--ae-subgroup-input-bg-color:hsl(225deg 6% 13%);--ae-subgroup-input-border-color:hsl(214deg 5% 30%);--ae-subpanel-bg-color:hsl(220deg 4% 14%);--ae-subpanel-border-color:hsl(214deg 5% 30%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(168deg 97% 41%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(0deg 84% 60%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(168deg 96% 42%);--ae-icon-hover-color:hsl(0deg 0% 10%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(0deg 0% 4%);--ae-nav-color:hsl(210deg 4% 80%);--ae-nav-hover-color:hsl(0deg 0% 4%);--ae-input-color:hsl(210deg 4% 80%);--ae-label-color:hsl(210deg 4% 80%);--ae-subgroup-input-color:hsl(0deg 100% 100%);--ae-placeholder-color:hsl(214deg 5% 30%);--ae-text-color:hsl(210deg 4% 80%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(225deg 6% 13%);--ae-modal-bg-color:hsl(0deg 0% 10%);--ae-modal-icon-color:hsl(168deg 97% 41%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/d-230-52-94.css b/extensions-builtin/sd_theme_editor/themes/d-230-52-94.css
index 9581727a..818b6d71 100644
--- a/extensions-builtin/sd_theme_editor/themes/d-230-52-94.css
+++ b/extensions-builtin/sd_theme_editor/themes/d-230-52-94.css
@@ -1 +1 @@
---main-bg-color:hsl(230deg 52% 4%);--primary-color:hsl(38deg 148% 36%);--input-bg-color:hsl(95deg 58% 7%);--input-border-color:hsl(84deg 57% 24%);--panel-bg-color:hsl(95deg 57% 11%);--panel-border-color:hsl(84deg 57% 24%);--panel-border-radius:0px;--subgroup-bg-color:hsl(230deg 52% 4%);--subgroup-input-bg-color:hsl(95deg 58% 7%);--subgroup-input-border-color:hsl(84deg 57% 24%);--subpanel-bg-color:hsl(90deg 56% 8%);--subpanel-border-color:hsl(84deg 57% 24%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(80deg 55% 30%);--input-focus-color:hsl(38deg 149% 35%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(230deg 136% 54%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(80deg 56% 74%);--icon-hover-color:hsl(230deg 52% 4%);--icon-size:22px;--nav-bg-color:hsl(230deg 52% 98%);--nav-color:hsl(80deg 56% 74%);--nav-hover-color:hsl(230deg 52% 98%);--input-color:hsl(80deg 56% 74%);--label-color:hsl(80deg 56% 74%);--subgroup-input-color:hsl(230deg 152% 94%);--placeholder-color:hsl(84deg 57% 24%);--text-color:hsl(80deg 56% 74%);--mobile-outside-gap-size:3px;--mobile-inside-padding-size:3px;--frame-bg-color:hsl(94deg 60% 7%);--modal-bg-color:hsl(229deg 52% 4%);--modal-icon-color:hsl(38deg 100% 36%);
\ No newline at end of file
+--ae-main-bg-color:hsl(230deg 52% 4%);--ae-primary-color:hsl(38deg 148% 36%);--ae-input-bg-color:hsl(95deg 58% 7%);--ae-input-border-color:hsl(84deg 57% 24%);--ae-panel-bg-color:hsl(95deg 57% 11%);--ae-panel-border-color:hsl(84deg 57% 24%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(230deg 52% 4%);--ae-subgroup-input-bg-color:hsl(95deg 58% 7%);--ae-subgroup-input-border-color:hsl(84deg 57% 24%);--ae-subpanel-bg-color:hsl(90deg 56% 8%);--ae-subpanel-border-color:hsl(84deg 57% 24%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(80deg 55% 30%);--ae-input-focus-color:hsl(38deg 149% 35%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(230deg 136% 54%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(80deg 56% 74%);--ae-icon-hover-color:hsl(230deg 52% 4%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(230deg 52% 98%);--ae-nav-color:hsl(80deg 56% 74%);--ae-nav-hover-color:hsl(230deg 52% 98%);--ae-input-color:hsl(80deg 56% 74%);--ae-label-color:hsl(80deg 56% 74%);--ae-subgroup-input-color:hsl(230deg 152% 94%);--ae-placeholder-color:hsl(84deg 57% 24%);--ae-text-color:hsl(80deg 56% 74%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(94deg 60% 7%);--ae-modal-bg-color:hsl(229deg 52% 4%);--ae-modal-icon-color:hsl(38deg 100% 36%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/default.css b/extensions-builtin/sd_theme_editor/themes/default.css
index 689a3f6c..b2131f91 100644
--- a/extensions-builtin/sd_theme_editor/themes/default.css
+++ b/extensions-builtin/sd_theme_editor/themes/default.css
@@ -1 +1 @@
---main-bg-color:hsl(0deg 0% 10%);--primary-color:hsl(168deg 97% 41%);--input-bg-color:hsl(225deg 6% 13%);--input-border-color:hsl(214deg 5% 30%);--panel-bg-color:hsl(225deg 5% 17%);--panel-border-color:hsl(214deg 5% 30%);--panel-border-radius:0px;--subgroup-bg-color:hsl(0deg 0% 10%);--subgroup-input-bg-color:hsl(225deg 6% 13%);--subgroup-input-border-color:hsl(214deg 5% 30%);--subpanel-bg-color:hsl(220deg 4% 14%);--subpanel-border-color:hsl(214deg 5% 30%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(210deg 3% 36%);--input-focus-color:hsl(168deg 97% 41%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(0deg 84% 60%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(168deg 97% 41%);--icon-hover-color:hsl(0deg 0% 10%);--icon-size:22px;--nav-bg-color:hsl(0deg 0% 4%);--nav-color:hsl(210deg 4% 80%);--nav-hover-color:hsl(0deg 0% 4%);--input-color:hsl(210deg 4% 80%);--label-color:hsl(210deg 4% 80%);--subgroup-input-color:hsl(0deg 0% 0%);--placeholder-color:hsl(214deg 5% 30%);--text-color:hsl(210deg 4% 80%);--mobile-outside-gap-size:2px;--mobile-inside-padding-size:2px;--frame-bg-color:hsl(225deg 6% 13%);--modal-bg-color:hsl(0deg 0% 10%);--modal-icon-color:hsl(168deg 97% 41%);
\ No newline at end of file
+--ae-main-bg-color:hsl(0deg 0% 10%);--ae-primary-color:hsl(168deg 97% 41%);--ae-input-bg-color:hsl(225deg 6% 13%);--ae-input-border-color:hsl(214deg 5% 30%);--ae-panel-bg-color:hsl(225deg 5% 17%);--ae-panel-border-color:hsl(214deg 5% 30%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(0deg 0% 10%);--ae-subgroup-input-bg-color:hsl(225deg 6% 13%);--ae-subgroup-input-border-color:hsl(214deg 5% 30%);--ae-subpanel-bg-color:hsl(220deg 4% 14%);--ae-subpanel-border-color:hsl(214deg 5% 30%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(168deg 97% 41%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(0deg 84% 60%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(168deg 97% 41%);--ae-icon-hover-color:hsl(0deg 0% 10%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(0deg 0% 4%);--ae-nav-color:hsl(210deg 4% 80%);--ae-nav-hover-color:hsl(0deg 0% 4%);--ae-input-color:hsl(210deg 4% 80%);--ae-label-color:hsl(210deg 4% 80%);--ae-subgroup-input-color:hsl(210deg 4% 80%);--ae-placeholder-color:hsl(214deg 5% 30%);--ae-text-color:hsl(210deg 4% 80%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(225deg 6% 13%);--ae-modal-bg-color:hsl(0deg 0% 10%);--ae-modal-icon-color:hsl(168deg 97% 41%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/default_cyan.css b/extensions-builtin/sd_theme_editor/themes/default_cyan.css
index 6d2bdf30..3c1b32cd 100644
--- a/extensions-builtin/sd_theme_editor/themes/default_cyan.css
+++ b/extensions-builtin/sd_theme_editor/themes/default_cyan.css
@@ -1 +1 @@
---main-bg-color:hsl(0deg 0% 10%);--primary-color:hsl(199deg 60% 60%);--input-bg-color:hsl(225deg 6% 13%);--input-border-color:hsl(214deg 5% 30%);--panel-bg-color:hsl(225deg 5% 17%);--panel-border-color:hsl(214deg 5% 30%);--panel-border-radius:0px;--subgroup-bg-color:hsl(0deg 0% 10%);--subgroup-input-bg-color:hsl(225deg 6% 13%);--subgroup-input-border-color:hsl(214deg 5% 30%);--subpanel-bg-color:hsl(220deg 4% 14%);--subpanel-border-color:hsl(214deg 5% 30%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(210deg 3% 36%);--input-focus-color:hsl(199deg 60% 60%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(357deg 50% 57%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(210deg 4% 80%);--icon-hover-color:hsl(0deg 0% 10%);--icon-size:22px;--nav-bg-color:hsl(0deg 0% 4%);--nav-color:hsl(210deg 4% 80%);--nav-hover-color:hsl(0deg 0% 4%);--input-color:hsl(210deg 4% 80%);--label-color:hsl(210deg 4% 80%);--subgroup-input-color:hsl(0deg 0% 0%);--placeholder-color:hsl(214deg 5% 30%);--text-color:hsl(210deg 4% 80%);--mobile-outside-gap-size:2px;--mobile-inside-padding-size:2px;--frame-bg-color:hsl(225deg 6% 13%);--modal-bg-color:hsl(0deg 0% 10%);--modal-icon-color:hsl(199deg 60% 60%);
\ No newline at end of file
+--ae-main-bg-color:hsl(0deg 0% 10%);--ae-primary-color:hsl(199deg 60% 60%);--ae-input-bg-color:hsl(225deg 6% 13%);--ae-input-border-color:hsl(214deg 5% 30%);--ae-panel-bg-color:hsl(225deg 5% 17%);--ae-panel-border-color:hsl(214deg 5% 30%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(0deg 0% 10%);--ae-subgroup-input-bg-color:hsl(225deg 6% 13%);--ae-subgroup-input-border-color:hsl(214deg 5% 30%);--ae-subpanel-bg-color:hsl(220deg 4% 14%);--ae-subpanel-border-color:hsl(214deg 5% 30%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(199deg 60% 60%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(357deg 50% 57%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(210deg 4% 80%);--ae-icon-hover-color:hsl(0deg 0% 10%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(0deg 0% 4%);--ae-nav-color:hsl(210deg 4% 80%);--ae-nav-hover-color:hsl(0deg 0% 4%);--ae-input-color:hsl(210deg 4% 80%);--ae-label-color:hsl(210deg 4% 80%);--ae-subgroup-input-color:hsl(210deg 4% 80%);--ae-placeholder-color:hsl(214deg 5% 30%);--ae-text-color:hsl(210deg 4% 80%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(225deg 6% 13%);--ae-modal-bg-color:hsl(0deg 0% 10%);--ae-modal-icon-color:hsl(199deg 60% 60%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/default_orange.css b/extensions-builtin/sd_theme_editor/themes/default_orange.css
index f89ea85a..736775be 100644
--- a/extensions-builtin/sd_theme_editor/themes/default_orange.css
+++ b/extensions-builtin/sd_theme_editor/themes/default_orange.css
@@ -1 +1 @@
---main-bg-color:hsl(0deg 0% 10%);--primary-color:hsl(16deg 77% 60%);--input-bg-color:hsl(225deg 6% 13%);--input-border-color:hsl(214deg 5% 30%);--panel-bg-color:hsl(225deg 5% 17%);--panel-border-color:hsl(214deg 5% 30%);--panel-border-radius:8px;--subgroup-bg-color:hsl(0deg 0% 10%);--subgroup-input-bg-color:hsl(225deg 6% 13%);--subgroup-input-border-color:hsl(214deg 5% 30%);--subpanel-bg-color:hsl(220deg 4% 14%);--subpanel-border-color:hsl(214deg 5% 30%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(210deg 3% 36%);--input-focus-color:hsl(16deg 77% 60%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(193deg 54% 55%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(210deg 4% 80%);--icon-hover-color:hsl(0deg 0% 10%);--icon-size:22px;--nav-bg-color:hsl(0deg 0% 4%);--nav-color:hsl(210deg 4% 80%);--nav-hover-color:hsl(0deg 0% 4%);--input-color:hsl(210deg 4% 80%);--label-color:hsl(210deg 4% 80%);--subgroup-input-color:hsl(0deg 0% 0%);--placeholder-color:hsl(214deg 5% 30%);--text-color:hsl(210deg 4% 80%);--mobile-outside-gap-size:2px;--mobile-inside-padding-size:2px;--frame-bg-color:hsl(225deg 6% 13%);--modal-bg-color:hsl(0deg 0% 10%);--modal-icon-color:hsl(16deg 77% 60%);
\ No newline at end of file
+--ae-main-bg-color:hsl(0deg 0% 10%);--ae-primary-color:hsl(16deg 77% 60%);--ae-input-bg-color:hsl(225deg 6% 13%);--ae-input-border-color:hsl(214deg 5% 30%);--ae-panel-bg-color:hsl(225deg 5% 17%);--ae-panel-border-color:hsl(214deg 5% 30%);--ae-panel-border-radius:8px;--ae-subgroup-bg-color:hsl(0deg 0% 10%);--ae-subgroup-input-bg-color:hsl(225deg 6% 13%);--ae-subgroup-input-border-color:hsl(214deg 5% 30%);--ae-subpanel-bg-color:hsl(220deg 4% 14%);--ae-subpanel-border-color:hsl(214deg 5% 30%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(16deg 77% 60%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(193deg 54% 55%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(210deg 4% 80%);--ae-icon-hover-color:hsl(0deg 0% 10%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(0deg 0% 4%);--ae-nav-color:hsl(210deg 4% 80%);--ae-nav-hover-color:hsl(0deg 0% 4%);--ae-input-color:hsl(210deg 4% 80%);--ae-label-color:hsl(210deg 4% 80%);--ae-subgroup-input-color:hsl(210deg 4% 80%);--ae-placeholder-color:hsl(214deg 5% 30%);--ae-text-color:hsl(210deg 4% 80%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(225deg 6% 13%);--ae-modal-bg-color:hsl(0deg 0% 10%);--ae-modal-icon-color:hsl(16deg 77% 60%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/fun.css b/extensions-builtin/sd_theme_editor/themes/fun.css
index 9c3ccdf2..23d77ece 100644
--- a/extensions-builtin/sd_theme_editor/themes/fun.css
+++ b/extensions-builtin/sd_theme_editor/themes/fun.css
@@ -1 +1 @@
---main-bg-color:hsl(253deg 22% 8%);--primary-color:hsl(76deg 96% 55%);--input-bg-color:hsl(260deg 25% 12%);--input-border-color:hsl(258deg 24% 32%);--panel-bg-color:hsl(258deg 24% 20%);--panel-border-color:hsl(258deg 24% 32%);--panel-border-radius:4px;--subgroup-bg-color:hsl(253deg 22% 8%);--subgroup-input-bg-color:hsl(258deg 24% 8%);--subgroup-input-border-color:hsl(258deg 24% 32%);--subpanel-bg-color:hsl(260deg 25% 12%);--subpanel-border-color:hsl(258deg 24% 32%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(210deg 3% 36%);--input-focus-color:hsl(296deg 96% 55%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(258deg 24% 32%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(259deg 24% 77%);--icon-hover-color:hsl(253deg 22% 8%);--icon-size:22px;--nav-bg-color:hsl(252deg 24% 4%);--nav-color:hsl(259deg 24% 77%);--nav-hover-color:hsl(252deg 24% 4%);--input-color:hsl(305deg 96% 55%);--label-color:hsl(259deg 24% 77%);--subgroup-input-color:hsl(0deg 100% 100%);--placeholder-color:hsl(258deg 24% 32%);--text-color:hsl(259deg 24% 77%);--mobile-outside-gap-size:2px;--mobile-inside-padding-size:2px;--frame-bg-color:hsl(260deg 25% 12%);--modal-bg-color:hsl(253deg 22% 8%);--modal-icon-color:hsl(76deg 96% 55%);
\ No newline at end of file
+--ae-main-bg-color:hsl(253deg 22% 8%);--ae-primary-color:hsl(76deg 96% 55%);--ae-input-bg-color:hsl(260deg 25% 12%);--ae-input-border-color:hsl(258deg 24% 32%);--ae-panel-bg-color:hsl(258deg 24% 20%);--ae-panel-border-color:hsl(258deg 24% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(253deg 22% 8%);--ae-subgroup-input-bg-color:hsl(258deg 24% 8%);--ae-subgroup-input-border-color:hsl(258deg 24% 32%);--ae-subpanel-bg-color:hsl(260deg 25% 12%);--ae-subpanel-border-color:hsl(258deg 24% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(296deg 96% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(258deg 24% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(259deg 24% 77%);--ae-icon-hover-color:hsl(253deg 22% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(252deg 24% 4%);--ae-nav-color:hsl(259deg 24% 77%);--ae-nav-hover-color:hsl(252deg 24% 4%);--ae-input-color:hsl(305deg 96% 55%);--ae-label-color:hsl(259deg 24% 77%);--ae-subgroup-input-color:hsl(76deg 96% 55%);--ae-placeholder-color:hsl(258deg 24% 32%);--ae-text-color:hsl(259deg 24% 77%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(260deg 25% 12%);--ae-modal-bg-color:hsl(253deg 22% 8%);--ae-modal-icon-color:hsl(76deg 96% 55%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/moonlight.css b/extensions-builtin/sd_theme_editor/themes/moonlight.css
index b6475d7c..4f70e44c 100644
--- a/extensions-builtin/sd_theme_editor/themes/moonlight.css
+++ b/extensions-builtin/sd_theme_editor/themes/moonlight.css
@@ -1 +1 @@
---main-bg-color:hsl(240deg 16% 6%);--primary-color:hsl(222deg 75% 62%);--input-bg-color:hsl(240deg 17% 8%);--input-border-color:hsl(240deg 20% 16%);--panel-bg-color:hsl(240deg 18% 12%);--panel-border-color:hsl(240deg 16% 16%);--panel-border-radius:0px;--subgroup-bg-color:hsl(240deg 17% 8%);--subgroup-input-bg-color:hsl(240deg 17% 8%);--subgroup-input-border-color:hsl(240deg 20% 16%);--subpanel-bg-color:hsl(240deg 18% 10%);--subpanel-border-color:hsl(240deg 20% 16%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(210deg 3% 36%);--input-focus-color:hsl(222deg 75% 62%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(222deg 75% 62%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(222deg 75% 62%);--icon-hover-color:hsl(240deg 18% 12%);--icon-size:22px;--nav-bg-color:hsl(240deg 16% 6%);--nav-color:hsl(185deg 66% 85%);--nav-hover-color:hsl(0deg 0% 4%);--input-color:hsl(185deg 66% 85%);--label-color:hsl(185deg 66% 85%);--subgroup-input-color:hsl(0deg 0% 0%);--placeholder-color:hsl(240deg 20% 24%);--text-color:hsl(185deg 66% 85%);--mobile-outside-gap-size:2px;--mobile-inside-padding-size:2px;--frame-bg-color:hsl(240deg 18% 10%);--modal-bg-color:hsl(240deg 16% 6%);--modal-icon-color:hsl(222deg 75% 62%);
\ No newline at end of file
+--ae-main-bg-color:hsl(240deg 16% 6%);--ae-primary-color:hsl(222deg 75% 62%);--ae-input-bg-color:hsl(240deg 17% 8%);--ae-input-border-color:hsl(240deg 20% 16%);--ae-panel-bg-color:hsl(240deg 18% 12%);--ae-panel-border-color:hsl(240deg 16% 16%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(240deg 17% 8%);--ae-subgroup-input-bg-color:hsl(240deg 17% 8%);--ae-subgroup-input-border-color:hsl(240deg 20% 16%);--ae-subpanel-bg-color:hsl(240deg 18% 10%);--ae-subpanel-border-color:hsl(240deg 20% 16%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(222deg 75% 62%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(222deg 75% 62%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(222deg 75% 62%);--ae-icon-hover-color:hsl(240deg 18% 12%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(240deg 16% 6%);--ae-nav-color:hsl(185deg 66% 85%);--ae-nav-hover-color:hsl(0deg 0% 4%);--ae-input-color:hsl(185deg 66% 85%);--ae-label-color:hsl(185deg 66% 85%);--ae-subgroup-input-color:hsl(185deg 66% 85%);--ae-placeholder-color:hsl(240deg 20% 24%);--ae-text-color:hsl(185deg 66% 85%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(240deg 18% 10%);--ae-modal-bg-color:hsl(240deg 16% 6%);--ae-modal-icon-color:hsl(222deg 75% 62%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/ogxBGreen.css b/extensions-builtin/sd_theme_editor/themes/ogxBGreen.css
index 91e2b61d..1e497888 100644
--- a/extensions-builtin/sd_theme_editor/themes/ogxBGreen.css
+++ b/extensions-builtin/sd_theme_editor/themes/ogxBGreen.css
@@ -1 +1 @@
---main-bg-color:hsl(195deg 22% 8%);--primary-color:hsl(159deg 96% 55%);--input-bg-color:hsl(202deg 25% 12%);--input-border-color:hsl(200deg 24% 32%);--panel-bg-color:hsl(200deg 24% 20%);--panel-border-color:hsl(200deg 24% 32%);--panel-border-radius:4px;--subgroup-bg-color:hsl(195deg 22% 8%);--subgroup-input-bg-color:hsl(200deg 24% 8%);--subgroup-input-border-color:hsl(200deg 24% 32%);--subpanel-bg-color:hsl(202deg 25% 12%);--subpanel-border-color:hsl(200deg 24% 32%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(152deg 3% 36%);--input-focus-color:hsl(159deg 96% 55%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(200deg 24% 32%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(159deg 96% 55%);--icon-hover-color:hsl(195deg 22% 8%);--icon-size:22px;--nav-bg-color:hsl(194deg 24% 4%);--nav-color:hsl(201deg 24% 77%);--nav-hover-color:hsl(194deg 24% 4%);--input-color:hsl(159deg 96% 55%);--label-color:hsl(201deg 24% 77%);--subgroup-input-color:hsl(302deg 100% 100%);--placeholder-color:hsl(200deg 24% 32%);--text-color:hsl(201deg 24% 77%);--mobile-outside-gap-size:3px;--mobile-inside-padding-size:3px;--frame-bg-color:hsl(200deg 25% 12%);--modal-bg-color:hsl(193deg 22% 8%);--modal-icon-color:hsl(159deg 96% 55%);
\ No newline at end of file
+--ae-main-bg-color:hsl(195deg 22% 8%);--ae-primary-color:hsl(159deg 96% 55%);--ae-input-bg-color:hsl(202deg 25% 12%);--ae-input-border-color:hsl(200deg 24% 32%);--ae-panel-bg-color:hsl(200deg 24% 20%);--ae-panel-border-color:hsl(200deg 24% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(195deg 22% 8%);--ae-subgroup-input-bg-color:hsl(200deg 24% 8%);--ae-subgroup-input-border-color:hsl(200deg 24% 32%);--ae-subpanel-bg-color:hsl(202deg 25% 12%);--ae-subpanel-border-color:hsl(200deg 24% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(152deg 3% 36%);--ae-input-focus-color:hsl(159deg 96% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(200deg 24% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(159deg 96% 55%);--ae-icon-hover-color:hsl(195deg 22% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(194deg 24% 4%);--ae-nav-color:hsl(201deg 24% 77%);--ae-nav-hover-color:hsl(194deg 24% 4%);--ae-input-color:hsl(159deg 96% 55%);--ae-label-color:hsl(201deg 24% 77%);--ae-subgroup-input-color:hsl(159deg 96% 55%);--ae-placeholder-color:hsl(200deg 24% 32%);--ae-text-color:hsl(201deg 24% 77%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(200deg 25% 12%);--ae-modal-bg-color:hsl(193deg 22% 8%);--ae-modal-icon-color:hsl(159deg 96% 55%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/ogxCyan.css b/extensions-builtin/sd_theme_editor/themes/ogxCyan.css
index ce92356a..3ca6e23c 100644
--- a/extensions-builtin/sd_theme_editor/themes/ogxCyan.css
+++ b/extensions-builtin/sd_theme_editor/themes/ogxCyan.css
@@ -1 +1 @@
---main-bg-color:hsl(253deg 22% 8%);--primary-color:hsl(198deg 96% 55%);--input-bg-color:hsl(260deg 25% 12%);--input-border-color:hsl(258deg 24% 32%);--panel-bg-color:hsl(258deg 24% 20%);--panel-border-color:hsl(258deg 24% 32%);--panel-border-radius:4px;--subgroup-bg-color:hsl(253deg 22% 8%);--subgroup-input-bg-color:hsl(258deg 24% 8%);--subgroup-input-border-color:hsl(258deg 24% 32%);--subpanel-bg-color:hsl(260deg 25% 12%);--subpanel-border-color:hsl(258deg 24% 32%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(210deg 3% 36%);--input-focus-color:hsl(198deg 96% 55%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(258deg 24% 32%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(259deg 24% 77%);--icon-hover-color:hsl(253deg 22% 8%);--icon-size:22px;--nav-bg-color:hsl(252deg 24% 4%);--nav-color:hsl(259deg 24% 77%);--nav-hover-color:hsl(252deg 24% 4%);--input-color:hsl(198deg 96% 55%);--label-color:hsl(259deg 24% 77%);--subgroup-input-color:hsl(0deg 100% 100%);--placeholder-color:hsl(258deg 24% 32%);--text-color:hsl(259deg 24% 77%);--mobile-outside-gap-size:2px;--mobile-inside-padding-size:2px;--frame-bg-color:hsl(260deg 25% 12%);--modal-bg-color:hsl(253deg 22% 8%);--modal-icon-color:hsl(198deg 96% 55%);
\ No newline at end of file
+--ae-main-bg-color:hsl(253deg 22% 8%);--ae-primary-color:hsl(198deg 96% 55%);--ae-input-bg-color:hsl(260deg 25% 12%);--ae-input-border-color:hsl(258deg 24% 32%);--ae-panel-bg-color:hsl(258deg 24% 20%);--ae-panel-border-color:hsl(258deg 24% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(253deg 22% 8%);--ae-subgroup-input-bg-color:hsl(258deg 24% 8%);--ae-subgroup-input-border-color:hsl(258deg 24% 32%);--ae-subpanel-bg-color:hsl(260deg 25% 12%);--ae-subpanel-border-color:hsl(258deg 24% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(198deg 96% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(258deg 24% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(259deg 24% 77%);--ae-icon-hover-color:hsl(253deg 22% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(252deg 24% 4%);--ae-nav-color:hsl(259deg 24% 77%);--ae-nav-hover-color:hsl(252deg 24% 4%);--ae-input-color:hsl(198deg 96% 55%);--ae-label-color:hsl(259deg 24% 77%);--ae-subgroup-input-color:hsl(198deg 96% 55%);--ae-placeholder-color:hsl(258deg 24% 32%);--ae-text-color:hsl(259deg 24% 77%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(260deg 25% 12%);--ae-modal-bg-color:hsl(253deg 22% 8%);--ae-modal-icon-color:hsl(198deg 96% 55%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/ogxCyanInvert.css b/extensions-builtin/sd_theme_editor/themes/ogxCyanInvert.css
index 59f25474..02b04e2d 100644
--- a/extensions-builtin/sd_theme_editor/themes/ogxCyanInvert.css
+++ b/extensions-builtin/sd_theme_editor/themes/ogxCyanInvert.css
@@ -1 +1 @@
---main-bg-color:hsl(73deg 22% 92%);--primary-color:hsl(18deg 96% 45%);--input-bg-color:hsl(80deg 25% 88%);--input-border-color:hsl(78deg 24% 68%);--panel-bg-color:hsl(78deg 24% 80%);--panel-border-color:hsl(78deg 24% 68%);--panel-border-radius:4px;--subgroup-bg-color:hsl(73deg 22% 92%);--subgroup-input-bg-color:hsl(73deg 22% 92%);--subgroup-input-border-color:hsl(78deg 24% 68%);--subpanel-bg-color:hsl(80deg 25% 88%);--subpanel-border-color:hsl(78deg 24% 68%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(30deg 3% 64%);--input-focus-color:hsl(18deg 96% 45%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(78deg 24% 68%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(79deg 24% 23%);--icon-hover-color:hsl(73deg 22% 92%);--icon-size:22px;--nav-bg-color:hsl(72deg 24% 96%);--nav-color:hsl(79deg 24% 23%);--nav-hover-color:hsl(72deg 24% 96%);--input-color:hsl(18deg 96% 45%);--label-color:hsl(79deg 24% 23%);--subgroup-input-color:hsl(0deg 0% 0%);--placeholder-color:hsl(78deg 24% 68%);--text-color:hsl(79deg 24% 23%);--mobile-outside-gap-size:2px;--mobile-inside-padding-size:2px;--frame-bg-color:hsl(80deg 25% 88%);--modal-bg-color:hsl(73deg 22% 92%);--modal-icon-color:hsl(18deg 96% 45%);
\ No newline at end of file
+--ae-main-bg-color:hsl(73deg 22% 92%);--ae-primary-color:hsl(18deg 96% 45%);--ae-input-bg-color:hsl(80deg 25% 88%);--ae-input-border-color:hsl(78deg 24% 68%);--ae-panel-bg-color:hsl(78deg 24% 80%);--ae-panel-border-color:hsl(78deg 24% 68%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(73deg 22% 92%);--ae-subgroup-input-bg-color:hsl(73deg 22% 92%);--ae-subgroup-input-border-color:hsl(78deg 24% 68%);--ae-subpanel-bg-color:hsl(80deg 25% 88%);--ae-subpanel-border-color:hsl(78deg 24% 68%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(30deg 3% 64%);--ae-input-focus-color:hsl(18deg 96% 45%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(78deg 24% 68%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(79deg 24% 23%);--ae-icon-hover-color:hsl(73deg 22% 92%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(72deg 24% 96%);--ae-nav-color:hsl(79deg 24% 23%);--ae-nav-hover-color:hsl(72deg 24% 96%);--ae-input-color:hsl(18deg 96% 45%);--ae-label-color:hsl(79deg 24% 23%);--ae-subgroup-input-color:hsl(18deg 96% 45%);--ae-placeholder-color:hsl(78deg 24% 68%);--ae-text-color:hsl(79deg 24% 23%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(80deg 25% 88%);--ae-modal-bg-color:hsl(73deg 22% 92%);--ae-modal-icon-color:hsl(18deg 96% 45%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/ogxGreen.css b/extensions-builtin/sd_theme_editor/themes/ogxGreen.css
index fb461390..077e55e7 100644
--- a/extensions-builtin/sd_theme_editor/themes/ogxGreen.css
+++ b/extensions-builtin/sd_theme_editor/themes/ogxGreen.css
@@ -1 +1 @@
---main-bg-color:hsl(253deg 22% 8%);--primary-color:hsl(149deg 96% 55%);--input-bg-color:hsl(260deg 25% 12%);--input-border-color:hsl(258deg 24% 32%);--panel-bg-color:hsl(258deg 24% 20%);--panel-border-color:hsl(258deg 24% 32%);--panel-border-radius:4px;--subgroup-bg-color:hsl(253deg 22% 8%);--subgroup-input-bg-color:hsl(258deg 24% 8%);--subgroup-input-border-color:hsl(258deg 24% 32%);--subpanel-bg-color:hsl(260deg 25% 12%);--subpanel-border-color:hsl(258deg 24% 32%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(210deg 3% 36%);--input-focus-color:hsl(149deg 96% 55%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(258deg 24% 32%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(259deg 24% 77%);--icon-hover-color:hsl(253deg 22% 8%);--icon-size:22px;--nav-bg-color:hsl(252deg 24% 4%);--nav-color:hsl(259deg 24% 77%);--nav-hover-color:hsl(252deg 24% 4%);--input-color:hsl(149deg 96% 55%);--label-color:hsl(259deg 24% 77%);--subgroup-input-color:hsl(0deg 100% 100%);--placeholder-color:hsl(258deg 24% 32%);--text-color:hsl(259deg 24% 77%);--mobile-outside-gap-size:3px;--mobile-inside-padding-size:3px;--frame-bg-color:hsl(260deg 25% 12%);--modal-bg-color:hsl(253deg 22% 8%);--modal-icon-color:hsl(253deg 22% 8%);
\ No newline at end of file
+--ae-main-bg-color:hsl(253deg 22% 8%);--ae-primary-color:hsl(149deg 96% 55%);--ae-input-bg-color:hsl(260deg 25% 12%);--ae-input-border-color:hsl(258deg 24% 32%);--ae-panel-bg-color:hsl(258deg 24% 20%);--ae-panel-border-color:hsl(258deg 24% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(253deg 22% 8%);--ae-subgroup-input-bg-color:hsl(258deg 24% 8%);--ae-subgroup-input-border-color:hsl(258deg 24% 32%);--ae-subpanel-bg-color:hsl(260deg 25% 12%);--ae-subpanel-border-color:hsl(258deg 24% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(149deg 96% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(258deg 24% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(259deg 24% 77%);--ae-icon-hover-color:hsl(253deg 22% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(252deg 24% 4%);--ae-nav-color:hsl(259deg 24% 77%);--ae-nav-hover-color:hsl(252deg 24% 4%);--ae-input-color:hsl(149deg 96% 55%);--ae-label-color:hsl(259deg 24% 77%);--ae-subgroup-input-color:hsl(149deg 96% 55%);--ae-placeholder-color:hsl(258deg 24% 32%);--ae-text-color:hsl(259deg 24% 77%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(260deg 25% 12%);--ae-modal-bg-color:hsl(253deg 22% 8%);--ae-modal-icon-color:hsl(253deg 22% 8%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/ogxRed.css b/extensions-builtin/sd_theme_editor/themes/ogxRed.css
index 09fa35a6..3d7d86a1 100644
--- a/extensions-builtin/sd_theme_editor/themes/ogxRed.css
+++ b/extensions-builtin/sd_theme_editor/themes/ogxRed.css
@@ -1 +1 @@
---main-bg-color:hsl(253deg 22% 8%);--primary-color:hsl(347deg 96% 55%);--input-bg-color:hsl(260deg 25% 12%);--input-border-color:hsl(258deg 24% 32%);--panel-bg-color:hsl(258deg 24% 20%);--panel-border-color:hsl(258deg 24% 32%);--panel-border-radius:4px;--subgroup-bg-color:hsl(253deg 22% 8%);--subgroup-input-bg-color:hsl(258deg 24% 8%);--subgroup-input-border-color:hsl(258deg 24% 32%);--subpanel-bg-color:hsl(260deg 25% 12%);--subpanel-border-color:hsl(258deg 24% 32%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(210deg 3% 36%);--input-focus-color:hsl(347deg 96% 55%);--outside-gap-size:8px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(258deg 24% 32%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(259deg 24% 77%);--icon-hover-color:hsl(253deg 22% 8%);--icon-size:22px;--nav-bg-color:hsl(252deg 24% 4%);--nav-color:hsl(259deg 24% 77%);--nav-hover-color:hsl(252deg 24% 4%);--input-color:hsl(347deg 96% 55%);--label-color:hsl(259deg 24% 77%);--subgroup-input-color:hsl(0deg 100% 100%);--placeholder-color:hsl(258deg 24% 32%);--text-color:hsl(259deg 24% 77%);--mobile-outside-gap-size:3px;--mobile-inside-padding-size:3px;--frame-bg-color:hsl(260deg 25% 12%);--modal-bg-color:hsl(253deg 22% 8%);--modal-icon-color:hsl(347deg 96% 55%);
\ No newline at end of file
+--ae-main-bg-color:hsl(253deg 22% 8%);--ae-primary-color:hsl(347deg 96% 55%);--ae-input-bg-color:hsl(260deg 25% 12%);--ae-input-border-color:hsl(258deg 24% 32%);--ae-panel-bg-color:hsl(258deg 24% 20%);--ae-panel-border-color:hsl(258deg 24% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(253deg 22% 8%);--ae-subgroup-input-bg-color:hsl(258deg 24% 8%);--ae-subgroup-input-border-color:hsl(258deg 24% 32%);--ae-subpanel-bg-color:hsl(260deg 25% 12%);--ae-subpanel-border-color:hsl(258deg 24% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(347deg 96% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(258deg 24% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(259deg 24% 77%);--ae-icon-hover-color:hsl(253deg 22% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(252deg 24% 4%);--ae-nav-color:hsl(259deg 24% 77%);--ae-nav-hover-color:hsl(252deg 24% 4%);--ae-input-color:hsl(347deg 96% 55%);--ae-label-color:hsl(259deg 24% 77%);--ae-subgroup-input-color:hsl(347deg 96% 55%);--ae-placeholder-color:hsl(258deg 24% 32%);--ae-text-color:hsl(259deg 24% 77%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(260deg 25% 12%);--ae-modal-bg-color:hsl(253deg 22% 8%);--ae-modal-icon-color:hsl(347deg 96% 55%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/retrog.css b/extensions-builtin/sd_theme_editor/themes/retrog.css
index cd1271c9..54839175 100644
--- a/extensions-builtin/sd_theme_editor/themes/retrog.css
+++ b/extensions-builtin/sd_theme_editor/themes/retrog.css
@@ -1 +1 @@
---main-bg-color:hsl(197deg 97% 14%);--primary-color:hsl(27deg 99% 50%);--input-bg-color:hsl(197deg 98% 16%);--input-border-color:hsl(166deg 62% 33%);--panel-bg-color:hsl(196deg 98% 18%);--panel-border-color:hsl(166deg 62% 33%);--panel-border-radius:0px;--subgroup-bg-color:hsl(197deg 97% 14%);--subgroup-input-bg-color:hsl(197deg 97% 14%);--subgroup-input-border-color:hsl(166deg 62% 33%);--subpanel-bg-color:hsl(197deg 98% 16%);--subpanel-border-color:hsl(166deg 62% 33%);--subpanel-border-radius:8px;--textarea-focus-color:hsl(210deg 3% 36%);--input-focus-color:hsl(222deg 75% 62%);--outside-gap-size:6px;--inside-padding-size:6px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(70deg 69% 54%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(27deg 99% 50%);--icon-hover-color:hsl(196deg 98% 18%);--icon-size:22px;--nav-bg-color:hsl(197deg 97% 14%);--nav-color:hsl(70deg 69% 54%);--nav-hover-color:hsl(197deg 97% 14%);--input-color:hsl(70deg 69% 54%);--label-color:hsl(70deg 69% 54%);--subgroup-input-color:hsl(27deg 99% 50%);--placeholder-color:hsl(166deg 62% 33%);--text-color:hsl(185deg 66% 85%);--mobile-outside-gap-size:3px;--mobile-inside-padding-size:3px;--frame-bg-color:hsl(197deg 98% 16%);--modal-bg-color:hsl(197deg 97% 14%);--modal-icon-color:hsl(27deg 99% 50%);
\ No newline at end of file
+--ae-main-bg-color:hsl(197deg 97% 14%);--ae-primary-color:hsl(27deg 99% 50%);--ae-input-bg-color:hsl(197deg 98% 16%);--ae-input-border-color:hsl(166deg 62% 33%);--ae-panel-bg-color:hsl(196deg 98% 18%);--ae-panel-border-color:hsl(166deg 62% 33%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(197deg 97% 14%);--ae-subgroup-input-bg-color:hsl(197deg 97% 14%);--ae-subgroup-input-border-color:hsl(166deg 62% 33%);--ae-subpanel-bg-color:hsl(197deg 98% 16%);--ae-subpanel-border-color:hsl(166deg 62% 33%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(222deg 75% 62%);--ae-outside-gap-size:6px;--ae-inside-padding-size:6px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(70deg 69% 54%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(27deg 99% 50%);--ae-icon-hover-color:hsl(196deg 98% 18%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(197deg 97% 14%);--ae-nav-color:hsl(70deg 69% 54%);--ae-nav-hover-color:hsl(197deg 97% 14%);--ae-input-color:hsl(70deg 69% 54%);--ae-label-color:hsl(70deg 69% 54%);--ae-subgroup-input-color:hsl(27deg 99% 50%);--ae-placeholder-color:hsl(166deg 62% 33%);--ae-text-color:hsl(185deg 66% 85%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(197deg 98% 16%);--ae-modal-bg-color:hsl(197deg 97% 14%);--ae-modal-icon-color:hsl(27deg 99% 50%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/tron.css b/extensions-builtin/sd_theme_editor/themes/tron.css
index 10b84eb3..65c3248a 100644
--- a/extensions-builtin/sd_theme_editor/themes/tron.css
+++ b/extensions-builtin/sd_theme_editor/themes/tron.css
@@ -1 +1 @@
---main-bg-color:hsl(185deg 75% 3%);--primary-color:hsl(182deg 95% 51%);--input-bg-color:hsl(185deg 73% 3%);--input-border-color:hsl(185deg 72% 25%);--panel-bg-color:hsl(180deg 76% 5%);--panel-border-color:hsl(185deg 72% 25%);--panel-border-radius:0px;--subgroup-bg-color:hsl(185deg 73% 3%);--subgroup-input-bg-color:hsl(185deg 73% 3%);--subgroup-input-border-color:hsl(185deg 72% 25%);--subpanel-bg-color:hsl(185deg 73% 3%);--subpanel-border-color:hsl(185deg 72% 25%);--subpanel-border-radius:0px;--textarea-focus-color:hsl(182deg 95% 51%);--input-focus-color:hsl(182deg 95% 51%);--outside-gap-size:2px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(182deg 95% 51%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(182deg 95% 51%);--icon-hover-color:hsl(185deg 73% 3%);--icon-size:22px;--nav-bg-color:hsl(185deg 73% 3%);--nav-color:hsl(182deg 95% 75%);--nav-hover-color:hsl(0deg 100% 50%);--input-color:hsl(182deg 95% 75%);--label-color:hsl(182deg 95% 75%);--subgroup-input-color:hsl(182deg 95% 51%);--placeholder-color:hsl(185deg 72% 25%);--text-color:hsl(182deg 95% 75%);--mobile-outside-gap-size:2px;--mobile-inside-padding-size:8px;--frame-bg-color:hsl(180deg 76% 5%);--modal-bg-color:hsl(185deg 73% 3%);--modal-icon-color:hsl(182deg 95% 51%);
\ No newline at end of file
+--ae-main-bg-color:hsl(185deg 75% 3%);--ae-primary-color:hsl(182deg 95% 51%);--ae-input-bg-color:hsl(185deg 73% 3%);--ae-input-border-color:hsl(185deg 72% 25%);--ae-panel-bg-color:hsl(180deg 76% 5%);--ae-panel-border-color:hsl(185deg 72% 25%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(185deg 73% 3%);--ae-subgroup-input-bg-color:hsl(185deg 73% 3%);--ae-subgroup-input-border-color:hsl(185deg 72% 25%);--ae-subpanel-bg-color:hsl(185deg 73% 3%);--ae-subpanel-border-color:hsl(185deg 72% 25%);--ae-subpanel-border-radius:0px;--ae-textarea-focus-color:hsl(182deg 95% 51%);--ae-input-focus-color:hsl(182deg 95% 51%);--ae-outside-gap-size:2px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(182deg 95% 51%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(182deg 95% 51%);--ae-icon-hover-color:hsl(185deg 73% 3%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(185deg 73% 3%);--ae-nav-color:hsl(182deg 95% 75%);--ae-nav-hover-color:hsl(0deg 100% 50%);--ae-input-color:hsl(182deg 95% 75%);--ae-label-color:hsl(182deg 95% 75%);--ae-subgroup-input-color:hsl(182deg 95% 51%);--ae-placeholder-color:hsl(185deg 72% 25%);--ae-text-color:hsl(182deg 95% 75%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:8px;--ae-frame-bg-color:hsl(180deg 76% 5%);--ae-modal-bg-color:hsl(185deg 73% 3%);--ae-modal-icon-color:hsl(182deg 95% 51%);
\ No newline at end of file
diff --git a/extensions-builtin/sd_theme_editor/themes/tron2.css b/extensions-builtin/sd_theme_editor/themes/tron2.css
index 1b0bf40c..98eeacbc 100644
--- a/extensions-builtin/sd_theme_editor/themes/tron2.css
+++ b/extensions-builtin/sd_theme_editor/themes/tron2.css
@@ -1 +1 @@
---main-bg-color:hsl(185deg 75% 3%);--primary-color:hsl(182deg 95% 51%);--input-bg-color:hsl(184deg 89% 7%);--input-border-color:hsl(185deg 72% 25%);--panel-bg-color:hsl(185deg 73% 3%);--panel-border-color:hsl(185deg 72% 25%);--panel-border-radius:0px;--subgroup-bg-color:hsl(185deg 73% 3%);--subgroup-input-bg-color:hsl(185deg 73% 3%);--subgroup-input-border-color:hsl(185deg 72% 25%);--subpanel-bg-color:hsl(185deg 73% 3%);--subpanel-border-color:hsl(185deg 72% 25%);--subpanel-border-radius:0px;--textarea-focus-color:hsl(182deg 95% 51%);--input-focus-color:hsl(182deg 95% 51%);--outside-gap-size:2px;--inside-padding-size:8px;--tool-button-size:34px;--tool-button-radius:16px;--generate-button-height:70px;--cancel-color:hsl(182deg 95% 51%);--max-padding:max(var(--outside-gap-size),var(--inside-padding-size));--icon-color:hsl(182deg 95% 51%);--icon-hover-color:hsl(185deg 73% 3%);--icon-size:22px;--nav-bg-color:hsl(185deg 73% 3%);--nav-color:hsl(182deg 95% 75%);--nav-hover-color:hsl(0deg 100% 50%);--input-color:hsl(182deg 95% 75%);--label-color:hsl(182deg 95% 75%);--subgroup-input-color:hsl(182deg 95% 51%);--placeholder-color:hsl(185deg 72% 25%);--text-color:hsl(182deg 95% 75%);--mobile-outside-gap-size:2px;--mobile-inside-padding-size:8px;--frame-bg-color:hsl(185deg 73% 3%);
\ No newline at end of file
+--ae-main-bg-color:hsl(185deg 75% 3%);--ae-primary-color:hsl(182deg 95% 51%);--ae-input-bg-color:hsl(184deg 89% 7%);--ae-input-border-color:hsl(185deg 72% 25%);--ae-panel-bg-color:hsl(185deg 73% 3%);--ae-panel-border-color:hsl(185deg 72% 25%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(185deg 73% 3%);--ae-subgroup-input-bg-color:hsl(185deg 73% 3%);--ae-subgroup-input-border-color:hsl(185deg 72% 25%);--ae-subpanel-bg-color:hsl(185deg 73% 3%);--ae-subpanel-border-color:hsl(185deg 72% 25%);--ae-subpanel-border-radius:0px;--ae-textarea-focus-color:hsl(182deg 95% 51%);--ae-input-focus-color:hsl(182deg 95% 51%);--ae-outside-gap-size:2px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(182deg 95% 51%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(182deg 95% 51%);--ae-icon-hover-color:hsl(185deg 73% 3%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(185deg 73% 3%);--ae-nav-color:hsl(182deg 95% 75%);--ae-nav-hover-color:hsl(0deg 100% 50%);--ae-input-color:hsl(182deg 95% 75%);--ae-label-color:hsl(182deg 95% 75%);--ae-subgroup-input-color:hsl(182deg 95% 51%);--ae-placeholder-color:hsl(185deg 72% 25%);--ae-text-color:hsl(182deg 95% 75%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:8px;--ae-frame-bg-color:hsl(185deg 73% 3%);
\ No newline at end of file
diff --git a/html/extra-networks-card.html b/html/extra-networks-card.html
index a148dfeb..6ce38fcb 100644
--- a/html/extra-networks-card.html
+++ b/html/extra-networks-card.html
@@ -10,8 +10,6 @@
{name}
-
-
{description}
diff --git a/html/footer.html b/html/footer.html
index 80d95191..50921614 100644
--- a/html/footer.html
+++ b/html/footer.html
@@ -1,6 +1,5 @@
-
-
-
+
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/html/licenses.html b/html/licenses.html
index bddbf466..bc995aa0 100644
--- a/html/licenses.html
+++ b/html/licenses.html
@@ -635,4 +635,30 @@ SOFTWARE.
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+
+
+
+The MPS workaround for nn.Linear on macOS 13.2.X is based on the MPS workaround for nn.Linear created by danieldk for Curated transformers
+
+The MIT License (MIT)
+
+Copyright (C) 2021 ExplosionAI GmbH
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/javascript/aspectRatioOverlay.js b/javascript/aspectRatioOverlay.js
index 0f164b82..a8278cca 100644
--- a/javascript/aspectRatioOverlay.js
+++ b/javascript/aspectRatioOverlay.js
@@ -12,7 +12,7 @@ function dimensionChange(e, is_width, is_height){
currentHeight = e.target.value*1.0
}
- var inImg2img = Boolean(gradioApp().querySelector("button.rounded-t-lg.border-gray-200"))
+ var inImg2img = gradioApp().querySelector("#tab_img2img").style.display == "block";
if(!inImg2img){
return;
@@ -22,7 +22,7 @@ function dimensionChange(e, is_width, is_height){
var tabIndex = get_tab_index('mode_img2img')
if(tabIndex == 0){ // img2img
- targetElement = gradioApp().querySelector('div[data-testid=image] img');
+ targetElement = gradioApp().querySelector('#img2img_image div[data-testid=image] img');
} else if(tabIndex == 1){ //Sketch
targetElement = gradioApp().querySelector('#img2img_sketch div[data-testid=image] img');
} else if(tabIndex == 2){ // Inpaint
@@ -30,7 +30,7 @@ function dimensionChange(e, is_width, is_height){
} else if(tabIndex == 3){ // Inpaint sketch
targetElement = gradioApp().querySelector('#inpaint_sketch div[data-testid=image] img');
}
-
+
if(targetElement){
@@ -38,7 +38,7 @@ function dimensionChange(e, is_width, is_height){
if(!arPreviewRect){
arPreviewRect = document.createElement('div')
arPreviewRect.id = "imageARPreview";
- gradioApp().getRootNode().appendChild(arPreviewRect)
+ gradioApp().appendChild(arPreviewRect)
}
@@ -91,23 +91,26 @@ onUiUpdate(function(){
if(arPreviewRect){
arPreviewRect.style.display = 'none';
}
- var inImg2img = Boolean(gradioApp().querySelector("button.rounded-t-lg.border-gray-200"))
- if(inImg2img){
- let inputs = gradioApp().querySelectorAll('input');
- inputs.forEach(function(e){
- var is_width = e.parentElement.id == "img2img_width"
- var is_height = e.parentElement.id == "img2img_height"
+ var tabImg2img = gradioApp().querySelector("#tab_img2img");
+ if (tabImg2img) {
+ var inImg2img = tabImg2img.style.display == "block";
+ if(inImg2img){
+ let inputs = gradioApp().querySelectorAll('input');
+ inputs.forEach(function(e){
+ var is_width = e.parentElement.id == "img2img_width"
+ var is_height = e.parentElement.id == "img2img_height"
- if((is_width || is_height) && !e.classList.contains('scrollwatch')){
- e.addEventListener('input', function(e){dimensionChange(e, is_width, is_height)} )
- e.classList.add('scrollwatch')
- }
- if(is_width){
- currentWidth = e.value*1.0
- }
- if(is_height){
- currentHeight = e.value*1.0
- }
- })
- }
+ if((is_width || is_height) && !e.classList.contains('scrollwatch')){
+ e.addEventListener('input', function(e){dimensionChange(e, is_width, is_height)} )
+ e.classList.add('scrollwatch')
+ }
+ if(is_width){
+ currentWidth = e.value*1.0
+ }
+ if(is_height){
+ currentHeight = e.value*1.0
+ }
+ })
+ }
+ }
});
diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js
index 11bcce1b..06f505b0 100644
--- a/javascript/contextMenus.js
+++ b/javascript/contextMenus.js
@@ -43,7 +43,7 @@ contextMenuInit = function(){
})
- gradioApp().getRootNode().appendChild(contextMenu)
+ gradioApp().appendChild(contextMenu)
let menuWidth = contextMenu.offsetWidth + 4;
let menuHeight = contextMenu.offsetHeight + 4;
diff --git a/javascript/dragdrop.js b/javascript/dragdrop.js
index fe008924..0450cecb 100644
--- a/javascript/dragdrop.js
+++ b/javascript/dragdrop.js
@@ -11,7 +11,7 @@ function dropReplaceImage( imgWrap, files ) {
const tmpFile = files[0];
- imgWrap.querySelector('.modify-upload button + button, .touch-none + div button + button')?.click();
+ imgWrap.querySelector('[aria-label="Clear"]')?.click();
const callback = () => {
const fileInput = imgWrap.querySelector('input[type="file"]');
if ( fileInput ) {
diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js
index 619bb1fa..20a5aadf 100644
--- a/javascript/edit-attention.js
+++ b/javascript/edit-attention.js
@@ -1,6 +1,6 @@
function keyupEditAttention(event){
let target = event.originalTarget || event.composedPath()[0];
- if (!target.matches("[id*='_toprow'] textarea.gr-text-input[placeholder]")) return;
+ if (! target.matches("[id*='_toprow'] [id*='_prompt'] textarea")) return;
if (! (event.metaKey || event.ctrlKey)) return;
let isPlus = event.key == "ArrowUp"
diff --git a/javascript/extensions.js b/javascript/extensions.js
index c593cd2e..72924a28 100644
--- a/javascript/extensions.js
+++ b/javascript/extensions.js
@@ -1,5 +1,5 @@
-function extensions_apply(_, _){
+function extensions_apply(_, _, disable_all){
var disable = []
var update = []
@@ -13,10 +13,10 @@ function extensions_apply(_, _){
restart_reload()
- return [JSON.stringify(disable), JSON.stringify(update)]
+ return [JSON.stringify(disable), JSON.stringify(update), disable_all]
}
-function extensions_check(){
+function extensions_check(_, _){
var disable = []
gradioApp().querySelectorAll('#extensions input[type="checkbox"]').forEach(function(x){
diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js
index c0973394..7bb517fb 100644
--- a/javascript/extraNetworks.js
+++ b/javascript/extraNetworks.js
@@ -21,13 +21,13 @@ function setupExtraNetworksForTab(tabname){
search.value = "";
updateInput(search);
})
-
- search.addEventListener("input", function(evt){
+
+ search.addEventListener("input", function(evt){
searchTerm = search.value.toLowerCase()
gradioApp().querySelectorAll('#'+tabname+'_extra_tabs div.card').forEach(function(elem){
- text = elem.querySelector('.name').textContent.toLowerCase() + " " + elem.querySelector('.search_term').textContent.toLowerCase();
- elem.parentElement.style.display = text.indexOf(searchTerm) == -1 ? "none" : "";
+ text = elem.querySelector('.name').textContent.toLowerCase() + " " + elem.querySelector('.search_term').textContent.toLowerCase()
+ elem.parentElement.style.display = text.indexOf(searchTerm) == -1 ? "none" : ""
})
});
}
@@ -110,7 +110,9 @@ function saveCardPreview(event, tabname, filename){
function extraNetworksSearchButton(tabs_id, event){
searchTextarea = gradioApp().querySelector("#" + tabs_id + ' > div > textarea')
button = event.target
- text = button.classList.contains("search-all") ? "" : button.textContent.trim()
+ text = button.classList.contains("search-all") ? "" : button.textContent.trim()
+ //text = event.target.selectedIndex == 0 ? "" : event.target.options[event.target.selectedIndex].text;
+
searchTextarea.value = text
updateInput(searchTextarea)
}
@@ -150,3 +152,41 @@ function extraNetworksShowMetadata(text){
popup(elem);
}
+
+function requestGet(url, data, handler, errorHandler){
+ var xhr = new XMLHttpRequest();
+ var args = Object.keys(data).map(function(k){ return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]) }).join('&')
+ xhr.open("GET", url + "?" + args, true);
+
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200) {
+ try {
+ var js = JSON.parse(xhr.responseText);
+ handler(js)
+ } catch (error) {
+ console.error(error);
+ errorHandler()
+ }
+ } else{
+ errorHandler()
+ }
+ }
+ };
+ var js = JSON.stringify(data);
+ xhr.send(js);
+}
+
+function extraNetworksRequestMetadata(event, extraPage, cardName){
+ showError = function(){ extraNetworksShowMetadata("there was an error getting metadata"); }
+
+ requestGet("./sd_extra_networks/metadata", {"page": extraPage, "item": cardName}, function(data){
+ if(data && data.metadata){
+ extraNetworksShowMetadata(data.metadata)
+ } else{
+ showError()
+ }
+ }, showError)
+
+ event.stopPropagation()
+}
diff --git a/javascript/generationParams.js b/javascript/generationParams.js
index 545e81c0..f12f270c 100644
--- a/javascript/generationParams.js
+++ b/javascript/generationParams.js
@@ -18,15 +18,15 @@ onUiUpdate(function(){
let modalObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutationRecord) {
- let selectedTab = gradioApp().querySelector('#tabs div button.bg-white')?.innerText
- if (mutationRecord.target.style.display === 'none' && selectedTab === 'txt2img' || selectedTab === 'img2img')
- gradioApp().getElementById(selectedTab+"_generation_info_button").click()
+ let selectedTab = gradioApp().querySelector('#tabs div button.selected')?.innerText
+ if (mutationRecord.target.style.display === 'none' && (selectedTab === 'txt2img' || selectedTab === 'img2img'))
+ gradioApp().getElementById(selectedTab+"_generation_info_button")?.click()
});
});
function attachGalleryListeners(tab_name) {
gallery = gradioApp().querySelector('#'+tab_name+'_gallery')
- gallery?.addEventListener('click', () => gradioApp().getElementById(tab_name+"_generation_info_button").click());
+ gallery?.addEventListener('click', () => gradioApp().getElementById(tab_name+"_generation_info_button")?.click());
gallery?.addEventListener('keydown', (e) => {
if (e.keyCode == 37 || e.keyCode == 39) // left or right arrow
gradioApp().getElementById(tab_name+"_generation_info_button").click()
diff --git a/javascript/hints.js b/javascript/hints.js
index bbad7d77..4cfe793e 100644
--- a/javascript/hints.js
+++ b/javascript/hints.js
@@ -18,13 +18,12 @@ titles = {
"\u2199\ufe0f": "Read generation parameters from prompt or last generation if prompt is empty into user interface.",
"\u{1f4c2}": "Open images output directory",
"\u{1f4be}": "Save style",
- "\u{1f5d1}": "Clear prompt",
+ "\u{1f5d1}\ufe0f": "Clear prompt",
"\u{1f4cb}": "Apply selected styles to current prompt",
"\u{1f4d2}": "Paste available values into the field",
- "\u{1f3b4}": "Show extra networks",
+ "\u{1f3b4}": "Show/hide extra networks",
"\u{1f5e8}": "Interogate Clip",
- "\u{1f5ea}": "Interogate Deepbooru",
-
+ "\u{1f5ea}": "Interogate Deepbooru",
"Inpaint a part of image": "Draw a mask over an image, and the script will regenerate the masked area with content according to prompt",
"SD upscale": "Upscale image normally, split result into tiles, improve each tile using img2img, merge whole image back",
@@ -42,8 +41,7 @@ titles = {
"Inpaint at full resolution": "Upscale masked region to target resolution, do inpainting, downscale back and paste into original image",
"Denoising strength": "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.",
- "Denoising strength change factor": "In loopback mode, on each loop the denoising strength is multiplied by this value. <1 means decreasing variety so your sequence will converge on a fixed picture. >1 means increasing variety so your sequence will become more and more chaotic.",
-
+
"Skip": "Stop processing current image and continue processing.",
"Interrupt": "Stop processing images and return any results accumulated so far.",
"Save": "Write image to a directory (default - log/images) and generation parameters into csv file.",
@@ -51,7 +49,7 @@ titles = {
"Send to txt2img": "Send to txt2img",
"Send to img2img": "Send to img2img",
"Send to inpaint": "Send to inpaint",
- "Send to extras": "Send to extras",
+ "Send to extras": "Send to extras",
"X values": "Separate values for X axis using commas.",
"Y values": "Separate values for Y axis using commas.",
@@ -78,8 +76,10 @@ titles = {
"Directory name pattern": "Use following tags to define how subdirectories for images and grids are chosen: [steps], [cfg],[prompt_hash], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [model_name], [prompt_words], [date], [datetime], [datetime], [datetime], [job_timestamp]; leave empty for default.",
"Max prompt words": "Set the maximum number of words to be used in the [prompt_words] option; ATTENTION: If the words are too long, they may exceed the maximum length of the file path that the system can handle",
- "Loopback": "Process an image, use it as an input, repeat.",
- "Loops": "How many times to repeat processing an image and using it as input for the next iteration",
+ "Loopback": "Performs img2img processing multiple times. Output images are used as input for the next loop.",
+ "Loops": "How many times to process an image. Each output is used as the input of the next loop. If set to 1, behavior will be as if this script were not used.",
+ "Final denoising strength": "The denoising strength for the final loop of each image in the batch.",
+ "Denoising strength curve": "The denoising curve controls the rate of denoising strength change each loop. Aggressive: Most of the change will happen towards the start of the loops. Linear: Change will be constant through all loops. Lazy: Most of the change will happen towards the end of the loops.",
"Style 1": "Style to apply; styles have components for both positive and negative prompts and apply to both",
"Style 2": "Style to apply; styles have components for both positive and negative prompts and apply to both",
diff --git a/javascript/imageviewer.js b/javascript/imageviewer.js
index 1f391cbf..655eae71 100644
--- a/javascript/imageviewer.js
+++ b/javascript/imageviewer.js
@@ -33,13 +33,7 @@ function negmod(n, m) {
function updateOnBackgroundChange() {
const modalImage = gradioApp().getElementById("modalImage")
if (modalImage && modalImage.offsetParent) {
- let allcurrentButtons = gradioApp().querySelectorAll(".gallery-item.transition-all.\\!ring-2")
- let currentButton = null
- allcurrentButtons.forEach(function(elem) {
- if (elem.parentElement.offsetParent) {
- currentButton = elem;
- }
- })
+ let currentButton = selected_gallery_button();
if (currentButton?.children?.length > 0 && modalImage.src != currentButton.children[0].src) {
modalImage.src = currentButton.children[0].src;
@@ -51,22 +45,10 @@ function updateOnBackgroundChange() {
}
function modalImageSwitch(offset) {
- var allgalleryButtons = gradioApp().querySelectorAll(".gallery-item.transition-all")
- var galleryButtons = []
- allgalleryButtons.forEach(function(elem) {
- if (elem.parentElement.offsetParent) {
- galleryButtons.push(elem);
- }
- })
+ var galleryButtons = all_gallery_buttons();
if (galleryButtons.length > 1) {
- var allcurrentButtons = gradioApp().querySelectorAll(".gallery-item.transition-all.\\!ring-2")
- var currentButton = null
- allcurrentButtons.forEach(function(elem) {
- if (elem.parentElement.offsetParent) {
- currentButton = elem;
- }
- })
+ var currentButton = selected_gallery_button();
var result = -1
galleryButtons.forEach(function(v, i) {
@@ -137,37 +119,29 @@ function modalKeyHandler(event) {
}
}
-function showGalleryImage() {
- setTimeout(function() {
- fullImg_preview = gradioApp().querySelectorAll('img.w-full.object-contain')
+function setupImageForLightbox(e) {
+ if (e.dataset.modded)
+ return;
- if (fullImg_preview != null) {
- fullImg_preview.forEach(function function_name(e) {
- if (e.dataset.modded)
- return;
- e.dataset.modded = true;
- if(e && e.parentElement.tagName == 'DIV'){
- e.style.cursor='pointer'
- e.style.userSelect='none'
+ e.dataset.modded = true;
+ e.style.cursor='pointer'
+ e.style.userSelect='none'
- var isFirefox = isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1
+ var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1
- // For Firefox, listening on click first switched to next image then shows the lightbox.
- // If you know how to fix this without switching to mousedown event, please.
- // For other browsers the event is click to make it possiblr to drag picture.
- var event = isFirefox ? 'mousedown' : 'click'
+ // For Firefox, listening on click first switched to next image then shows the lightbox.
+ // If you know how to fix this without switching to mousedown event, please.
+ // For other browsers the event is click to make it possiblr to drag picture.
+ var event = isFirefox ? 'mousedown' : 'click'
- e.addEventListener(event, function (evt) {
- if(!opts.js_modal_lightbox || evt.button != 0) return;
- modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed)
- evt.preventDefault()
- showModal(evt)
- }, true);
- }
- });
- }
+ e.addEventListener(event, function (evt) {
+ if(!opts.js_modal_lightbox || evt.button != 0) return;
+
+ modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed)
+ evt.preventDefault()
+ showModal(evt)
+ }, true);
- }, 100);
}
function modalZoomSet(modalImage, enable) {
@@ -200,21 +174,21 @@ function modalTileImageToggle(event) {
}
function galleryImageHandler(e) {
- if (e && e.parentElement.tagName == 'BUTTON') {
+ //if (e && e.parentElement.tagName == 'BUTTON') {
e.onclick = showGalleryImage;
- }
+ //}
}
onUiUpdate(function() {
- fullImg_preview = gradioApp().querySelectorAll('img.w-full')
+ fullImg_preview = gradioApp().querySelectorAll('.gradio-gallery > div > img')
if (fullImg_preview != null) {
- fullImg_preview.forEach(galleryImageHandler);
+ fullImg_preview.forEach(setupImageForLightbox);
}
updateOnBackgroundChange();
})
document.addEventListener("DOMContentLoaded", function() {
- const modalFragment = document.createDocumentFragment();
+ //const modalFragment = document.createDocumentFragment();
const modal = document.createElement('div')
modal.onclick = closeModal;
modal.id = "lightboxModal";
@@ -278,14 +252,13 @@ document.addEventListener("DOMContentLoaded", function() {
modal.appendChild(modalNext)
+ gradioApp().appendChild(modal)
- gradioApp().getRootNode().appendChild(modal)
- document.body.appendChild(modalFragment);
+ document.body.appendChild(modal);
});
*/
-
//called from progressbar
function showGalleryImage() {
//need to clean up the old code
@@ -390,7 +363,7 @@ function createGallerySpotlight() {
slide = 0;
gallery = [];
- gradioApp().querySelectorAll("#"+selectedTabItemId+' .grid img.w-full.object-contain').forEach(function (elem, i){
+ gradioApp().querySelectorAll("#"+selectedTabItemId+' .grid-wrap img').forEach(function (elem, i){
elem.setAttribute("gal-id", i);
if(fullImg_src == elem.src) slide = (i+1);
gallery[i] = {
@@ -434,7 +407,7 @@ function createGallerySpotlight() {
},
onclose: function(index){
- gradioApp().querySelector("#"+selectedTabItemId+' .grid .gallery-item:nth-child('+(slide+1)+')').click();
+ gradioApp().querySelector("#"+selectedTabItemId+' .thumbnail-item:nth-child('+(slide+1)+')').click();
}
};
@@ -465,7 +438,7 @@ function onUiUpdateIViewer(){
//update_performant_inputs(selectedTabItemId);
//fullImg_preview = gradioApp().querySelector('#'+selectedTabItemId+' [id$="2img_results"] .modify-upload + img.w-full.object-contain');
- fullImg_preview = gradioApp().querySelector('#'+selectedTabItemId+' .modify-upload + img.w-full.object-contain');
+ fullImg_preview = gradioApp().querySelector('#'+selectedTabItemId+' .preview img');
if(opts.js_modal_lightbox && fullImg_preview ) {
fullImg_src = fullImg_preview.src;
diff --git a/javascript/notification.js b/javascript/notification.js
index 5ae6df24..8ddd4c5d 100644
--- a/javascript/notification.js
+++ b/javascript/notification.js
@@ -15,7 +15,7 @@ onUiUpdate(function(){
}
}
- const galleryPreviews = gradioApp().querySelectorAll('div[id^="tab_"][style*="display: block"] div[id$="_results"] img.h-full.w-full.overflow-hidden');
+ const galleryPreviews = gradioApp().querySelectorAll('div[id^="tab_"][style*="display: block"] div[id$="_results"] .thumbnail-item > img');
if (galleryPreviews == null) return;
diff --git a/javascript/progressbar.js b/javascript/progressbar.js
index e3419376..2f48469f 100644
--- a/javascript/progressbar.js
+++ b/javascript/progressbar.js
@@ -1,78 +1,13 @@
// code related to showing and updating progressbar shown as the image is being made
-
-galleries = {}
-storedGallerySelections = {}
-galleryObservers = {}
-
function rememberGallerySelection(id_gallery){
- storedGallerySelections[id_gallery] = getGallerySelectedIndex(id_gallery)
+
}
function getGallerySelectedIndex(id_gallery){
- let galleryButtons = gradioApp().querySelectorAll('#'+id_gallery+' .gallery-item')
- let galleryBtnSelected = gradioApp().querySelector('#'+id_gallery+' .gallery-item.\\!ring-2')
- let currentlySelectedIndex = -1
- galleryButtons.forEach(function(v, i){ if(v==galleryBtnSelected) { currentlySelectedIndex = i } })
-
- return currentlySelectedIndex
}
-// this is a workaround for https://github.com/gradio-app/gradio/issues/2984
-function check_gallery(id_gallery){
- let gallery = gradioApp().getElementById(id_gallery)
- // if gallery has no change, no need to setting up observer again.
- if (gallery && galleries[id_gallery] !== gallery){
- galleries[id_gallery] = gallery;
- if(galleryObservers[id_gallery]){
- galleryObservers[id_gallery].disconnect();
- }
-
- storedGallerySelections[id_gallery] = -1
-
- galleryObservers[id_gallery] = new MutationObserver(function (){
- let galleryButtons = gradioApp().querySelectorAll('#'+id_gallery+' .gallery-item')
- let galleryBtnSelected = gradioApp().querySelector('#'+id_gallery+' .gallery-item.\\!ring-2')
- let currentlySelectedIndex = getGallerySelectedIndex(id_gallery)
- prevSelectedIndex = storedGallerySelections[id_gallery]
- storedGallerySelections[id_gallery] = -1
-
- if (prevSelectedIndex !== -1 && galleryButtons.length>prevSelectedIndex && !galleryBtnSelected) {
- // automatically re-open previously selected index (if exists)
- activeElement = gradioApp().activeElement;
- let scrollX = window.scrollX;
- let scrollY = window.scrollY;
-
- galleryButtons[prevSelectedIndex].click();
- showGalleryImage();
-
- // When the gallery button is clicked, it gains focus and scrolls itself into view
- // We need to scroll back to the previous position
- setTimeout(function (){
- window.scrollTo(scrollX, scrollY);
- }, 50);
-
- if(activeElement){
- // i fought this for about an hour; i don't know why the focus is lost or why this helps recover it
- // if someone has a better solution please by all means
- setTimeout(function (){
- activeElement.focus({
- preventScroll: true // Refocus the element that was focused before the gallery was opened without scrolling to it
- })
- }, 1);
- }
- }
- })
- galleryObservers[id_gallery].observe( gallery, { childList:true, subtree:false })
- }
-}
-
-onUiUpdate(function(){
- check_gallery('txt2img_gallery')
- check_gallery('img2img_gallery')
-})
-
function request(url, data, handler, errorHandler){
var xhr = new XMLHttpRequest();
var url = url;
@@ -162,7 +97,7 @@ function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgre
if(divProgress){
parentProgressbar.removeChild(divProgress)
}
-
+
if(progressbarContainer.id == "txt2img_gallery_container"){
showSubmitButtons('txt2img', true);
}else if(progressbarContainer.id == "img2img_gallery_container"){
@@ -171,6 +106,9 @@ function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgre
if(livePreview){
if(parentGallery) parentGallery.removeChild(livePreview)
}
+ gradioApp().querySelectorAll('#tabs + div, #tabs + div > *:not(ul)').forEach(function (elem){
+ elem.style.setProperty("display", "block", "important");
+ })
atEnd()
}
diff --git a/javascript/ui.js b/javascript/ui.js
index 915dca58..123fcd0e 100644
--- a/javascript/ui.js
+++ b/javascript/ui.js
@@ -7,9 +7,31 @@ function set_theme(theme){
}
}
+function all_gallery_buttons() {
+ var allGalleryButtons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery].gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small');
+ var visibleGalleryButtons = [];
+ allGalleryButtons.forEach(function(elem) {
+ if (elem.parentElement.offsetParent) {
+ visibleGalleryButtons.push(elem);
+ }
+ })
+ return visibleGalleryButtons;
+}
+
+function selected_gallery_button() {
+ var allCurrentButtons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery].gradio-gallery .thumbnail-item.thumbnail-small.selected');
+ var visibleCurrentButton = null;
+ allCurrentButtons.forEach(function(elem) {
+ if (elem.parentElement.offsetParent) {
+ visibleCurrentButton = elem;
+ }
+ })
+ return visibleCurrentButton;
+}
+
function selected_gallery_index(){
- var buttons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery] .gallery-item')
- var button = gradioApp().querySelector('[style="display: block;"].tabitem div[id$=_gallery] .gallery-item.\\!ring-2')
+ var buttons = all_gallery_buttons();
+ var button = selected_gallery_button();
var result = -1
buttons.forEach(function(v, i){ if(v==button) { result = i } })
@@ -18,14 +40,18 @@ function selected_gallery_index(){
}
function extract_image_from_gallery(gallery){
- if(gallery.length == 1){
- return [gallery[0]]
+ if (gallery.length == 0){
+ return [null];
+ }
+ if (gallery.length == 1){
+ return [gallery[0]];
}
index = selected_gallery_index()
if (index < 0 || index >= gallery.length){
- return [null]
+ // Use the first image in the gallery as the default
+ index = 0;
}
return [gallery[index]];
@@ -68,14 +94,14 @@ function switch_to_inpaint_sketch(){
switch_to_img2img_tab(3);
return args_to_array(arguments);
}
-
-/* function switch_to_inpaint(){
+/*
+function switch_to_inpaint(){
gradioApp().querySelector('#tabs').querySelectorAll('button')[1].click();
gradioApp().getElementById('mode_img2img').querySelectorAll('button')[2].click();
return args_to_array(arguments);
}
- */
+*/
function switch_to_extras(){
gradioApp().querySelector('#tabs').querySelectorAll('button')[2].click();
@@ -85,8 +111,8 @@ function switch_to_extras(){
function get_tab_index(tabId){
var res = 0
- gradioApp().getElementById(tabId).querySelector('div').querySelectorAll('button').forEach(function(button, i){
- if(button.className.indexOf('bg-white') != -1)
+ gradioApp().getElementById(tabId).querySelector('div').querySelectorAll('button').forEach(function(button, i){
+ if(button.className.indexOf('selected') != -1)
res = i
})
@@ -140,7 +166,6 @@ function submit(){
var id = randomId()
requestProgress(id, gradioApp().getElementById('txt2img_gallery_container'), gradioApp().getElementById('txt2img_gallery'), function(){
showSubmitButtons('txt2img', true)
-
})
var res = create_submit_args(arguments)
@@ -215,14 +240,12 @@ function recalculate_prompts_img2img(){
}
function recalculate_prompts_inpaint(){
- //console.log("img2img_prompt");
recalculatePromptTokens('img2img_prompt')
recalculatePromptTokens('img2img_neg_prompt')
return args_to_array(arguments);
}
-let selectedTabItemId = "tab_txt2img";
-
+let selectedTabItemId = "tab_txt2img";
opts = {}
onUiUpdate(function(){
if(Object.keys(opts).length != 0) return;
@@ -265,7 +288,7 @@ onUiUpdate(function(){
}
prompt.parentElement.insertBefore(counter, prompt)
- counter.classList.add("token-counter")
+ counter.classList.add("token-counter")
prompt.parentElement.style.position = "relative"
promptTokecountUpdateFuncs[id] = function(){ update_token_counter(id_button); }
@@ -287,13 +310,10 @@ onUiUpdate(function(){
})
gradioApp().querySelectorAll('#settings > div > div > div').forEach(function(elem){
elem.style.maxHeight = "none";
- })
+ })
}
}
-
-
-
- /*
+/*
^ matches the start
* matches any position
$ matches the end
@@ -312,12 +332,12 @@ onUiUpdate(function(){
var offset = elem.offsetHeight - elem.clientHeight;
elem.addEventListener('input', function (e) {
e.target.style.minHeight = 'auto';
- e.target.style.minHeight = e.target.scrollHeight + offset + 'px';
+ e.target.style.minHeight = e.target.scrollHeight + offset + 2 + 'px';
});
elem.addEventListener('focus', function (e) {
e.target.style.minHeight = 'auto';
- e.target.style.minHeight = e.target.scrollHeight + offset + 'px';
+ e.target.style.minHeight = e.target.scrollHeight + offset + 2 + 'px';
});
});
@@ -414,12 +434,12 @@ onUiUpdate(function(){
})
function tabItemChanged(idx){
- gradioApp().querySelectorAll('#tabs > div > button.bg-white, #nav_menu_header_tabs > button.bg-white').forEach(function (tab){
- tab.classList.remove("bg-white");
+ gradioApp().querySelectorAll('#tabs > div > button.selected, #nav_menu_header_tabs > button.selected').forEach(function (tab){
+ tab.classList.remove("selected");
})
gradioApp().querySelectorAll('#tabs > div > button:nth-child('+(idx+1)+'), #nav_menu_header_tabs > button:nth-child('+(idx+1)+')').forEach(function (tab){
- tab.classList.add("bg-white");
+ tab.classList.add("selected");
})
//gardio removes listeners and attributes from tab buttons we add them again here
@@ -431,7 +451,32 @@ onUiUpdate(function(){
})
- window.onUiHeaderTabUpdate();
+/* gradioApp().querySelectorAll('[id^="image_buttons_"] button').forEach(function (elem){
+
+ if(elem.id == "txt2img_tab"){
+ elem.setAttribute("tab-id", 0);
+ elem.removeEventListener('click', navTabClicked);
+ elem.addEventListener('click', navTabClicked);
+ }else if(elem.id == "img2img_tab" || elem.id == "inpaint_tab"){
+ elem.setAttribute("tab-id", 1);
+ elem.removeEventListener('click', navTabClicked);
+ elem.addEventListener('click', navTabClicked);
+ }if(elem.id == "extras_tab"){
+ elem.setAttribute("tab-id", 2);
+ elem.removeEventListener('click', navTabClicked);
+ elem.addEventListener('click', navTabClicked);
+ }
+ }) */
+
+/* const pdiv = gradioApp().querySelector("#"+selectedTabItemId+" .progressDiv");
+ if(!pdiv && selectedTabItemId == "tab_txt2img"){
+ showSubmitButtons('txt2img', true);
+ }else if(!pdiv && selectedTabItemId == "tab_img2img"){
+ showSubmitButtons('img2img', true);
+ } */
+
+
+ //window.onUiHeaderTabUpdate();
// also here the same issue
/*
gradioApp().querySelectorAll('[id^="image_buttons"] [id$="_tab"]').forEach(function (button, index){
@@ -452,6 +497,7 @@ onUiUpdate(function(){
netMenuVisibility();
}
+
// menu
function disableScroll() {
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
@@ -493,7 +539,7 @@ onUiUpdate(function(){
if(theme_menu != menu && theme_menu_open) theme_menu.click();
}
- // if we change to view other than 2img and if aside mode is selected close extra networks aside and hide the net menu icon
+ // if we change to other view other than 2img and if aside mode is selected close extra networks aside and hide the net menu icon
let net_container = gradioApp().querySelector('#txt2img_extra_networks_row');
let net_menu_open = false;
const net_menu = gradioApp().querySelector('#extra_networks_menu');
@@ -598,6 +644,36 @@ onUiUpdate(function(){
//
+ // extra networks nav menu
+ function toggleAccordion(e) {
+
+ //e.stopImmediatePropagation();
+ let accordion_content = e.currentTarget.parentElement.querySelector(".gap.svelte-vt1mxs");
+
+ if(accordion_content){
+ e.preventDefault();
+ e.stopPropagation();
+ let accordion_icon = e.currentTarget.parentElement.querySelector(".label-wrap > .icon");
+ if(accordion_content.className.indexOf("hidden") != -1){
+ accordion_content.classList.remove("hidden");
+ accordion_icon.style.setProperty('transform', 'rotate(0deg)');
+ e.currentTarget.classList.add("hide");
+ }else{
+ accordion_content.classList.add("hidden");
+ accordion_icon.style.setProperty('transform', 'rotate(90deg)');
+ e.currentTarget.classList.remove("hide");
+ }
+ }else{
+ let accordion_btn = e.currentTarget.parentElement.querySelector(".label-wrap");
+ e.currentTarget.classList.add("hide");
+ accordion_btn.click();
+ }
+ }
+
+ gradioApp().querySelectorAll('.gradio-accordion > div.wrap').forEach((elem) => {
+ elem.addEventListener('click', toggleAccordion);
+ })
+
// additional ui styles
let styleobj = {};
@@ -618,7 +694,7 @@ onUiUpdate(function(){
// generated image fit contain - scale
function imageGeneratedFitMethod(value) {
- styleobj.ui_view_fit = "[id$='2img_gallery'] div>img {object-fit:" + value + ";}";
+ styleobj.ui_view_fit = "[id$='2img_gallery'] div>img {object-fit:" + value + "!important;}";
}
gradioApp().querySelector("#setting_ui_output_image_fit").addEventListener('click', function (e) {
if (e.target && e.target.matches("input[type='radio']")) {
@@ -630,7 +706,7 @@ onUiUpdate(function(){
// livePreview fit contain - scale
function imagePreviewFitMethod(value) {
- styleobj.ui_fit = ".livePreview img {object-fit:" + value + ";}";
+ styleobj.ui_fit = ".livePreview img {object-fit:" + value + "!important;}";
}
gradioApp().querySelector("#setting_live_preview_image_fit").addEventListener('click', function (e) {
if (e.target && e.target.matches("input[type='radio']")) {
@@ -680,7 +756,7 @@ onUiUpdate(function(){
extra_networks_visibility(opts.extra_networks_default_visibility);
function extra_networks_card_size(value) {
- styleobj.extra_networks_card_size = ":host{--extra-networks-card-size:" + value + ";}";
+ styleobj.extra_networks_card_size = ":root{--ae-extra-networks-card-size:" + value + ";}";
}
gradioApp().querySelectorAll("#setting_extra_networks_cards_size input").forEach(function (elem){
elem.addEventListener('input', function (e) {
@@ -691,7 +767,7 @@ onUiUpdate(function(){
extra_networks_card_size(opts.extra_networks_cards_size);
function extra_networks_cards_visible_rows(value) {
- styleobj.extra_networks_cards_visible_rows = ":host{--extra-networks-visible-rows:" + value + ";}";
+ styleobj.extra_networks_cards_visible_rows = ":root{--ae-extra-networks-visible-rows:" + value + ";}";
}
gradioApp().querySelectorAll("#setting_extra_networks_cards_visible_rows input").forEach(function (elem){
elem.addEventListener('input', function (e) {
@@ -775,11 +851,9 @@ onUiUpdate(function(){
function navigate2TabItem(idx){
gradioApp().querySelectorAll('#tabs > div.tabitem').forEach(function (tabitem, index){
if(idx == index){
- tabitem.style.display = "block";
- //tabitem.classList.add("wtf");
+ tabitem.style.display = "block";
}else{
- tabitem.style.display = "none";
- //tabitem.classList.remove("wtf");
+ tabitem.style.display = "none";
}
})
}
@@ -803,10 +877,12 @@ onUiUpdate(function(){
if(setting_ui_header_tabs.value.indexOf(tabvalue) != -1){
headertabs[tabvalue] = true;
checked_header = "checked";
- }
- radio_hidden_html += ''+elem.innerText+' ';
- radio_header_html += ''+elem.innerText+' ';
+ }
+ radio_hidden_html += ''+elem.innerText+' ';
+ radio_header_html += ''+elem.innerText+' ';
+
+
tabitems[index].setAttribute("tab-item", index);
elem.setAttribute("tab-id", index);
@@ -815,18 +891,17 @@ onUiUpdate(function(){
parent_header_tabs.append(clonetab);
clonetab.addEventListener('click', navTabClicked);
-
})
let div = document.createElement("div");
div.id = "hidden_radio_tabs_container";
- div.classList.add("flex", "flex-wrap", "gap-2");
+ div.classList.add("flex", "flex-wrap", "gap-2", "wrap", "svelte-1qxcj04");
div.innerHTML = radio_hidden_html;
setting_ui_hidden_tabs.parentElement.appendChild(div);
div = document.createElement("div");
div.id = "header_radio_tabs_container";
- div.classList.add("flex", "flex-wrap", "gap-2");
+ div.classList.add("flex", "flex-wrap", "gap-2", "wrap", "svelte-1qxcj04");
div.innerHTML = radio_header_html;
setting_ui_header_tabs.parentElement.appendChild(div);
@@ -848,11 +923,11 @@ onUiUpdate(function(){
updateOpStyles();
}
})
-
+
tabsHiddenChange();
gradioApp().querySelectorAll('[id^="image_buttons_"] button, #png_2img_results button').forEach(function (elem){
-
+ //console.log(opts.send_seed);
if(elem.id == "txt2img_tab"){
elem.setAttribute("tab-id", 0);
elem.addEventListener('click', navTabClicked);
@@ -883,6 +958,7 @@ onUiUpdate(function(){
})
})
+
// add - remove quicksettings
const settings_submit = gradioApp().querySelector('#settings_submit');
const quick_parent = gradioApp().querySelector("#quicksettings_overflow_container");
@@ -942,7 +1018,7 @@ onUiUpdate(function(){
// input release component dispatcher
let active_clone_input = [];
- let focus_input, last_focus_input;
+ let focus_input;
function ui_input_release_component(elem){
@@ -951,7 +1027,11 @@ onUiUpdate(function(){
//img2img_width
let parent = elem.parentElement;
let comp_parent = parent.parentElement.parentElement;
- if(comp_parent.id == "img2img_width" || comp_parent.id == "img2img_height" || comp_parent.className.indexOf("posex") != -1) return;
+ if( comp_parent.id == "img2img_width" ||
+ comp_parent.id == "img2img_height" ||
+ comp_parent.id.indexOf("--ae-") != -1 ||
+ comp_parent.id.indexOf("theme") != -1 ||
+ comp_parent.className.indexOf("posex") != -1) return;
let clone_num = elem.cloneNode();
active_clone_input.push(clone_num);
@@ -973,10 +1053,6 @@ onUiUpdate(function(){
focus_input = clone_num;
})
-/* clone_num.addEventListener('blur', function (e) {
- focus_input = false;
- }) */
-
if(label){
let comp_range = comp_parent.querySelector("input[type='range']");
let clone_range = comp_range.cloneNode();
@@ -987,17 +1063,16 @@ onUiUpdate(function(){
comp_range.parentElement.append(clone_range);
comp_range.classList.add("hidden");
- clone_range.addEventListener('input', function (e) {
- clone_num.value = e.target.value;
- })
+ clone_range.addEventListener('input', function (e) {
+ clone_num.value = e.target.value;
+ })
clone_range.addEventListener('change', function (e) {
elem.value = clone_range.value;
updateInput(elem);
})
clone_num.addEventListener('input', function (e) {
clone_range.value = e.target.value;
- })
-
+ })
const rect = clone_range.getBoundingClientRect();
const xoffset = (rect.left + window.scrollX);
clone_range.addEventListener('touchmove', function(e) {
@@ -1005,8 +1080,7 @@ onUiUpdate(function(){
let percent = parseInt(((e.touches[0].pageX - xoffset) / this.offsetWidth) * 10000) / 10000;
clone_range.value = ( percent * (this.max - this.min)) + parseFloat(this.min);
clone_num.value = clone_range.value;
- });
-
+ });
}
}
function ui_input_focus_handler(e){
@@ -1049,11 +1123,9 @@ onUiUpdate(function(){
function ui_dispatch_input_release(value){
if(value){
gradioApp().querySelector(".gradio-container").addEventListener('mouseover', ui_input_release_handler);
- //gradioApp().querySelector(".gradio-container").addEventListener('touchmove', ui_input_release_handler);
gradioApp().querySelector(".gradio-container").addEventListener('mousedown', ui_input_focus_handler);
}else{
gradioApp().querySelector(".gradio-container").removeEventListener('mouseover', ui_input_release_handler);
- //gradioApp().querySelector(".gradio-container").removeEventListener('touchmove', ui_input_release_handler);
gradioApp().querySelector(".gradio-container").removeEventListener('mousedown', ui_input_focus_handler);
}
}
@@ -1062,61 +1134,6 @@ onUiUpdate(function(){
})
ui_dispatch_input_release(opts.ui_dispatch_input_release);
-
- // performant dispatch for gradio's range slider and input number fields
- /*
- function ui_performant_gradio_input_components(sel){
- let selectors = sel.split(",");
- selectors.push("#quicksettings_overflow_container", "#tab_txt2img", "#tab_img2img", "#tab_extras", "#tab_modelmerger", "#tab_ti");
- selectors = selectors.filter(e => e);
- for (let i = 0; i < selectors.length; i++) {
- selectors[i] = selectors[i]+" input[type='number']";
- }
- let input_selectors = selectors.join(",");
-
- gradioApp().querySelectorAll(input_selectors).forEach(function (elem, index){
- let parent = elem.parentElement;
- let label = parent.querySelector("label");
-
- //console.log(elem.value);
-
- let clone_num = elem.cloneNode(true);
- clone_num.id = "num_clone_"+index;
- clone_num.value = elem.value;
- parent.append(clone_num);
- //elem.classList.add("hidden");
-
- clone_num.addEventListener('change', function (e) {
- elem.value = clone_num.value;
- updateInput(elem);
- })
-
-
- if(label){
- let comp_range = parent.parentElement.parentElement.querySelector("input[type='range']");
- let clone_range = comp_range.cloneNode(true);
- clone_range.id = comp_range.id+"_clone";
- clone_range.value = comp_range.value;
- comp_range.parentElement.append(clone_range);
- //comp_range.classList.add("hidden");
-
- clone_range.addEventListener('input', function (e) {
- clone_num.value = e.target.value;
- })
- clone_range.addEventListener('change', function (e) {
- elem.value = clone_range.value;
- updateInput(elem);
- })
- clone_num.addEventListener('input', function (e) {
- clone_range.value = e.target.value;
- })
- }
-
- })
- }
- */
- //ui_performant_gradio_input_components(opts.ui_performant_gradio_input_components);
-
// step ticks for performant input range
function ui_show_range_ticks(value, interactive){
if(value){
@@ -1127,12 +1144,12 @@ onUiUpdate(function(){
let tsp = 'max(3px, calc('+spacing+'% - 2px))';
let fsp = 'max(4px, calc('+spacing+'% + 0px))';
var style = elem.style;
- style.setProperty('--slider-bg-overlay', 'repeating-linear-gradient( 90deg, transparent, transparent '+tsp+', var(--input-border-color) '+tsp+', var(--input-border-color) '+fsp+' )');
+ style.setProperty('--ae-slider-bg-overlay', 'repeating-linear-gradient( 90deg, transparent, transparent '+tsp+', var(--ae-input-border-color) '+tsp+', var(--ae-input-border-color) '+fsp+' )');
})
}else if(interactive){
gradioApp().querySelectorAll("input[type='range']").forEach(function (elem){
var style = elem.style;
- style.setProperty('--slider-bg-overlay', 'transparent');
+ style.setProperty('--ae-slider-bg-overlay', 'transparent');
})
}
}
@@ -1154,10 +1171,11 @@ onUiUpdate(function(){
return false;
}
let sdCheckpointModels = [];
- function getSdCheckpointModels(){
- gradioApp().querySelectorAll("#quicksettings #setting_sd_model_checkpoint option").forEach(function (elem, i){
- sdCheckpointModels[i] = elem.value;
- })
+ function getSdCheckpointModels(){
+ gradioApp().querySelectorAll("#txt2img_checkpoints_cards .card").forEach(function (elem, i){
+ sdCheckpointModels[i] = elem.getAttribute("onclick").split('"')[1];
+ })
+
}
getSdCheckpointModels();
@@ -1187,8 +1205,8 @@ onUiUpdate(function(){
}
}
if(checked_overrides.indexOf(token_name) != -1){
- token.querySelector(".token-remove").click();
- gradioApp().querySelector("[id$='2img_override_settings']").classList.add("show");
+ token.querySelector(".token-remove").click();
+ gradioApp().querySelector("#"+selectedTabItemId+" [id$='2img_override_settings']").parentElement.classList.add("show");
}else{
// maybe we add them again, for now we can select and add the removed tokens manually from the drop down
}
@@ -1230,9 +1248,9 @@ onUiUpdate(function(){
if(selectedTabItemId == "tab_txt2img"){
pnginfo.querySelector('#txt2img_tab').click();
- //close generation info
- gradioApp().querySelector('#txt2img_results > div:last-child > div:last-child > div:last-child').classList.add("!hidden");
-
+ //close generation info
+ gradioApp().querySelector('#txt2img_results > div:last-child > div.gradio-accordion > div.hide')?.click();
+
const img_src = pnginfo.querySelector('img');
const gallery_parent = gradioApp().querySelector('#txt2img_gallery_container');
const live_preview = gallery_parent.querySelector('.livePreview');
@@ -1247,44 +1265,48 @@ onUiUpdate(function(){
}else if(selectedTabItemId == "tab_img2img"){
pnginfo.querySelector('#img2img_tab').click();
//close generation info
- gradioApp().querySelector('#img2img_results > div:last-child > div:last-child > div:last-child').classList.add("!hidden");
+ gradioApp().querySelector('#img2img_results > div:last-child > div.gradio-accordion > div.hide')?.click();
}
}
function fetchPngInfoData(files){
- const oldFetch = window.fetch;
- window.fetch = async (input, options) => {
+ /* const oldFetch = window.fetch;
+
+ window.fetch = async (input, options) => {
const response = await oldFetch(input, options);
- if( 'run/predict/' === input ) {
+ if( 'run/predict/' === input ) {
if(response.ok){
- window.fetch = oldFetch;
- setTimeout(function() { forwardFromPngInfo(); }, 500);
+ window.fetch = oldFetch;
}
}
return response;
- };
+ }; */
const fileInput = gradioApp().querySelector('#pnginfo_image input[type="file"]');
if(fileInput.files != files){
fileInput.files = files;
fileInput.dispatchEvent(new Event('change'));
- }
+ }
+
+ setTimeout(function() { forwardFromPngInfo(); }, 500);
+
}
- function drop2View(e){
+ function drop2View(e){
e.stopPropagation();
e.preventDefault();
const files = e.dataTransfer.files;
- if ( ! isValidImageList( files ) ) {
+
+ if (!isValidImageList(files)) {
return;
}
const data_image = gradioApp().querySelector('#pnginfo_image [data-testid="image"]');
- data_image.querySelector('.modify-upload button + button, .touch-none + div button + button')?.click();
+ data_image.querySelector('[aria-label="Clear"]')?.click();
setTimeout(function() { fetchPngInfoData(files); }, 1000);
}
- gradioApp().querySelectorAll('[id$="2img_results"]').forEach((elem) => {
+ gradioApp().querySelectorAll('[id$="2img_results"]').forEach((elem) => {
elem.addEventListener('drop', drop2View);
})
@@ -1444,7 +1466,6 @@ onUiUpdate(function(){
/* anapnoe ui end */
-
})
onOptionsChanged(function(){
@@ -1486,10 +1507,9 @@ function update_token_counter(button_id) {
}
function restart_reload(){
-
- let bg_color = getComputedStyle(gradioApp().querySelector(".container")).getPropertyValue('--main-bg-color');
- let primary_color = getComputedStyle(gradioApp().querySelector(".icon-info")).getPropertyValue('--primary-color');
- let panel_color = getComputedStyle(gradioApp().querySelector(".gr-box")).getPropertyValue('--panel-bg-color');
+ let bg_color = window.getComputedStyle(gradioApp().querySelector("#header-top")).getPropertyValue('--ae-main-bg-color');
+ let primary_color = window.getComputedStyle(gradioApp().querySelector(".icon-info")).getPropertyValue('--ae-primary-color');
+ let panel_color = window.getComputedStyle(gradioApp().querySelector(".gradio-box")).getPropertyValue('--ae-panel-bg-color');
localStorage.setItem("bg_color", bg_color);
localStorage.setItem("primary_color", primary_color);
@@ -1530,8 +1550,6 @@ function selectCheckpoint(name){
desiredCheckpointName = name;
gradioApp().getElementById('change_checkpoint').click()
}
-
-
document.addEventListener('readystatechange', function (e) {
document.body.style.display = "none";
if(localStorage.hasOwnProperty('bg_color')){
@@ -1541,10 +1559,9 @@ document.addEventListener('readystatechange', function (e) {
})
window.onload = function() {
- //document.getElementsByTagName("html")[0].style.backgroundColor = localStorage.getItem("bg_color");
- //document.body.style.backgroundColor = localStorage.getItem("bg_color");
+ document.getElementsByTagName("html")[0].style.backgroundColor = localStorage.getItem("bg_color");
+ document.body.style.backgroundColor = localStorage.getItem("bg_color");
+ document.body.style.display = "none";
+ setTimeout(function(){document.body.style.display = "block";},1000)
- //document.body.style.display = "none";
- setTimeout(function(){document.body.style.display = "block";},100)
-
-}
+}
\ No newline at end of file
diff --git a/launch.py b/launch.py
index b943fed2..68e08114 100644
--- a/launch.py
+++ b/launch.py
@@ -5,24 +5,25 @@ import sys
import importlib.util
import shlex
import platform
-import argparse
import json
-parser = argparse.ArgumentParser(add_help=False)
-parser.add_argument("--ui-settings-file", type=str, default='config.json')
-parser.add_argument("--data-dir", type=str, default=os.path.dirname(os.path.realpath(__file__)))
-args, _ = parser.parse_known_args(sys.argv)
+from modules import cmd_args
+from modules.paths_internal import script_path, extensions_dir
-script_path = os.path.dirname(__file__)
-data_path = os.getcwd()
+commandline_args = os.environ.get('COMMANDLINE_ARGS', "")
+sys.argv += shlex.split(commandline_args)
+
+args, _ = cmd_args.parser.parse_known_args()
-dir_repos = "repositories"
-dir_extensions = "extensions"
python = sys.executable
git = os.environ.get('GIT', "git")
index_url = os.environ.get('INDEX_URL', "")
stored_commit_hash = None
skip_install = False
+dir_repos = "repositories"
+
+if 'GRADIO_ANALYTICS_ENABLED' not in os.environ:
+ os.environ['GRADIO_ANALYTICS_ENABLED'] = 'False'
def check_python_version():
@@ -70,23 +71,6 @@ def commit_hash():
return stored_commit_hash
-def extract_arg(args, name):
- return [x for x in args if x != name], name in args
-
-
-def extract_opt(args, name):
- opt = None
- is_present = False
- if name in args:
- is_present = True
- idx = args.index(name)
- del args[idx]
- if idx < len(args) and args[idx][0] != "-":
- opt = args[idx]
- del args[idx]
- return args, is_present, opt
-
-
def run(command, desc=None, errdesc=None, custom_env=None, live=False):
if desc is not None:
print(desc)
@@ -222,16 +206,20 @@ def list_extensions(settings_file):
print(e, file=sys.stderr)
disabled_extensions = set(settings.get('disabled_extensions', []))
+ disable_all_extensions = settings.get('disable_all_extensions', 'none')
- return [x for x in os.listdir(os.path.join(data_path, dir_extensions)) if x not in disabled_extensions]
+ if disable_all_extensions != 'none':
+ return []
+
+ return [x for x in os.listdir(extensions_dir) if x not in disabled_extensions]
def run_extensions_installers(settings_file):
- if not os.path.isdir(dir_extensions):
+ if not os.path.isdir(extensions_dir):
return
for dirname_extension in list_extensions(settings_file):
- run_extension_installer(os.path.join(dir_extensions, dirname_extension))
+ run_extension_installer(os.path.join(extensions_dir, dirname_extension))
def prepare_environment():
@@ -239,7 +227,6 @@ def prepare_environment():
torch_command = os.environ.get('TORCH_COMMAND', "pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 --extra-index-url https://download.pytorch.org/whl/cu117")
requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt")
- commandline_args = os.environ.get('COMMANDLINE_ARGS', "")
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'xformers==0.0.16rc425')
gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379")
@@ -252,27 +239,13 @@ def prepare_environment():
codeformer_repo = os.environ.get('CODEFORMER_REPO', 'https://github.com/sczhou/CodeFormer.git')
blip_repo = os.environ.get('BLIP_REPO', 'https://github.com/salesforce/BLIP.git')
- stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "47b6b607fdd31875c9279cd2f4f16b92e4ea958e")
+ stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "cf1d67a6fd5ea1aa600c4df58e5b47da45f6bdbf")
taming_transformers_commit_hash = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "24268930bf1dce879235a7fddd0b2355b84d7ea6")
k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "5b3af030dd83e0297272d861c19477735d0317ec")
codeformer_commit_hash = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af")
blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9")
- sys.argv += shlex.split(commandline_args)
-
- sys.argv, _ = extract_arg(sys.argv, '-f')
- sys.argv, update_all_extensions = extract_arg(sys.argv, '--update-all-extensions')
- sys.argv, skip_torch_cuda_test = extract_arg(sys.argv, '--skip-torch-cuda-test')
- sys.argv, skip_python_version_check = extract_arg(sys.argv, '--skip-python-version-check')
- sys.argv, reinstall_xformers = extract_arg(sys.argv, '--reinstall-xformers')
- sys.argv, reinstall_torch = extract_arg(sys.argv, '--reinstall-torch')
- sys.argv, update_check = extract_arg(sys.argv, '--update-check')
- sys.argv, run_tests, test_dir = extract_opt(sys.argv, '--tests')
- sys.argv, skip_install = extract_arg(sys.argv, '--skip-install')
- xformers = '--xformers' in sys.argv
- ngrok = '--ngrok' in sys.argv
-
- if not skip_python_version_check:
+ if not args.skip_python_version_check:
check_python_version()
commit = commit_hash()
@@ -280,10 +253,10 @@ def prepare_environment():
print(f"Python {sys.version}")
print(f"Commit hash: {commit}")
- if reinstall_torch or not is_installed("torch") or not is_installed("torchvision"):
+ if args.reinstall_torch or not is_installed("torch") or not is_installed("torchvision"):
run(f'"{python}" -m {torch_command}', "Installing torch and torchvision", "Couldn't install torch", live=True)
- if not skip_torch_cuda_test:
+ if not args.skip_torch_cuda_test:
run_python("import torch; assert torch.cuda.is_available(), 'Torch is not able to use GPU; add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check'")
if not is_installed("gfpgan"):
@@ -295,7 +268,7 @@ def prepare_environment():
if not is_installed("open_clip"):
run_pip(f"install {openclip_package}", "open_clip")
- if (not is_installed("xformers") or reinstall_xformers) and xformers:
+ if (not is_installed("xformers") or args.reinstall_xformers) and args.xformers:
if platform.system() == "Windows":
if platform.python_version().startswith("3.10"):
run_pip(f"install -U -I --no-deps {xformers_package}", "xformers")
@@ -307,7 +280,7 @@ def prepare_environment():
elif platform.system() == "Linux":
run_pip(f"install {xformers_package}", "xformers")
- if not is_installed("pyngrok") and ngrok:
+ if not is_installed("pyngrok") and args.ngrok:
run_pip("install pyngrok", "ngrok")
os.makedirs(os.path.join(script_path, dir_repos), exist_ok=True)
@@ -327,18 +300,18 @@ def prepare_environment():
run_extensions_installers(settings_file=args.ui_settings_file)
- if update_check:
+ if args.update_check:
version_check(commit)
- if update_all_extensions:
- git_pull_recursive(os.path.join(data_path, dir_extensions))
+ if args.update_all_extensions:
+ git_pull_recursive(extensions_dir)
if "--exit" in sys.argv:
print("Exiting because of --exit argument")
exit(0)
- if run_tests:
- exitcode = tests(test_dir)
+ if args.tests and not args.no_tests:
+ exitcode = tests(args.tests)
exit(exitcode)
@@ -352,6 +325,8 @@ def tests(test_dir):
sys.argv.append("--skip-torch-cuda-test")
if "--disable-nan-check" not in sys.argv:
sys.argv.append("--disable-nan-check")
+ if "--no-tests" not in sys.argv:
+ sys.argv.append("--no-tests")
print(f"Launching Web UI in another process for testing with arguments: {' '.join(sys.argv[1:])}")
diff --git a/models/karlo/ViT-L-14_stats.th b/models/karlo/ViT-L-14_stats.th
new file mode 100644
index 00000000..a6a06e94
Binary files /dev/null and b/models/karlo/ViT-L-14_stats.th differ
diff --git a/modules/api/api.py b/modules/api/api.py
index 35e17afc..518b2a61 100644
--- a/modules/api/api.py
+++ b/modules/api/api.py
@@ -3,11 +3,15 @@ import io
import time
import datetime
import uvicorn
+import gradio as gr
from threading import Lock
from io import BytesIO
from gradio.processing_utils import decode_base64_to_file
-from fastapi import APIRouter, Depends, FastAPI, HTTPException, Request, Response
+from fastapi import APIRouter, Depends, FastAPI, Request, Response
from fastapi.security import HTTPBasic, HTTPBasicCredentials
+from fastapi.exceptions import HTTPException
+from fastapi.responses import JSONResponse
+from fastapi.encoders import jsonable_encoder
from secrets import compare_digest
import modules.shared as shared
@@ -18,7 +22,7 @@ from modules.textual_inversion.textual_inversion import create_embedding, train_
from modules.textual_inversion.preprocess import preprocess
from modules.hypernetworks.hypernetwork import create_hypernetwork, train_hypernetwork
from PIL import PngImagePlugin,Image
-from modules.sd_models import checkpoints_list
+from modules.sd_models import checkpoints_list, unload_model_weights, reload_model_weights
from modules.sd_models_config import find_checkpoint_config_near_filename
from modules.realesrgan_model import get_realesrgan_models
from modules import devices
@@ -90,6 +94,16 @@ def encode_pil_to_base64(image):
return base64.b64encode(bytes_data)
def api_middleware(app: FastAPI):
+ rich_available = True
+ try:
+ import anyio # importing just so it can be placed on silent list
+ import starlette # importing just so it can be placed on silent list
+ from rich.console import Console
+ console = Console()
+ except:
+ import traceback
+ rich_available = False
+
@app.middleware("http")
async def log_and_time(req: Request, call_next):
ts = time.time()
@@ -110,6 +124,36 @@ def api_middleware(app: FastAPI):
))
return res
+ def handle_exception(request: Request, e: Exception):
+ err = {
+ "error": type(e).__name__,
+ "detail": vars(e).get('detail', ''),
+ "body": vars(e).get('body', ''),
+ "errors": str(e),
+ }
+ print(f"API error: {request.method}: {request.url} {err}")
+ if not isinstance(e, HTTPException): # do not print backtrace on known httpexceptions
+ if rich_available:
+ console.print_exception(show_locals=True, max_frames=2, extra_lines=1, suppress=[anyio, starlette], word_wrap=False, width=min([console.width, 200]))
+ else:
+ traceback.print_exc()
+ return JSONResponse(status_code=vars(e).get('status_code', 500), content=jsonable_encoder(err))
+
+ @app.middleware("http")
+ async def exception_handling(request: Request, call_next):
+ try:
+ return await call_next(request)
+ except Exception as e:
+ return handle_exception(request, e)
+
+ @app.exception_handler(Exception)
+ async def fastapi_exception_handler(request: Request, e: Exception):
+ return handle_exception(request, e)
+
+ @app.exception_handler(HTTPException)
+ async def http_exception_handler(request: Request, e: HTTPException):
+ return handle_exception(request, e)
+
class Api:
def __init__(self, app: FastAPI, queue_lock: Lock):
@@ -150,8 +194,13 @@ class Api:
self.add_api_route("/sdapi/v1/train/embedding", self.train_embedding, methods=["POST"], response_model=TrainResponse)
self.add_api_route("/sdapi/v1/train/hypernetwork", self.train_hypernetwork, methods=["POST"], response_model=TrainResponse)
self.add_api_route("/sdapi/v1/memory", self.get_memory, methods=["GET"], response_model=MemoryResponse)
+ self.add_api_route("/sdapi/v1/unload-checkpoint", self.unloadapi, methods=["POST"])
+ self.add_api_route("/sdapi/v1/reload-checkpoint", self.reloadapi, methods=["POST"])
self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=ScriptsList)
+ self.default_script_arg_txt2img = []
+ self.default_script_arg_img2img = []
+
def add_api_route(self, path: str, endpoint, **kwargs):
if shared.cmd_opts.api_auth:
return self.app.add_api_route(path, endpoint, dependencies=[Depends(self.auth)], **kwargs)
@@ -185,7 +234,7 @@ class Api:
script_idx = script_name_to_index(script_name, script_runner.scripts)
return script_runner.scripts[script_idx]
- def init_script_args(self, request, selectable_scripts, selectable_idx, script_runner):
+ def init_default_script_args(self, script_runner):
#find max idx from the scripts in runner and generate a none array to init script_args
last_arg_index = 1
for script in script_runner.scripts:
@@ -193,13 +242,24 @@ class Api:
last_arg_index = script.args_to
# None everywhere except position 0 to initialize script args
script_args = [None]*last_arg_index
+ script_args[0] = 0
+
+ # get default values
+ with gr.Blocks(): # will throw errors calling ui function without this
+ for script in script_runner.scripts:
+ if script.ui(script.is_img2img):
+ ui_default_values = []
+ for elem in script.ui(script.is_img2img):
+ ui_default_values.append(elem.value)
+ script_args[script.args_from:script.args_to] = ui_default_values
+ return script_args
+
+ def init_script_args(self, request, default_script_args, selectable_scripts, selectable_idx, script_runner):
+ script_args = default_script_args.copy()
# position 0 in script_arg is the idx+1 of the selectable script that is going to be run when using scripts.scripts_*2img.run()
if selectable_scripts:
script_args[selectable_scripts.args_from:selectable_scripts.args_to] = request.script_args
script_args[0] = selectable_idx + 1
- else:
- # when [0] = 0 no selectable script to run
- script_args[0] = 0
# Now check for always on scripts
if request.alwayson_scripts and (len(request.alwayson_scripts) > 0):
@@ -220,6 +280,8 @@ class Api:
if not script_runner.scripts:
script_runner.initialize_scripts(False)
ui.create_ui()
+ if not self.default_script_arg_txt2img:
+ self.default_script_arg_txt2img = self.init_default_script_args(script_runner)
selectable_scripts, selectable_script_idx = self.get_selectable_script(txt2imgreq.script_name, script_runner)
populate = txt2imgreq.copy(update={ # Override __init__ params
@@ -235,7 +297,7 @@ class Api:
args.pop('script_args', None) # will refeed them to the pipeline directly after initializing them
args.pop('alwayson_scripts', None)
- script_args = self.init_script_args(txt2imgreq, selectable_scripts, selectable_script_idx, script_runner)
+ script_args = self.init_script_args(txt2imgreq, self.default_script_arg_txt2img, selectable_scripts, selectable_script_idx, script_runner)
send_images = args.pop('send_images', True)
args.pop('save_images', None)
@@ -272,6 +334,8 @@ class Api:
if not script_runner.scripts:
script_runner.initialize_scripts(True)
ui.create_ui()
+ if not self.default_script_arg_img2img:
+ self.default_script_arg_img2img = self.init_default_script_args(script_runner)
selectable_scripts, selectable_script_idx = self.get_selectable_script(img2imgreq.script_name, script_runner)
populate = img2imgreq.copy(update={ # Override __init__ params
@@ -289,7 +353,7 @@ class Api:
args.pop('script_args', None) # will refeed them to the pipeline directly after initializing them
args.pop('alwayson_scripts', None)
- script_args = self.init_script_args(img2imgreq, selectable_scripts, selectable_script_idx, script_runner)
+ script_args = self.init_script_args(img2imgreq, self.default_script_arg_img2img, selectable_scripts, selectable_script_idx, script_runner)
send_images = args.pop('send_images', True)
args.pop('save_images', None)
@@ -412,6 +476,16 @@ class Api:
return {}
+ def unloadapi(self):
+ unload_model_weights()
+
+ return {}
+
+ def reloadapi(self):
+ reload_model_weights()
+
+ return {}
+
def skip(self):
shared.state.skip()
diff --git a/modules/cmd_args.py b/modules/cmd_args.py
new file mode 100644
index 00000000..81c0b82a
--- /dev/null
+++ b/modules/cmd_args.py
@@ -0,0 +1,103 @@
+import argparse
+import os
+from modules.paths_internal import models_path, script_path, data_path, extensions_dir, extensions_builtin_dir, sd_default_config, sd_model_file
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument("-f", action='store_true', help=argparse.SUPPRESS) # allows running as root; implemented outside of webui
+parser.add_argument("--update-all-extensions", action='store_true', help="launch.py argument: download updates for all extensions when starting the program")
+parser.add_argument("--skip-python-version-check", action='store_true', help="launch.py argument: do not check python version")
+parser.add_argument("--skip-torch-cuda-test", action='store_true', help="launch.py argument: do not check if CUDA is able to work properly")
+parser.add_argument("--reinstall-xformers", action='store_true', help="launch.py argument: install the appropriate version of xformers even if you have some version already installed")
+parser.add_argument("--reinstall-torch", action='store_true', help="launch.py argument: install the appropriate version of torch even if you have some version already installed")
+parser.add_argument("--update-check", action='store_true', help="launch.py argument: chck for updates at startup")
+parser.add_argument("--tests", type=str, default=None, help="launch.py argument: run tests in the specified directory")
+parser.add_argument("--no-tests", action='store_true', help="launch.py argument: do not run tests even if --tests option is specified")
+parser.add_argument("--skip-install", action='store_true', help="launch.py argument: skip installation of packages")
+parser.add_argument("--data-dir", type=str, default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), help="base path where all user data is stored")
+parser.add_argument("--config", type=str, default=sd_default_config, help="path to config which constructs model",)
+parser.add_argument("--ckpt", type=str, default=sd_model_file, help="path to checkpoint of stable diffusion model; if specified, this checkpoint will be added to the list of checkpoints and loaded",)
+parser.add_argument("--ckpt-dir", type=str, default=None, help="Path to directory with stable diffusion checkpoints")
+parser.add_argument("--vae-dir", type=str, default=None, help="Path to directory with VAE files")
+parser.add_argument("--gfpgan-dir", type=str, help="GFPGAN directory", default=('./src/gfpgan' if os.path.exists('./src/gfpgan') else './GFPGAN'))
+parser.add_argument("--gfpgan-model", type=str, help="GFPGAN model file name", default=None)
+parser.add_argument("--no-half", action='store_true', help="do not switch the model to 16-bit floats")
+parser.add_argument("--no-half-vae", action='store_true', help="do not switch the VAE model to 16-bit floats")
+parser.add_argument("--no-progressbar-hiding", action='store_true', help="do not hide progressbar in gradio UI (we hide it because it slows down ML if you have hardware acceleration in browser)")
+parser.add_argument("--max-batch-count", type=int, default=16, help="maximum batch count value for the UI")
+parser.add_argument("--embeddings-dir", type=str, default=os.path.join(data_path, 'embeddings'), help="embeddings directory for textual inversion (default: embeddings)")
+parser.add_argument("--textual-inversion-templates-dir", type=str, default=os.path.join(script_path, 'textual_inversion_templates'), help="directory with textual inversion templates")
+parser.add_argument("--hypernetwork-dir", type=str, default=os.path.join(models_path, 'hypernetworks'), help="hypernetwork directory")
+parser.add_argument("--localizations-dir", type=str, default=os.path.join(script_path, 'localizations'), help="localizations directory")
+parser.add_argument("--allow-code", action='store_true', help="allow custom script execution from webui")
+parser.add_argument("--medvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a little speed for low VRM usage")
+parser.add_argument("--lowvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a lot of speed for very low VRM usage")
+parser.add_argument("--lowram", action='store_true', help="load stable diffusion checkpoint weights to VRAM instead of RAM")
+parser.add_argument("--always-batch-cond-uncond", action='store_true', help="disables cond/uncond batching that is enabled to save memory with --medvram or --lowvram")
+parser.add_argument("--unload-gfpgan", action='store_true', help="does not do anything.")
+parser.add_argument("--precision", type=str, help="evaluate at this precision", choices=["full", "autocast"], default="autocast")
+parser.add_argument("--upcast-sampling", action='store_true', help="upcast sampling. No effect with --no-half. Usually produces similar results to --no-half with better performance while using less memory.")
+parser.add_argument("--share", action='store_true', help="use share=True for gradio and make the UI accessible through their site")
+parser.add_argument("--ngrok", type=str, help="ngrok authtoken, alternative to gradio --share", default=None)
+parser.add_argument("--ngrok-region", type=str, help="The region in which ngrok should start.", default="us")
+parser.add_argument("--enable-insecure-extension-access", action='store_true', help="enable extensions tab regardless of other options")
+parser.add_argument("--codeformer-models-path", type=str, help="Path to directory with codeformer model file(s).", default=os.path.join(models_path, 'Codeformer'))
+parser.add_argument("--gfpgan-models-path", type=str, help="Path to directory with GFPGAN model file(s).", default=os.path.join(models_path, 'GFPGAN'))
+parser.add_argument("--esrgan-models-path", type=str, help="Path to directory with ESRGAN model file(s).", default=os.path.join(models_path, 'ESRGAN'))
+parser.add_argument("--bsrgan-models-path", type=str, help="Path to directory with BSRGAN model file(s).", default=os.path.join(models_path, 'BSRGAN'))
+parser.add_argument("--realesrgan-models-path", type=str, help="Path to directory with RealESRGAN model file(s).", default=os.path.join(models_path, 'RealESRGAN'))
+parser.add_argument("--clip-models-path", type=str, help="Path to directory with CLIP model file(s).", default=None)
+parser.add_argument("--xformers", action='store_true', help="enable xformers for cross attention layers")
+parser.add_argument("--force-enable-xformers", action='store_true', help="enable xformers for cross attention layers regardless of whether the checking code thinks you can run it; do not make bug reports if this fails to work")
+parser.add_argument("--xformers-flash-attention", action='store_true', help="enable xformers with Flash Attention to improve reproducibility (supported for SD2.x or variant only)")
+parser.add_argument("--deepdanbooru", action='store_true', help="does not do anything")
+parser.add_argument("--opt-split-attention", action='store_true', help="force-enables Doggettx's cross-attention layer optimization. By default, it's on for torch cuda.")
+parser.add_argument("--opt-sub-quad-attention", action='store_true', help="enable memory efficient sub-quadratic cross-attention layer optimization")
+parser.add_argument("--sub-quad-q-chunk-size", type=int, help="query chunk size for the sub-quadratic cross-attention layer optimization to use", default=1024)
+parser.add_argument("--sub-quad-kv-chunk-size", type=int, help="kv chunk size for the sub-quadratic cross-attention layer optimization to use", default=None)
+parser.add_argument("--sub-quad-chunk-threshold", type=int, help="the percentage of VRAM threshold for the sub-quadratic cross-attention layer optimization to use chunking", default=None)
+parser.add_argument("--opt-split-attention-invokeai", action='store_true', help="force-enables InvokeAI's cross-attention layer optimization. By default, it's on when cuda is unavailable.")
+parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find")
+parser.add_argument("--opt-sdp-attention", action='store_true', help="enable scaled dot product cross-attention layer optimization; requires PyTorch 2.*")
+parser.add_argument("--opt-sdp-no-mem-attention", action='store_true', help="enable scaled dot product cross-attention layer optimization without memory efficient attention, makes image generation deterministic; requires PyTorch 2.*")
+parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization")
+parser.add_argument("--disable-nan-check", action='store_true', help="do not check if produced images/latent spaces have nans; useful for running without a checkpoint in CI")
+parser.add_argument("--use-cpu", nargs='+', help="use CPU as torch device for specified modules", default=[], type=str.lower)
+parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests")
+parser.add_argument("--port", type=int, help="launch gradio with given server port, you need root/admin rights for ports < 1024, defaults to 7860 if available", default=None)
+parser.add_argument("--show-negative-prompt", action='store_true', help="does not do anything", default=False)
+parser.add_argument("--ui-config-file", type=str, help="filename to use for ui configuration", default=os.path.join(data_path, 'ui-config.json'))
+parser.add_argument("--hide-ui-dir-config", action='store_true', help="hide directory configuration from webui", default=False)
+parser.add_argument("--freeze-settings", action='store_true', help="disable editing settings", default=False)
+parser.add_argument("--ui-settings-file", type=str, help="filename to use for ui settings", default=os.path.join(data_path, 'config.json'))
+parser.add_argument("--gradio-debug", action='store_true', help="launch gradio with --debug option")
+parser.add_argument("--gradio-auth", type=str, help='set gradio authentication like "username:password"; or comma-delimit multiple like "u1:p1,u2:p2,u3:p3"', default=None)
+parser.add_argument("--gradio-auth-path", type=str, help='set gradio authentication file path ex. "/path/to/auth/file" same auth format as --gradio-auth', default=None)
+parser.add_argument("--gradio-img2img-tool", type=str, help='does not do anything')
+parser.add_argument("--gradio-inpaint-tool", type=str, help="does not do anything")
+parser.add_argument("--opt-channelslast", action='store_true', help="change memory type for stable diffusion to channels last")
+parser.add_argument("--styles-file", type=str, help="filename to use for styles", default=os.path.join(data_path, 'styles.csv'))
+parser.add_argument("--autolaunch", action='store_true', help="open the webui URL in the system's default browser upon launch", default=False)
+parser.add_argument("--theme", type=str, help="launches the UI with light or dark theme", default=None)
+parser.add_argument("--use-textbox-seed", action='store_true', help="use textbox for seeds in UI (no up/down, but possible to input long seeds)", default=False)
+parser.add_argument("--disable-console-progressbars", action='store_true', help="do not output progressbars to console", default=False)
+parser.add_argument("--enable-console-prompts", action='store_true', help="print prompts to console when generating with txt2img and img2img", default=False)
+parser.add_argument('--vae-path', type=str, help='Checkpoint to use as VAE; setting this argument disables all settings related to VAE', default=None)
+parser.add_argument("--disable-safe-unpickle", action='store_true', help="disable checking pytorch models for malicious code", default=False)
+parser.add_argument("--api", action='store_true', help="use api=True to launch the API together with the webui (use --nowebui instead for only the API)")
+parser.add_argument("--api-auth", type=str, help='Set authentication for API like "username:password"; or comma-delimit multiple like "u1:p1,u2:p2,u3:p3"', default=None)
+parser.add_argument("--api-log", action='store_true', help="use api-log=True to enable logging of all API requests")
+parser.add_argument("--nowebui", action='store_true', help="use api=True to launch the API instead of the webui")
+parser.add_argument("--ui-debug-mode", action='store_true', help="Don't load model to quickly launch UI")
+parser.add_argument("--device-id", type=str, help="Select the default CUDA device to use (export CUDA_VISIBLE_DEVICES=0,1,etc might be needed before)", default=None)
+parser.add_argument("--administrator", action='store_true', help="Administrator rights", default=False)
+parser.add_argument("--cors-allow-origins", type=str, help="Allowed CORS origin(s) in the form of a comma-separated list (no spaces)", default=None)
+parser.add_argument("--cors-allow-origins-regex", type=str, help="Allowed CORS origin(s) in the form of a single regular expression", default=None)
+parser.add_argument("--tls-keyfile", type=str, help="Partially enables TLS, requires --tls-certfile to fully function", default=None)
+parser.add_argument("--tls-certfile", type=str, help="Partially enables TLS, requires --tls-keyfile to fully function", default=None)
+parser.add_argument("--server-name", type=str, help="Sets hostname of server", default=None)
+parser.add_argument("--gradio-queue", action='store_true', help="does not do anything", default=True)
+parser.add_argument("--no-gradio-queue", action='store_true', help="Disables gradio queue; causes the webpage to use http requests instead of websockets; was the defaul in earlier versions")
+parser.add_argument("--skip-version-check", action='store_true', help="Do not check versions of torch and xformers")
+parser.add_argument("--no-hashing", action='store_true', help="disable sha256 hashing of checkpoints to help loading performance", default=False)
+parser.add_argument("--no-download-sd-model", action='store_true', help="don't download SD1.5 model even if no model is found in --ckpt-dir", default=False)
diff --git a/modules/extensions.py b/modules/extensions.py
index ed4b58fe..3a7a0372 100644
--- a/modules/extensions.py
+++ b/modules/extensions.py
@@ -5,17 +5,22 @@ import traceback
import time
import git
-from modules import paths, shared
+from modules import shared
+from modules.paths_internal import extensions_dir, extensions_builtin_dir
extensions = []
-extensions_dir = os.path.join(paths.data_path, "extensions")
-extensions_builtin_dir = os.path.join(paths.script_path, "extensions-builtin")
if not os.path.exists(extensions_dir):
os.makedirs(extensions_dir)
+
def active():
- return [x for x in extensions if x.enabled]
+ if shared.opts.disable_all_extensions == "all":
+ return []
+ elif shared.opts.disable_all_extensions == "extra":
+ return [x for x in extensions if x.enabled and x.is_builtin]
+ else:
+ return [x for x in extensions if x.enabled]
class Extension:
@@ -27,21 +32,29 @@ class Extension:
self.can_update = False
self.is_builtin = is_builtin
self.version = ''
+ self.remote = None
+ self.have_info_from_repo = False
+
+ def read_info_from_repo(self):
+ if self.have_info_from_repo:
+ return
+
+ self.have_info_from_repo = True
repo = None
try:
- if os.path.exists(os.path.join(path, ".git")):
- repo = git.Repo(path)
+ if os.path.exists(os.path.join(self.path, ".git")):
+ repo = git.Repo(self.path)
except Exception:
- print(f"Error reading github repository info from {path}:", file=sys.stderr)
+ print(f"Error reading github repository info from {self.path}:", file=sys.stderr)
print(traceback.format_exc(), file=sys.stderr)
if repo is None or repo.bare:
self.remote = None
else:
try:
- self.remote = next(repo.remote().urls, None)
self.status = 'unknown'
+ self.remote = next(repo.remote().urls, None)
head = repo.head.commit
ts = time.asctime(time.gmtime(repo.head.commit.committed_date))
self.version = f'{head.hexsha[:8]} ({ts})'
@@ -89,7 +102,12 @@ def list_extensions():
if not os.path.isdir(extensions_dir):
return
- paths = []
+ if shared.opts.disable_all_extensions == "all":
+ print("*** \"Disable all extensions\" option was set, will not load any extensions ***")
+ elif shared.opts.disable_all_extensions == "extra":
+ print("*** \"Disable all extensions\" option was set, will only load built-in extensions ***")
+
+ extension_paths = []
for dirname in [extensions_dir, extensions_builtin_dir]:
if not os.path.isdir(dirname):
return
@@ -99,9 +117,8 @@ def list_extensions():
if not os.path.isdir(path):
continue
- paths.append((extension_dirname, path, dirname == extensions_builtin_dir))
+ extension_paths.append((extension_dirname, path, dirname == extensions_builtin_dir))
- for dirname, path, is_builtin in paths:
+ for dirname, path, is_builtin in extension_paths:
extension = Extension(name=dirname, path=path, enabled=dirname not in shared.opts.disabled_extensions, is_builtin=is_builtin)
extensions.append(extension)
-
diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py
index d0cf3e8c..162ea59e 100644
--- a/modules/generation_parameters_copypaste.py
+++ b/modules/generation_parameters_copypaste.py
@@ -401,9 +401,14 @@ def connect_paste(button, paste_fields, input_comp, override_settings_component,
button.click(
fn=paste_func,
- _js=f"recalculate_prompts_{tabname}",
inputs=[input_comp],
outputs=[x[0] for x in paste_fields],
)
+ button.click(
+ fn=None,
+ _js=f"recalculate_prompts_{tabname}",
+ inputs=[],
+ outputs=[],
+ )
diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py
index f6ef42d5..1fc49537 100644
--- a/modules/hypernetworks/hypernetwork.py
+++ b/modules/hypernetworks/hypernetwork.py
@@ -312,7 +312,7 @@ class Hypernetwork:
def list_hypernetworks(path):
res = {}
- for filename in sorted(glob.iglob(os.path.join(path, '**/*.pt'), recursive=True)):
+ for filename in sorted(glob.iglob(os.path.join(path, '**/*.pt'), recursive=True), key=str.lower):
name = os.path.splitext(os.path.basename(filename))[0]
# Prevent a hypothetical "None.pt" from being listed.
if name != "None":
diff --git a/modules/images.py b/modules/images.py
index 2da988ee..b3535070 100644
--- a/modules/images.py
+++ b/modules/images.py
@@ -261,9 +261,12 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None):
if scale > 1.0:
upscalers = [x for x in shared.sd_upscalers if x.name == upscaler_name]
- assert len(upscalers) > 0, f"could not find upscaler named {upscaler_name}"
+ if len(upscalers) == 0:
+ upscaler = shared.sd_upscalers[0]
+ print(f"could not find upscaler named {upscaler_name or ''}, using {upscaler.name} as a fallback")
+ else:
+ upscaler = upscalers[0]
- upscaler = upscalers[0]
im = upscaler.scaler.upscale(im, scale, upscaler.data_path)
if im.width != w or im.height != h:
@@ -645,6 +648,8 @@ Steps: {json_info["steps"]}, Sampler: {sampler}, CFG scale: {json_info["scale"]}
def image_data(data):
+ import gradio as gr
+
try:
image = Image.open(io.BytesIO(data))
textinfo, _ = read_info_from_image(image)
@@ -660,7 +665,7 @@ def image_data(data):
except Exception:
pass
- return '', None
+ return gr.update(), None
def flatten(img, bgcolor):
diff --git a/modules/img2img.py b/modules/img2img.py
index 735a8a1a..4dad4eb5 100644
--- a/modules/img2img.py
+++ b/modules/img2img.py
@@ -159,7 +159,8 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s
if shared.cmd_opts.enable_console_prompts:
print(f"\nimg2img: {prompt}", file=shared.progress_print_out)
- p.extra_generation_params["Mask blur"] = mask_blur
+ if mask:
+ p.extra_generation_params["Mask blur"] = mask_blur
if is_batch:
assert not shared.cmd_opts.hide_ui_dir_config, "Launched with --hide-ui-dir-config, batch img2img disabled"
diff --git a/modules/lowvram.py b/modules/lowvram.py
index 042a0254..e254cc13 100644
--- a/modules/lowvram.py
+++ b/modules/lowvram.py
@@ -55,12 +55,12 @@ def setup_for_low_vram(sd_model, use_medvram):
if hasattr(sd_model.cond_stage_model, 'model'):
sd_model.cond_stage_model.transformer = sd_model.cond_stage_model.model
- # remove four big modules, cond, first_stage, depth (if applicable), and unet from the model and then
+ # remove several big modules: cond, first_stage, depth/embedder (if applicable), and unet from the model and then
# send the model to GPU. Then put modules back. the modules will be in CPU.
- stored = sd_model.cond_stage_model.transformer, sd_model.first_stage_model, getattr(sd_model, 'depth_model', None), sd_model.model
- sd_model.cond_stage_model.transformer, sd_model.first_stage_model, sd_model.depth_model, sd_model.model = None, None, None, None
+ stored = sd_model.cond_stage_model.transformer, sd_model.first_stage_model, getattr(sd_model, 'depth_model', None), getattr(sd_model, 'embedder', None), sd_model.model
+ sd_model.cond_stage_model.transformer, sd_model.first_stage_model, sd_model.depth_model, sd_model.embedder, sd_model.model = None, None, None, None, None
sd_model.to(devices.device)
- sd_model.cond_stage_model.transformer, sd_model.first_stage_model, sd_model.depth_model, sd_model.model = stored
+ sd_model.cond_stage_model.transformer, sd_model.first_stage_model, sd_model.depth_model, sd_model.embedder, sd_model.model = stored
# register hooks for those the first three models
sd_model.cond_stage_model.transformer.register_forward_pre_hook(send_me_to_gpu)
@@ -69,6 +69,8 @@ def setup_for_low_vram(sd_model, use_medvram):
sd_model.first_stage_model.decode = first_stage_model_decode_wrap
if sd_model.depth_model:
sd_model.depth_model.register_forward_pre_hook(send_me_to_gpu)
+ if sd_model.embedder:
+ sd_model.embedder.register_forward_pre_hook(send_me_to_gpu)
parents[sd_model.cond_stage_model.transformer] = sd_model.cond_stage_model
if hasattr(sd_model.cond_stage_model, 'model'):
diff --git a/modules/mac_specific.py b/modules/mac_specific.py
index 18e6ff72..6fe8dea0 100644
--- a/modules/mac_specific.py
+++ b/modules/mac_specific.py
@@ -1,4 +1,5 @@
import torch
+import platform
from modules import paths
from modules.sd_hijack_utils import CondFunc
from packaging import version
@@ -32,6 +33,10 @@ if has_mps:
# MPS fix for randn in torchsde
CondFunc('torchsde._brownian.brownian_interval._randn', lambda _, size, dtype, device, seed: torch.randn(size, dtype=dtype, device=torch.device("cpu"), generator=torch.Generator(torch.device("cpu")).manual_seed(int(seed))).to(device), lambda _, size, dtype, device, seed: device.type == 'mps')
+ if platform.mac_ver()[0].startswith("13.2."):
+ # MPS workaround for https://github.com/pytorch/pytorch/issues/95188, thanks to danieldk (https://github.com/explosion/curated-transformers/pull/124)
+ CondFunc('torch.nn.functional.linear', lambda _, input, weight, bias: (torch.matmul(input, weight.t()) + bias) if bias is not None else torch.matmul(input, weight.t()), lambda _, input, weight, bias: input.numel() > 10485760)
+
if version.parse(torch.__version__) < version.parse("1.13"):
# PyTorch 1.13 doesn't need these fixes but unfortunately is slower and has regressions that prevent training from working
@@ -49,4 +54,6 @@ if has_mps:
CondFunc('torch.cumsum', cumsum_fix_func, None)
CondFunc('torch.Tensor.cumsum', cumsum_fix_func, None)
CondFunc('torch.narrow', lambda orig_func, *args, **kwargs: orig_func(*args, **kwargs).clone(), None)
-
+ if version.parse(torch.__version__) == version.parse("2.0"):
+ # MPS workaround for https://github.com/pytorch/pytorch/issues/96113
+ CondFunc('torch.nn.functional.layer_norm', lambda orig_func, x, normalized_shape, weight, bias, eps, **kwargs: orig_func(x.float(), normalized_shape, weight.float() if weight is not None else None, bias.float() if bias is not None else bias, eps).to(x.dtype), lambda *args, **kwargs: len(args) == 6)
diff --git a/modules/modelloader.py b/modules/modelloader.py
index e351d808..522affc6 100644
--- a/modules/modelloader.py
+++ b/modules/modelloader.py
@@ -4,7 +4,6 @@ import shutil
import importlib
from urllib.parse import urlparse
-from basicsr.utils.download_util import load_file_from_url
from modules import shared
from modules.upscaler import Upscaler, UpscalerLanczos, UpscalerNearest, UpscalerNone
from modules.paths import script_path, models_path
@@ -59,6 +58,7 @@ def load_models(model_path: str, model_url: str = None, command_path: str = None
if model_url is not None and len(output) == 0:
if download_name is not None:
+ from basicsr.utils.download_util import load_file_from_url
dl = load_file_from_url(model_url, model_path, True, download_name)
output.append(dl)
else:
diff --git a/modules/paths.py b/modules/paths.py
index d991cc71..0e1e00e7 100644
--- a/modules/paths.py
+++ b/modules/paths.py
@@ -1,16 +1,9 @@
-import argparse
import os
import sys
+from modules.paths_internal import models_path, script_path, data_path, extensions_dir, extensions_builtin_dir
+
import modules.safe
-script_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
-
-# Parse the --data-dir flag first so we can use it as a base for our other argument default values
-parser = argparse.ArgumentParser(add_help=False)
-parser.add_argument("--data-dir", type=str, default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), help="base path where all user data is stored",)
-cmd_opts_pre = parser.parse_known_args()[0]
-data_path = cmd_opts_pre.data_dir
-models_path = os.path.join(data_path, "models")
# data_path = cmd_opts_pre.data
sys.path.insert(0, script_path)
diff --git a/modules/paths_internal.py b/modules/paths_internal.py
new file mode 100644
index 00000000..926ec3bb
--- /dev/null
+++ b/modules/paths_internal.py
@@ -0,0 +1,22 @@
+"""this module defines internal paths used by program and is safe to import before dependencies are installed in launch.py"""
+
+import argparse
+import os
+
+script_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+
+sd_configs_path = os.path.join(script_path, "configs")
+sd_default_config = os.path.join(sd_configs_path, "v1-inference.yaml")
+sd_model_file = os.path.join(script_path, 'model.ckpt')
+default_sd_model_file = sd_model_file
+
+# Parse the --data-dir flag first so we can use it as a base for our other argument default values
+parser_pre = argparse.ArgumentParser(add_help=False)
+parser_pre.add_argument("--data-dir", type=str, default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), help="base path where all user data is stored",)
+cmd_opts_pre = parser_pre.parse_known_args()[0]
+
+data_path = cmd_opts_pre.data_dir
+
+models_path = os.path.join(data_path, "models")
+extensions_dir = os.path.join(data_path, "extensions")
+extensions_builtin_dir = os.path.join(script_path, "extensions-builtin")
diff --git a/modules/processing.py b/modules/processing.py
index 59717b4c..6d9c6a8d 100644
--- a/modules/processing.py
+++ b/modules/processing.py
@@ -78,22 +78,28 @@ def apply_overlay(image, paste_loc, index, overlays):
def txt2img_image_conditioning(sd_model, x, width, height):
- if sd_model.model.conditioning_key not in {'hybrid', 'concat'}:
- # Dummy zero conditioning if we're not using inpainting model.
+ if sd_model.model.conditioning_key in {'hybrid', 'concat'}: # Inpainting models
+
+ # The "masked-image" in this case will just be all zeros since the entire image is masked.
+ image_conditioning = torch.zeros(x.shape[0], 3, height, width, device=x.device)
+ image_conditioning = sd_model.get_first_stage_encoding(sd_model.encode_first_stage(image_conditioning))
+
+ # Add the fake full 1s mask to the first dimension.
+ image_conditioning = torch.nn.functional.pad(image_conditioning, (0, 0, 0, 0, 1, 0), value=1.0)
+ image_conditioning = image_conditioning.to(x.dtype)
+
+ return image_conditioning
+
+ elif sd_model.model.conditioning_key == "crossattn-adm": # UnCLIP models
+
+ return x.new_zeros(x.shape[0], 2*sd_model.noise_augmentor.time_embed.dim, dtype=x.dtype, device=x.device)
+
+ else:
+ # Dummy zero conditioning if we're not using inpainting or unclip models.
# Still takes up a bit of memory, but no encoder call.
# Pretty sure we can just make this a 1x1 image since its not going to be used besides its batch size.
return x.new_zeros(x.shape[0], 5, 1, 1, dtype=x.dtype, device=x.device)
- # The "masked-image" in this case will just be all zeros since the entire image is masked.
- image_conditioning = torch.zeros(x.shape[0], 3, height, width, device=x.device)
- image_conditioning = sd_model.get_first_stage_encoding(sd_model.encode_first_stage(image_conditioning))
-
- # Add the fake full 1s mask to the first dimension.
- image_conditioning = torch.nn.functional.pad(image_conditioning, (0, 0, 0, 0, 1, 0), value=1.0)
- image_conditioning = image_conditioning.to(x.dtype)
-
- return image_conditioning
-
class StableDiffusionProcessing:
"""
@@ -190,6 +196,14 @@ class StableDiffusionProcessing:
return conditioning_image
+ def unclip_image_conditioning(self, source_image):
+ c_adm = self.sd_model.embedder(source_image)
+ if self.sd_model.noise_augmentor is not None:
+ noise_level = 0 # TODO: Allow other noise levels?
+ c_adm, noise_level_emb = self.sd_model.noise_augmentor(c_adm, noise_level=repeat(torch.tensor([noise_level]).to(c_adm.device), '1 -> b', b=c_adm.shape[0]))
+ c_adm = torch.cat((c_adm, noise_level_emb), 1)
+ return c_adm
+
def inpainting_image_conditioning(self, source_image, latent_image, image_mask=None):
self.is_using_inpainting_conditioning = True
@@ -241,6 +255,9 @@ class StableDiffusionProcessing:
if self.sampler.conditioning_key in {'hybrid', 'concat'}:
return self.inpainting_image_conditioning(source_image, latent_image, image_mask=image_mask)
+ if self.sampler.conditioning_key == "crossattn-adm":
+ return self.unclip_image_conditioning(source_image)
+
# Dummy zero conditioning if we're not using inpainting or depth model.
return latent_image.new_zeros(latent_image.shape[0], 5, 1, 1)
@@ -689,6 +706,22 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
image.info["parameters"] = text
output_images.append(image)
+ if hasattr(p, 'mask_for_overlay') and p.mask_for_overlay:
+ image_mask = p.mask_for_overlay.convert('RGB')
+ image_mask_composite = Image.composite(image.convert('RGBA').convert('RGBa'), Image.new('RGBa', image.size), p.mask_for_overlay.convert('L')).convert('RGBA')
+
+ if opts.save_mask:
+ images.save_image(image_mask, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-mask")
+
+ if opts.save_mask_composite:
+ images.save_image(image_mask_composite, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-mask-composite")
+
+ if opts.return_mask:
+ output_images.append(image_mask)
+
+ if opts.return_mask_composite:
+ output_images.append(image_mask_composite)
+
del x_samples_ddim
devices.torch_gc()
diff --git a/modules/scripts.py b/modules/scripts.py
index 8de19884..b3ab915d 100644
--- a/modules/scripts.py
+++ b/modules/scripts.py
@@ -239,7 +239,15 @@ def load_scripts():
elif issubclass(script_class, scripts_postprocessing.ScriptPostprocessing):
postprocessing_scripts_data.append(ScriptClassData(script_class, scriptfile.path, scriptfile.basedir, module))
- for scriptfile in sorted(scripts_list):
+ def orderby(basedir):
+ # 1st webui, 2nd extensions-builtin, 3rd extensions
+ priority = {os.path.join(paths.script_path, "extensions-builtin"):1, paths.script_path:0}
+ for key in priority:
+ if basedir.startswith(key):
+ return priority[key]
+ return 9999
+
+ for scriptfile in sorted(scripts_list, key=lambda x: [orderby(x.basedir), x]):
try:
if scriptfile.basedir != paths.script_path:
sys.path = [scriptfile.basedir] + sys.path
@@ -332,7 +340,7 @@ class ScriptRunner:
script.args_to = len(inputs)
for script in self.alwayson_scripts:
- with gr.Group() as group:
+ with gr.Group(elem_classes="script-alwayson-group") as group:
create_script_ui(script, inputs, inputs_alwayson)
script.group = group
@@ -341,7 +349,7 @@ class ScriptRunner:
inputs[0] = dropdown
for script in self.selectable_scripts:
- with gr.Group(visible=False) as group:
+ with gr.Group(visible=False, elem_classes="script-group") as group:
create_script_ui(script, inputs, inputs_alwayson)
script.group = group
@@ -513,6 +521,18 @@ def reload_scripts():
scripts_postproc = scripts_postprocessing.ScriptPostprocessingRunner()
+def add_classes_to_gradio_component(comp):
+ """
+ this adds gradio-* to the component for css styling (ie gradio-button to gr.Button), as well as some others
+ """
+
+ comp.elem_classes = ["gradio-" + comp.get_block_name(), *(comp.elem_classes or [])]
+
+ if getattr(comp, 'multiselect', False):
+ comp.elem_classes.append('multiselect')
+
+
+
def IOComponent_init(self, *args, **kwargs):
if scripts_current is not None:
scripts_current.before_component(self, **kwargs)
@@ -521,6 +541,8 @@ def IOComponent_init(self, *args, **kwargs):
res = original_IOComponent_init(self, *args, **kwargs)
+ add_classes_to_gradio_component(self)
+
script_callbacks.after_component_callback(self, **kwargs)
if scripts_current is not None:
@@ -531,3 +553,15 @@ def IOComponent_init(self, *args, **kwargs):
original_IOComponent_init = gr.components.IOComponent.__init__
gr.components.IOComponent.__init__ = IOComponent_init
+
+
+def BlockContext_init(self, *args, **kwargs):
+ res = original_BlockContext_init(self, *args, **kwargs)
+
+ add_classes_to_gradio_component(self)
+
+ return res
+
+
+original_BlockContext_init = gr.blocks.BlockContext.__init__
+gr.blocks.BlockContext.__init__ = BlockContext_init
diff --git a/modules/scripts_postprocessing.py b/modules/scripts_postprocessing.py
index ce0ebb61..b11568c0 100644
--- a/modules/scripts_postprocessing.py
+++ b/modules/scripts_postprocessing.py
@@ -109,7 +109,7 @@ class ScriptPostprocessingRunner:
inputs = []
for script in self.scripts_in_preferred_order():
- with gr.Box() as group:
+ with gr.Row() as group:
self.create_script_ui(script, inputs)
script.group = group
diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py
index 2e307b5d..372555ff 100644
--- a/modules/sd_hijack_optimizations.py
+++ b/modules/sd_hijack_optimizations.py
@@ -337,7 +337,7 @@ def xformers_attention_forward(self, x, context=None, mask=None):
dtype = q.dtype
if shared.opts.upcast_attn:
- q, k = q.float(), k.float()
+ q, k, v = q.float(), k.float(), v.float()
out = xformers.ops.memory_efficient_attention(q, k, v, attn_bias=None, op=get_xformers_flash_attention_op(q, k, v))
@@ -372,7 +372,7 @@ def scaled_dot_product_attention_forward(self, x, context=None, mask=None):
dtype = q.dtype
if shared.opts.upcast_attn:
- q, k = q.float(), k.float()
+ q, k, v = q.float(), k.float(), v.float()
# the output of sdp = (batch, num_heads, seq_len, head_dim)
hidden_states = torch.nn.functional.scaled_dot_product_attention(
diff --git a/modules/sd_hijack_unet.py b/modules/sd_hijack_unet.py
index 843ab66c..15858263 100644
--- a/modules/sd_hijack_unet.py
+++ b/modules/sd_hijack_unet.py
@@ -67,7 +67,7 @@ def hijack_ddpm_edit():
unet_needs_upcast = lambda *args, **kwargs: devices.unet_needs_upcast
CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.apply_model', apply_model, unet_needs_upcast)
CondFunc('ldm.modules.diffusionmodules.openaimodel.timestep_embedding', lambda orig_func, timesteps, *args, **kwargs: orig_func(timesteps, *args, **kwargs).to(torch.float32 if timesteps.dtype == torch.int64 else devices.dtype_unet), unet_needs_upcast)
-if version.parse(torch.__version__) <= version.parse("1.13.1"):
+if version.parse(torch.__version__) <= version.parse("1.13.2") or torch.cuda.is_available():
CondFunc('ldm.modules.diffusionmodules.util.GroupNorm32.forward', lambda orig_func, self, *args, **kwargs: orig_func(self.float(), *args, **kwargs), unet_needs_upcast)
CondFunc('ldm.modules.attention.GEGLU.forward', lambda orig_func, self, x: orig_func(self.float(), x.float()).to(devices.dtype_unet), unet_needs_upcast)
CondFunc('open_clip.transformer.ResidualAttentionBlock.__init__', lambda orig_func, *args, **kwargs: kwargs.update({'act_layer': GELUHijack}) and False or orig_func(*args, **kwargs), lambda _, *args, **kwargs: kwargs.get('act_layer') is None or kwargs['act_layer'] == torch.nn.GELU)
diff --git a/modules/sd_models.py b/modules/sd_models.py
index f0cb1240..6ea874df 100644
--- a/modules/sd_models.py
+++ b/modules/sd_models.py
@@ -122,7 +122,7 @@ def list_models():
elif cmd_ckpt is not None and cmd_ckpt != shared.default_sd_model_file:
print(f"Checkpoint in --ckpt argument not found (Possible it was moved to {model_path}: {cmd_ckpt}", file=sys.stderr)
- for filename in model_list:
+ for filename in sorted(model_list, key=str.lower):
checkpoint_info = CheckpointInfo(filename)
checkpoint_info.register()
@@ -178,7 +178,7 @@ def select_checkpoint():
return checkpoint_info
-chckpoint_dict_replacements = {
+checkpoint_dict_replacements = {
'cond_stage_model.transformer.embeddings.': 'cond_stage_model.transformer.text_model.embeddings.',
'cond_stage_model.transformer.encoder.': 'cond_stage_model.transformer.text_model.encoder.',
'cond_stage_model.transformer.final_layer_norm.': 'cond_stage_model.transformer.text_model.final_layer_norm.',
@@ -186,7 +186,7 @@ chckpoint_dict_replacements = {
def transform_checkpoint_dict_key(k):
- for text, replacement in chckpoint_dict_replacements.items():
+ for text, replacement in checkpoint_dict_replacements.items():
if k.startswith(text):
k = replacement + k[len(text):]
@@ -383,6 +383,14 @@ def repair_config(sd_config):
elif shared.cmd_opts.upcast_sampling:
sd_config.model.params.unet_config.params.use_fp16 = True
+ if getattr(sd_config.model.params.first_stage_config.params.ddconfig, "attn_type", None) == "vanilla-xformers" and not shared.xformers_available:
+ sd_config.model.params.first_stage_config.params.ddconfig.attn_type = "vanilla"
+
+ # For UnCLIP-L, override the hardcoded karlo directory
+ if hasattr(sd_config.model.params, "noise_aug_config") and hasattr(sd_config.model.params.noise_aug_config.params, "clip_stats_path"):
+ karlo_path = os.path.join(paths.models_path, 'karlo')
+ sd_config.model.params.noise_aug_config.params.clip_stats_path = sd_config.model.params.noise_aug_config.params.clip_stats_path.replace("checkpoints/karlo_models", karlo_path)
+
sd1_clip_weight = 'cond_stage_model.transformer.text_model.embeddings.token_embedding.weight'
sd2_clip_weight = 'cond_stage_model.model.transformer.resblocks.0.attn.in_proj_weight'
@@ -494,7 +502,7 @@ def reload_model_weights(sd_model=None, info=None):
if sd_model is None or checkpoint_config != sd_model.used_config:
del sd_model
checkpoints_loaded.clear()
- load_model(checkpoint_info, already_loaded_state_dict=state_dict, time_taken_to_load_state_dict=timer.records["load weights from disk"])
+ load_model(checkpoint_info, already_loaded_state_dict=state_dict)
return shared.sd_model
try:
@@ -517,3 +525,23 @@ def reload_model_weights(sd_model=None, info=None):
print(f"Weights loaded in {timer.summary()}.")
return sd_model
+
+def unload_model_weights(sd_model=None, info=None):
+ from modules import lowvram, devices, sd_hijack
+ timer = Timer()
+
+ if shared.sd_model:
+
+ # shared.sd_model.cond_stage_model.to(devices.cpu)
+ # shared.sd_model.first_stage_model.to(devices.cpu)
+ shared.sd_model.to(devices.cpu)
+ sd_hijack.model_hijack.undo_hijack(shared.sd_model)
+ shared.sd_model = None
+ sd_model = None
+ gc.collect()
+ devices.torch_gc()
+ torch.cuda.empty_cache()
+
+ print(f"Unloaded weights {timer.summary()}.")
+
+ return sd_model
\ No newline at end of file
diff --git a/modules/sd_models_config.py b/modules/sd_models_config.py
index 91c21700..9398f528 100644
--- a/modules/sd_models_config.py
+++ b/modules/sd_models_config.py
@@ -14,6 +14,8 @@ config_sd2 = os.path.join(sd_repo_configs_path, "v2-inference.yaml")
config_sd2v = os.path.join(sd_repo_configs_path, "v2-inference-v.yaml")
config_sd2_inpainting = os.path.join(sd_repo_configs_path, "v2-inpainting-inference.yaml")
config_depth_model = os.path.join(sd_repo_configs_path, "v2-midas-inference.yaml")
+config_unclip = os.path.join(sd_repo_configs_path, "v2-1-stable-unclip-l-inference.yaml")
+config_unopenclip = os.path.join(sd_repo_configs_path, "v2-1-stable-unclip-h-inference.yaml")
config_inpainting = os.path.join(sd_configs_path, "v1-inpainting-inference.yaml")
config_instruct_pix2pix = os.path.join(sd_configs_path, "instruct-pix2pix.yaml")
config_alt_diffusion = os.path.join(sd_configs_path, "alt-diffusion-inference.yaml")
@@ -65,9 +67,14 @@ def is_using_v_parameterization_for_sd2(state_dict):
def guess_model_config_from_state_dict(sd, filename):
sd2_cond_proj_weight = sd.get('cond_stage_model.model.transformer.resblocks.0.attn.in_proj_weight', None)
diffusion_model_input = sd.get('model.diffusion_model.input_blocks.0.0.weight', None)
+ sd2_variations_weight = sd.get('embedder.model.ln_final.weight', None)
if sd.get('depth_model.model.pretrained.act_postprocess3.0.project.0.bias', None) is not None:
return config_depth_model
+ elif sd2_variations_weight is not None and sd2_variations_weight.shape[0] == 768:
+ return config_unclip
+ elif sd2_variations_weight is not None and sd2_variations_weight.shape[0] == 1024:
+ return config_unopenclip
if sd2_cond_proj_weight is not None and sd2_cond_proj_weight.shape[1] == 1024:
if diffusion_model_input.shape[1] == 9:
diff --git a/modules/sd_samplers_compvis.py b/modules/sd_samplers_compvis.py
index 083da18c..bfcc5574 100644
--- a/modules/sd_samplers_compvis.py
+++ b/modules/sd_samplers_compvis.py
@@ -70,8 +70,13 @@ class VanillaStableDiffusionSampler:
# Have to unwrap the inpainting conditioning here to perform pre-processing
image_conditioning = None
+ uc_image_conditioning = None
if isinstance(cond, dict):
- image_conditioning = cond["c_concat"][0]
+ if self.conditioning_key == "crossattn-adm":
+ image_conditioning = cond["c_adm"]
+ uc_image_conditioning = unconditional_conditioning["c_adm"]
+ else:
+ image_conditioning = cond["c_concat"][0]
cond = cond["c_crossattn"][0]
unconditional_conditioning = unconditional_conditioning["c_crossattn"][0]
@@ -98,8 +103,12 @@ class VanillaStableDiffusionSampler:
# Wrap the image conditioning back up since the DDIM code can accept the dict directly.
# Note that they need to be lists because it just concatenates them later.
if image_conditioning is not None:
- cond = {"c_concat": [image_conditioning], "c_crossattn": [cond]}
- unconditional_conditioning = {"c_concat": [image_conditioning], "c_crossattn": [unconditional_conditioning]}
+ if self.conditioning_key == "crossattn-adm":
+ cond = {"c_adm": image_conditioning, "c_crossattn": [cond]}
+ unconditional_conditioning = {"c_adm": uc_image_conditioning, "c_crossattn": [unconditional_conditioning]}
+ else:
+ cond = {"c_concat": [image_conditioning], "c_crossattn": [cond]}
+ unconditional_conditioning = {"c_concat": [image_conditioning], "c_crossattn": [unconditional_conditioning]}
return x, ts, cond, unconditional_conditioning
@@ -176,8 +185,12 @@ class VanillaStableDiffusionSampler:
# Wrap the conditioning models with additional image conditioning for inpainting model
if image_conditioning is not None:
- conditioning = {"c_concat": [image_conditioning], "c_crossattn": [conditioning]}
- unconditional_conditioning = {"c_concat": [image_conditioning], "c_crossattn": [unconditional_conditioning]}
+ if self.conditioning_key == "crossattn-adm":
+ conditioning = {"c_adm": image_conditioning, "c_crossattn": [conditioning]}
+ unconditional_conditioning = {"c_adm": torch.zeros_like(image_conditioning), "c_crossattn": [unconditional_conditioning]}
+ else:
+ conditioning = {"c_concat": [image_conditioning], "c_crossattn": [conditioning]}
+ unconditional_conditioning = {"c_concat": [image_conditioning], "c_crossattn": [unconditional_conditioning]}
samples = self.launch_sampling(t_enc + 1, lambda: self.sampler.decode(x1, conditioning, t_enc, unconditional_guidance_scale=p.cfg_scale, unconditional_conditioning=unconditional_conditioning))
@@ -195,8 +208,12 @@ class VanillaStableDiffusionSampler:
# Wrap the conditioning models with additional image conditioning for inpainting model
# dummy_for_plms is needed because PLMS code checks the first item in the dict to have the right shape
if image_conditioning is not None:
- conditioning = {"dummy_for_plms": np.zeros((conditioning.shape[0],)), "c_crossattn": [conditioning], "c_concat": [image_conditioning]}
- unconditional_conditioning = {"c_crossattn": [unconditional_conditioning], "c_concat": [image_conditioning]}
+ if self.conditioning_key == "crossattn-adm":
+ conditioning = {"dummy_for_plms": np.zeros((conditioning.shape[0],)), "c_crossattn": [conditioning], "c_adm": image_conditioning}
+ unconditional_conditioning = {"c_crossattn": [unconditional_conditioning], "c_adm": torch.zeros_like(image_conditioning)}
+ else:
+ conditioning = {"dummy_for_plms": np.zeros((conditioning.shape[0],)), "c_crossattn": [conditioning], "c_concat": [image_conditioning]}
+ unconditional_conditioning = {"c_crossattn": [unconditional_conditioning], "c_concat": [image_conditioning]}
samples_ddim = self.launch_sampling(steps, lambda: self.sampler.sample(S=steps, conditioning=conditioning, batch_size=int(x.shape[0]), shape=x[0].shape, verbose=False, unconditional_guidance_scale=p.cfg_scale, unconditional_conditioning=unconditional_conditioning, x_T=x, eta=self.eta)[0])
diff --git a/modules/sd_samplers_kdiffusion.py b/modules/sd_samplers_kdiffusion.py
index 93f0e55a..e9f08518 100644
--- a/modules/sd_samplers_kdiffusion.py
+++ b/modules/sd_samplers_kdiffusion.py
@@ -92,14 +92,21 @@ class CFGDenoiser(torch.nn.Module):
batch_size = len(conds_list)
repeats = [len(conds_list[i]) for i in range(batch_size)]
+ if shared.sd_model.model.conditioning_key == "crossattn-adm":
+ image_uncond = torch.zeros_like(image_cond)
+ make_condition_dict = lambda c_crossattn, c_adm: {"c_crossattn": c_crossattn, "c_adm": c_adm}
+ else:
+ image_uncond = image_cond
+ make_condition_dict = lambda c_crossattn, c_concat: {"c_crossattn": c_crossattn, "c_concat": [c_concat]}
+
if not is_edit_model:
x_in = torch.cat([torch.stack([x[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [x])
sigma_in = torch.cat([torch.stack([sigma[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [sigma])
- image_cond_in = torch.cat([torch.stack([image_cond[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [image_cond])
+ image_cond_in = torch.cat([torch.stack([image_cond[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [image_uncond])
else:
x_in = torch.cat([torch.stack([x[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [x] + [x])
sigma_in = torch.cat([torch.stack([sigma[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [sigma] + [sigma])
- image_cond_in = torch.cat([torch.stack([image_cond[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [image_cond] + [torch.zeros_like(self.init_latent)])
+ image_cond_in = torch.cat([torch.stack([image_cond[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [image_uncond] + [torch.zeros_like(self.init_latent)])
denoiser_params = CFGDenoiserParams(x_in, image_cond_in, sigma_in, state.sampling_step, state.sampling_steps, tensor, uncond)
cfg_denoiser_callback(denoiser_params)
@@ -116,13 +123,13 @@ class CFGDenoiser(torch.nn.Module):
cond_in = torch.cat([tensor, uncond, uncond])
if shared.batch_cond_uncond:
- x_out = self.inner_model(x_in, sigma_in, cond={"c_crossattn": [cond_in], "c_concat": [image_cond_in]})
+ x_out = self.inner_model(x_in, sigma_in, cond=make_condition_dict([cond_in], image_cond_in))
else:
x_out = torch.zeros_like(x_in)
for batch_offset in range(0, x_out.shape[0], batch_size):
a = batch_offset
b = a + batch_size
- x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond={"c_crossattn": [cond_in[a:b]], "c_concat": [image_cond_in[a:b]]})
+ x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond=make_condition_dict([cond_in[a:b]], image_cond_in[a:b]))
else:
x_out = torch.zeros_like(x_in)
batch_size = batch_size*2 if shared.batch_cond_uncond else batch_size
@@ -135,9 +142,9 @@ class CFGDenoiser(torch.nn.Module):
else:
c_crossattn = torch.cat([tensor[a:b]], uncond)
- x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond={"c_crossattn": c_crossattn, "c_concat": [image_cond_in[a:b]]})
+ x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond=make_condition_dict(c_crossattn, image_cond_in[a:b]))
- x_out[-uncond.shape[0]:] = self.inner_model(x_in[-uncond.shape[0]:], sigma_in[-uncond.shape[0]:], cond={"c_crossattn": [uncond], "c_concat": [image_cond_in[-uncond.shape[0]:]]})
+ x_out[-uncond.shape[0]:] = self.inner_model(x_in[-uncond.shape[0]:], sigma_in[-uncond.shape[0]:], cond=make_condition_dict([uncond], image_cond_in[-uncond.shape[0]:]))
denoised_params = CFGDenoisedParams(x_out, state.sampling_step, state.sampling_steps)
cfg_denoised_callback(denoised_params)
diff --git a/modules/shared.py b/modules/shared.py
index 677f35bd..048dba0e 100644
--- a/modules/shared.py
+++ b/modules/shared.py
@@ -13,113 +13,22 @@ import modules.interrogate
import modules.memmon
import modules.styles
import modules.devices as devices
-from modules import localization, extensions, script_loading, errors, ui_components, shared_items
-from modules.paths import models_path, script_path, data_path
+from modules import localization, script_loading, errors, ui_components, shared_items, cmd_args
+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
from modules.generation_parameters_copypaste import infotext_to_setting_name_mapping
demo = None
-sd_configs_path = os.path.join(script_path, "configs")
-sd_default_config = os.path.join(sd_configs_path, "v1-inference.yaml")
-sd_model_file = os.path.join(script_path, 'model.ckpt')
-default_sd_model_file = sd_model_file
+parser = cmd_args.parser
-parser = argparse.ArgumentParser()
-parser.add_argument("--data-dir", type=str, default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), help="base path where all user data is stored",)
-parser.add_argument("--config", type=str, default=sd_default_config, help="path to config which constructs model",)
-parser.add_argument("--ckpt", type=str, default=sd_model_file, help="path to checkpoint of stable diffusion model; if specified, this checkpoint will be added to the list of checkpoints and loaded",)
-parser.add_argument("--ckpt-dir", type=str, default=None, help="Path to directory with stable diffusion checkpoints")
-parser.add_argument("--vae-dir", type=str, default=None, help="Path to directory with VAE files")
-parser.add_argument("--gfpgan-dir", type=str, help="GFPGAN directory", default=('./src/gfpgan' if os.path.exists('./src/gfpgan') else './GFPGAN'))
-parser.add_argument("--gfpgan-model", type=str, help="GFPGAN model file name", default=None)
-parser.add_argument("--no-half", action='store_true', help="do not switch the model to 16-bit floats")
-parser.add_argument("--no-half-vae", action='store_true', help="do not switch the VAE model to 16-bit floats")
-parser.add_argument("--no-progressbar-hiding", action='store_true', help="do not hide progressbar in gradio UI (we hide it because it slows down ML if you have hardware acceleration in browser)")
-parser.add_argument("--max-batch-count", type=int, default=16, help="maximum batch count value for the UI")
-parser.add_argument("--embeddings-dir", type=str, default=os.path.join(data_path, 'embeddings'), help="embeddings directory for textual inversion (default: embeddings)")
-parser.add_argument("--textual-inversion-templates-dir", type=str, default=os.path.join(script_path, 'textual_inversion_templates'), help="directory with textual inversion templates")
-parser.add_argument("--hypernetwork-dir", type=str, default=os.path.join(models_path, 'hypernetworks'), help="hypernetwork directory")
-parser.add_argument("--localizations-dir", type=str, default=os.path.join(script_path, 'localizations'), help="localizations directory")
-parser.add_argument("--allow-code", action='store_true', help="allow custom script execution from webui")
-parser.add_argument("--medvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a little speed for low VRM usage")
-parser.add_argument("--lowvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a lot of speed for very low VRM usage")
-parser.add_argument("--lowram", action='store_true', help="load stable diffusion checkpoint weights to VRAM instead of RAM")
-parser.add_argument("--always-batch-cond-uncond", action='store_true', help="disables cond/uncond batching that is enabled to save memory with --medvram or --lowvram")
-parser.add_argument("--unload-gfpgan", action='store_true', help="does not do anything.")
-parser.add_argument("--precision", type=str, help="evaluate at this precision", choices=["full", "autocast"], default="autocast")
-parser.add_argument("--upcast-sampling", action='store_true', help="upcast sampling. No effect with --no-half. Usually produces similar results to --no-half with better performance while using less memory.")
-parser.add_argument("--share", action='store_true', help="use share=True for gradio and make the UI accessible through their site")
-parser.add_argument("--ngrok", type=str, help="ngrok authtoken, alternative to gradio --share", default=None)
-parser.add_argument("--ngrok-region", type=str, help="The region in which ngrok should start.", default="us")
-parser.add_argument("--enable-insecure-extension-access", action='store_true', help="enable extensions tab regardless of other options")
-parser.add_argument("--codeformer-models-path", type=str, help="Path to directory with codeformer model file(s).", default=os.path.join(models_path, 'Codeformer'))
-parser.add_argument("--gfpgan-models-path", type=str, help="Path to directory with GFPGAN model file(s).", default=os.path.join(models_path, 'GFPGAN'))
-parser.add_argument("--esrgan-models-path", type=str, help="Path to directory with ESRGAN model file(s).", default=os.path.join(models_path, 'ESRGAN'))
-parser.add_argument("--bsrgan-models-path", type=str, help="Path to directory with BSRGAN model file(s).", default=os.path.join(models_path, 'BSRGAN'))
-parser.add_argument("--realesrgan-models-path", type=str, help="Path to directory with RealESRGAN model file(s).", default=os.path.join(models_path, 'RealESRGAN'))
-parser.add_argument("--clip-models-path", type=str, help="Path to directory with CLIP model file(s).", default=None)
-parser.add_argument("--xformers", action='store_true', help="enable xformers for cross attention layers")
-parser.add_argument("--force-enable-xformers", action='store_true', help="enable xformers for cross attention layers regardless of whether the checking code thinks you can run it; do not make bug reports if this fails to work")
-parser.add_argument("--xformers-flash-attention", action='store_true', help="enable xformers with Flash Attention to improve reproducibility (supported for SD2.x or variant only)")
-parser.add_argument("--deepdanbooru", action='store_true', help="does not do anything")
-parser.add_argument("--opt-split-attention", action='store_true', help="force-enables Doggettx's cross-attention layer optimization. By default, it's on for torch cuda.")
-parser.add_argument("--opt-sub-quad-attention", action='store_true', help="enable memory efficient sub-quadratic cross-attention layer optimization")
-parser.add_argument("--sub-quad-q-chunk-size", type=int, help="query chunk size for the sub-quadratic cross-attention layer optimization to use", default=1024)
-parser.add_argument("--sub-quad-kv-chunk-size", type=int, help="kv chunk size for the sub-quadratic cross-attention layer optimization to use", default=None)
-parser.add_argument("--sub-quad-chunk-threshold", type=int, help="the percentage of VRAM threshold for the sub-quadratic cross-attention layer optimization to use chunking", default=None)
-parser.add_argument("--opt-split-attention-invokeai", action='store_true', help="force-enables InvokeAI's cross-attention layer optimization. By default, it's on when cuda is unavailable.")
-parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find")
-parser.add_argument("--opt-sdp-attention", action='store_true', help="enable scaled dot product cross-attention layer optimization; requires PyTorch 2.*")
-parser.add_argument("--opt-sdp-no-mem-attention", action='store_true', help="enable scaled dot product cross-attention layer optimization without memory efficient attention, makes image generation deterministic; requires PyTorch 2.*")
-parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization")
-parser.add_argument("--disable-nan-check", action='store_true', help="do not check if produced images/latent spaces have nans; useful for running without a checkpoint in CI")
-parser.add_argument("--use-cpu", nargs='+', help="use CPU as torch device for specified modules", default=[], type=str.lower)
-parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests")
-parser.add_argument("--port", type=int, help="launch gradio with given server port, you need root/admin rights for ports < 1024, defaults to 7860 if available", default=None)
-parser.add_argument("--show-negative-prompt", action='store_true', help="does not do anything", default=False)
-parser.add_argument("--ui-config-file", type=str, help="filename to use for ui configuration", default=os.path.join(data_path, 'ui-config.json'))
-parser.add_argument("--hide-ui-dir-config", action='store_true', help="hide directory configuration from webui", default=False)
-parser.add_argument("--freeze-settings", action='store_true', help="disable editing settings", default=False)
-parser.add_argument("--ui-settings-file", type=str, help="filename to use for ui settings", default=os.path.join(data_path, 'config.json'))
-parser.add_argument("--gradio-debug", action='store_true', help="launch gradio with --debug option")
-parser.add_argument("--gradio-auth", type=str, help='set gradio authentication like "username:password"; or comma-delimit multiple like "u1:p1,u2:p2,u3:p3"', default=None)
-parser.add_argument("--gradio-auth-path", type=str, help='set gradio authentication file path ex. "/path/to/auth/file" same auth format as --gradio-auth', default=None)
-parser.add_argument("--gradio-img2img-tool", type=str, help='does not do anything')
-parser.add_argument("--gradio-inpaint-tool", type=str, help="does not do anything")
-parser.add_argument("--opt-channelslast", action='store_true', help="change memory type for stable diffusion to channels last")
-parser.add_argument("--styles-file", type=str, help="filename to use for styles", default=os.path.join(data_path, 'styles.csv'))
-parser.add_argument("--autolaunch", action='store_true', help="open the webui URL in the system's default browser upon launch", default=False)
-parser.add_argument("--theme", type=str, help="launches the UI with light or dark theme", default=None)
-parser.add_argument("--use-textbox-seed", action='store_true', help="use textbox for seeds in UI (no up/down, but possible to input long seeds)", default=False)
-parser.add_argument("--disable-console-progressbars", action='store_true', help="do not output progressbars to console", default=False)
-parser.add_argument("--enable-console-prompts", action='store_true', help="print prompts to console when generating with txt2img and img2img", default=False)
-parser.add_argument('--vae-path', type=str, help='Checkpoint to use as VAE; setting this argument disables all settings related to VAE', default=None)
-parser.add_argument("--disable-safe-unpickle", action='store_true', help="disable checking pytorch models for malicious code", default=False)
-parser.add_argument("--api", action='store_true', help="use api=True to launch the API together with the webui (use --nowebui instead for only the API)")
-parser.add_argument("--api-auth", type=str, help='Set authentication for API like "username:password"; or comma-delimit multiple like "u1:p1,u2:p2,u3:p3"', default=None)
-parser.add_argument("--api-log", action='store_true', help="use api-log=True to enable logging of all API requests")
-parser.add_argument("--nowebui", action='store_true', help="use api=True to launch the API instead of the webui")
-parser.add_argument("--ui-debug-mode", action='store_true', help="Don't load model to quickly launch UI")
-parser.add_argument("--device-id", type=str, help="Select the default CUDA device to use (export CUDA_VISIBLE_DEVICES=0,1,etc might be needed before)", default=None)
-parser.add_argument("--administrator", action='store_true', help="Administrator rights", default=False)
-parser.add_argument("--cors-allow-origins", type=str, help="Allowed CORS origin(s) in the form of a comma-separated list (no spaces)", default=None)
-parser.add_argument("--cors-allow-origins-regex", type=str, help="Allowed CORS origin(s) in the form of a single regular expression", default=None)
-parser.add_argument("--tls-keyfile", type=str, help="Partially enables TLS, requires --tls-certfile to fully function", default=None)
-parser.add_argument("--tls-certfile", type=str, help="Partially enables TLS, requires --tls-keyfile to fully function", default=None)
-parser.add_argument("--server-name", type=str, help="Sets hostname of server", default=None)
-parser.add_argument("--gradio-queue", action='store_true', help="Uses gradio queue; experimental option; breaks restart UI button")
-parser.add_argument("--skip-version-check", action='store_true', help="Do not check versions of torch and xformers")
-parser.add_argument("--no-hashing", action='store_true', help="disable sha256 hashing of checkpoints to help loading performance", default=False)
-parser.add_argument("--no-download-sd-model", action='store_true', help="don't download SD1.5 model even if no model is found in --ckpt-dir", default=False)
-
-
-script_loading.preload_extensions(extensions.extensions_dir, parser)
-script_loading.preload_extensions(extensions.extensions_builtin_dir, parser)
+script_loading.preload_extensions(extensions_dir, parser)
+script_loading.preload_extensions(extensions_builtin_dir, parser)
if os.environ.get('IGNORE_CMD_ARGS_ERRORS', None) is None:
cmd_opts = parser.parse_args()
else:
cmd_opts, _ = parser.parse_known_args()
+
restricted_opts = {
"samples_filename_pattern",
"directories_filename_pattern",
@@ -332,6 +241,8 @@ options_templates.update(options_section(('saving-images', "Saving images/grids"
"save_images_before_face_restoration": OptionInfo(False, "Save a copy of image before doing face restoration."),
"save_images_before_highres_fix": OptionInfo(False, "Save a copy of image before applying highres fix."),
"save_images_before_color_correction": OptionInfo(False, "Save a copy of image before applying color correction to img2img results"),
+ "save_mask": OptionInfo(False, "For inpainting, save a copy of the greyscale mask"),
+ "save_mask_composite": OptionInfo(False, "For inpainting, save a masked composite"),
"jpeg_quality": OptionInfo(80, "Quality for saved jpeg images", gr.Slider, {"minimum": 1, "maximum": 100, "step": 1}),
"webp_lossless": OptionInfo(False, "Use lossless compression for webp images"),
"export_for_4chan": OptionInfo(True, "If the saved image file size is above the limit, or its either width or height are above the limit, save a downscaled copy as JPG"),
@@ -423,7 +334,6 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), {
"upcast_attn": OptionInfo(False, "Upcast cross attention layer to float32"),
"sd_max_resolution": OptionInfo(2048, "Max resolution output for txt2img and img2img"),
"ignore_overrides": OptionInfo([], "Ignore Overrides", gr.CheckboxGroup, lambda: {"choices": [x[0] for x in infotext_to_setting_name_mapping]}),
-
}))
options_templates.update(options_section(('compatibility', "Compatibility"), {
@@ -449,18 +359,22 @@ options_templates.update(options_section(('interrogate', "Interrogate Options"),
}))
options_templates.update(options_section(('extra_networks', "Extra Networks"), {
+ #"extra_networks_default_view": OptionInfo("cards", "Default view for Extra Networks", gr.Dropdown, {"choices": ["cards", "thumbs"]}),
"extra_networks_default_multiplier": OptionInfo(1.0, "Multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
+ #"extra_networks_card_width": OptionInfo(0, "Card width for Extra Networks (px)"),
+ #"extra_networks_card_height": OptionInfo(0, "Card height for Extra Networks (px)"),
"extra_networks_add_text_separator": OptionInfo(" ", "Extra text to add before <...> when adding extra network to prompt"),
"sd_hypernetwork": OptionInfo("None", "Add hypernetwork to prompt", gr.Dropdown, lambda: {"choices": [""] + [x for x in hypernetworks.keys()]}, refresh=reload_hypernetworks),
"extra_networks_default_visibility": OptionInfo(True, "Extra Networks default visibility"),
"extra_networks_cards_size": OptionInfo(1, "Card size for extra networks", gr.Slider, {"minimum": 0.8, "maximum": 2, "step": 0.1}),
"extra_networks_cards_visible_rows": OptionInfo(1, "Visible card rows for extra networks", gr.Slider, {"minimum": 1, "maximum": 3, "step": 1}),
- "extra_networks_aside": OptionInfo(True, "Extra Networks aside view"),
-
+ "extra_networks_aside": OptionInfo(True, "Extra Networks aside view"),
}))
options_templates.update(options_section(('ui', "User interface"), {
"return_grid": OptionInfo(True, "Show grid in results for web"),
+ "return_mask": OptionInfo(False, "For inpainting, include the greyscale mask in results for web"),
+ "return_mask_composite": OptionInfo(False, "For inpainting, include masked composite in results for web"),
"do_not_show_images": OptionInfo(False, "Do not show any images in results for web"),
"add_model_hash_to_info": OptionInfo(True, "Add model hash to generation information"),
"add_model_name_to_info": OptionInfo(True, "Add model name to generation information"),
@@ -482,10 +396,12 @@ options_templates.update(options_section(('ui', "User interface"), {
"ui_header_tabs": OptionInfo("", "Header Tabs"),
"ui_views_order": OptionInfo("row-reverse", "Interface order input/parameters | output/preview", gr.Radio, {"choices": ["row", "row-reverse"]}),
"ui_extra_networks_tab_reorder": OptionInfo("", "Extra networks tab order"),
- #"ui_performant_gradio_input_components": OptionInfo("", "Performant gradio components is enabled for all main tabs and scripts. Use css selectors only for extensions that have their own tab"),
+ "ui_hidden_tabs": OptionInfo("", "Hidden Tabs"),
+ "ui_header_tabs": OptionInfo("", "Header Tabs"),
+ "ui_views_order": OptionInfo("row-reverse", "Interface order input/parameters | output/preview", gr.Radio, {"choices": ["row", "row-reverse"]}),
"ui_output_image_fit": OptionInfo("Scale-down", "Generated image fit method", gr.Radio, {"choices": ["Scale-down", "Contain"]}),
"ui_show_range_ticks": OptionInfo(True, "Show ticks for range sliders"),
- "ui_dispatch_input_release": OptionInfo(True, "Dispatch event change on release, for slider and input number components"),
+ "ui_dispatch_input_release": OptionInfo(True, "Dispatch event change on release, for slider and input number components"),
"localization": OptionInfo("None", "Localization (requires restart)", gr.Dropdown, lambda: {"choices": ["None"] + list(localization.localizations.keys())}, refresh=lambda: localization.list_localizations(cmd_opts.localizations_dir)),
}))
@@ -497,7 +413,7 @@ options_templates.update(options_section(('ui', "Live previews"), {
"show_progress_type": OptionInfo("Approx NN", "Image creation progress preview mode", gr.Radio, {"choices": ["Full", "Approx NN", "Approx cheap"]}),
"live_preview_content": OptionInfo("Prompt", "Live preview subject", gr.Radio, {"choices": ["Combined", "Prompt", "Negative prompt"]}),
"live_preview_refresh_period": OptionInfo(1000, "Progressbar/preview update period, in milliseconds"),
- "live_preview_image_fit": OptionInfo("Scale-down", "Live preview image fit method", gr.Radio, {"choices": ["Scale-down", "Contain"]}),
+ "live_preview_image_fit": OptionInfo("Scale-down", "Live preview image fit method", gr.Radio, {"choices": ["Scale-down", "Contain"]}),
}))
options_templates.update(options_section(('sampler-params', "Sampler parameters"), {
@@ -523,7 +439,8 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), {
}))
options_templates.update(options_section((None, "Hidden options"), {
- "disabled_extensions": OptionInfo([], "Disable those extensions"),
+ "disabled_extensions": OptionInfo([], "Disable these extensions"),
+ "disable_all_extensions": OptionInfo("none", "Disable all extensions (preserves the list of disabled extensions)", gr.Radio, {"choices": ["none", "extra", "all"]}),
"sd_checkpoint_hash": OptionInfo("", "SHA256 hash of the current checkpoint"),
}))
@@ -741,7 +658,7 @@ mem_mon.start()
def listfiles(dirname):
- filenames = [os.path.join(dirname, x) for x in sorted(os.listdir(dirname)) if not x.startswith(".")]
+ filenames = [os.path.join(dirname, x) for x in sorted(os.listdir(dirname), key=str.lower) if not x.startswith(".")]
return [file for file in filenames if os.path.isfile(file)]
diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py
index c63c7d1d..d2e62e58 100644
--- a/modules/textual_inversion/textual_inversion.py
+++ b/modules/textual_inversion/textual_inversion.py
@@ -152,7 +152,11 @@ class EmbeddingDatabase:
name = data.get('name', name)
else:
data = extract_image_data_embed(embed_image)
- name = data.get('name', name)
+ if data:
+ name = data.get('name', name)
+ else:
+ # if data is None, means this is not an embeding, just a preview image
+ return
elif ext in ['.BIN', '.PT']:
data = torch.load(path, map_location="cpu")
elif ext in ['.SAFETENSORS']:
diff --git a/modules/ui.py b/modules/ui.py
index beb8f341..698fe51b 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -20,7 +20,7 @@ from PIL import Image, PngImagePlugin
from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call
from modules import sd_hijack, sd_models, localization, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, postprocessing, ui_components, ui_common, ui_postprocessing
-from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML
+from modules.ui_components import FormRow, FormColumn, FormGroup, ToolButton, FormHTML
from modules.paths import script_path, data_path
from modules.shared import opts, cmd_opts, restricted_opts
@@ -70,17 +70,6 @@ def gr_show(visible=True):
sample_img2img = "assets/stable-samples/img2img/sketch-mountains-input.jpg"
sample_img2img = sample_img2img if os.path.exists(sample_img2img) else None
-css_hide_progressbar = """
-.wrap .m-12 svg { display:none!important; }
-.wrap .m-12::before { content:"Loading..." }
-.wrap .z-20 svg { display:none!important; }
-.wrap .z-20::before { content:"Loading..." }
-.wrap.cover-bg .z-20::before { content:"" }
-.progress-bar { display:none!important; }
-.meta-text { display:none!important; }
-.meta-text-center { display:none!important; }
-"""
-
# Using constants for these since the variation selector isn't visible.
# Important that they exactly match script.js for tooltip to work.
random_symbol = '\U0001f3b2\ufe0f' # 🎲️
@@ -89,15 +78,13 @@ paste_symbol = '\u2199\ufe0f' # ↙
refresh_symbol = '\U0001f504' # 🔄
save_style_symbol = '\U0001f4be' # 💾
apply_style_symbol = '\U0001f4cb' # 📋
-clear_prompt_symbol = '\U0001F5D1' # 🗑️
+clear_prompt_symbol = '\U0001f5d1\ufe0f' # 🗑️
extra_networks_symbol = '\U0001F3B4' # 🎴
#switch_values_symbol = '\U000021C5' # ⇅
-switch_values_symbol = '\u2B80' # ⮀
-
+switch_values_symbol = '\u2B80' # ⮀
interogate_bubble_symbol = '\U0001F5E8' # 🗨
interogate_2bubble_symbol = '\U0001F5EA' # 🗪
-
def plaintext_to_html(text):
return ui_common.plaintext_to_html(text)
@@ -186,13 +173,7 @@ def create_seed_inputs(target_interface):
with gr.Row(elem_id = target_interface+"_group_seed"):
with gr.Box():
- # use -collapse or -collapse-all
- # always the end to remove padding and margin of all the nested containers a bit of a hack but
- # this is a workaround since gradio hasn't yet class style support for most of the components
- # variants are not a choice either for rows columns
- # this also can help script developers to have more complex layouts
- with gr.Row(elem_id=target_interface + '_seed_row-collapse-all'):
-
+ with gr.Row(elem_id=target_interface + '_seed_row-collapse-all'):
seed = (gr.Textbox if cmd_opts.use_textbox_seed else gr.Number)(label='Seed', value=-1, elem_id=target_interface + '_seed')
# #seed.style(container=False)
random_seed = ToolButton(value=random_symbol, elem_id=target_interface + '_random_seed')
@@ -205,27 +186,25 @@ def create_seed_inputs(target_interface):
# Components to show/hide based on the 'Extra' checkbox
seed_extras = []
- #with FormRow(visible=False, elem_id=target_interface + '_subseed_row') as seed_extra_row_1:
- #with gr.Group(elem_id="group-subseed", visible=False) as seed_extra_group:
-
+
# use sub-group
# at any place to indicate a different style already defined by the css rules
- with FormGroup(elem_id=target_interface + '_subseed_row_sub-group', visible=False) as seed_extra_group:
+ with gr.Column(elem_id=target_interface + '_subseed_row_sub-group', visible=False) as seed_extra_group:
seed_extras.append(seed_extra_group)
with gr.Row(visible=False) as seed_extra_row_1:
seed_extras.append(seed_extra_row_1)
- with gr.Box():
+ with gr.Box():
with gr.Row(elem_id= target_interface + '_subseed_row-collapse-all'):
subseed = gr.Number(label='Variation seed', value=-1, elem_id=target_interface + '_subseed')
#subseed.style(container=False)
random_subseed = ToolButton(value=random_symbol, elem_id=target_interface + '_random_subseed')
- reuse_subseed = ToolButton(value=reuse_symbol, elem_id=target_interface + '_reuse_subseed')
-
- subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01, elem_id=target_interface + '_subseed_strength')
+ reuse_subseed = ToolButton(value=reuse_symbol, elem_id=target_interface + '_reuse_subseed')
+ with gr.Box(elem_id= target_interface + '_subseed_strength_row-collapse-all'):
+ #with gr.Row(elem_id= target_interface + '_subseed_strength_row'):
+ subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01, elem_id=target_interface + '_subseed_strength')
- #with FormRow(visible=False) as seed_extra_row_2:
with gr.Row(visible=False) as seed_extra_row_2:
seed_extras.append(seed_extra_row_2)
seed_resize_from_w = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize seed from width", value=0, elem_id=target_interface + '_seed_resize_from_w')
@@ -290,7 +269,6 @@ def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info:
def update_token_counter(text, steps):
try:
text, _ = extra_networks.parse_prompt(text)
-
_, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps)
@@ -304,6 +282,28 @@ def update_token_counter(text, steps):
token_count, max_length = max([model_hijack.get_prompt_lengths(prompt) for prompt in prompts], key=lambda args: args[0])
return f"{token_count}/{max_length} "
+def create_generate(is_img2img):
+ id_part = "img2img" if is_img2img else "txt2img"
+
+ with gr.Column(scale=1):
+ with gr.Row(elem_id=f"{id_part}_generate_box", elem_classes="generate-box"):
+ interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt", elem_classes="generate-box-interrupt")
+ skip = gr.Button('Skip', elem_id=f"{id_part}_skip", elem_classes="generate-box-skip")
+ submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary')
+
+ skip.click(
+ fn=lambda: shared.state.skip(),
+ inputs=[],
+ outputs=[],
+ )
+
+ interrupt.click(
+ fn=lambda: shared.state.interrupt(),
+ inputs=[],
+ outputs=[],
+ )
+
+ return submit
def create_generate(is_img2img):
id_part = "img2img" if is_img2img else "txt2img"
@@ -332,7 +332,6 @@ def create_toprow(is_img2img):
id_part = "img2img" if is_img2img else "txt2img"
with gr.Row(elem_id=f"{id_part}_toprow-collapse", variant="compact"):
-
with gr.Column(scale=6):
with gr.Row():
with gr.Column(scale=80):
@@ -341,18 +340,18 @@ def create_toprow(is_img2img):
create_refresh_button(prompt_styles, shared.prompt_styles.reload, lambda: {"choices": [k for k, v in shared.prompt_styles.styles.items()]}, f"refresh_{id_part}_style_index")
with gr.Row():
+ token_counter = gr.HTML(value=" ", elem_id=f"{id_part}_token_counter")
prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=True, lines=3,
placeholder="Prompt (press Ctrl+Enter or Alt+Enter to generate)"
)
with gr.Row():
+ negative_token_counter = gr.HTML(value=" ", elem_id=f"{id_part}_negative_token_counter")
negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=True, lines=3,
placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)"
)
- with gr.Column(elem_id=f"{id_part}_actions_column"):
-
-
+ with gr.Column(elem_id=f"{id_part}_actions_column"):
with gr.Row(elem_id=f"{id_part}_tools"):
paste = ToolButton(value=paste_symbol, elem_id="paste")
clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt")
@@ -366,9 +365,8 @@ def create_toprow(is_img2img):
button_interrogate = ToolButton(value=interogate_bubble_symbol, elem_id="interrogate")
button_deepbooru = ToolButton(value=interogate_2bubble_symbol, elem_id="deepbooru")
- token_counter = gr.HTML(value=" ", elem_id=f"{id_part}_token_counter")
- token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button")
- negative_token_counter = gr.HTML(value=" ", elem_id=f"{id_part}_negative_token_counter")
+
+ token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button")
negative_token_button = gr.Button(visible=False, elem_id=f"{id_part}_negative_token_button")
clear_prompt_button.click(
@@ -496,13 +494,10 @@ def create_ui():
with gr.Blocks(analytics_enabled=False) as txt2img_interface:
- #submit = create_generate(is_img2img=False)
-
+ #submit = create_generate(is_img2img=False)
dummy_component = gr.Label(visible=False)
txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="binary", visible=False)
-
-
with gr.Row().style(equal_height=False):
txt2img_gallery, generation_info, html_info, html_log = create_output_panel("txt2img", opts.outdir_txt2img_samples)
gr.Row(elem_id="txt2img_splitter")
@@ -514,13 +509,13 @@ def create_ui():
with gr.Column(elem_id="txt2img_settings_scroll"):
with gr.Accordion("Prompt", open=True):
txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=False)
-
-
+
with gr.Row(elem_id="txt2img_extra_networks_row", visible=True) as extra_networks:
from modules import ui_extra_networks
extra_networks_ui = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'txt2img')
#with gr.Accordion("Parameters", open=True):
+
for category in ordered_ui_categories():
if category == "sampler":
@@ -528,12 +523,13 @@ def create_ui():
elif category == "dimensions":
with gr.Row():
+
width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="txt2img_width")
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn")
height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="txt2img_height")
if opts.dimensions_and_batch_together:
-
+
with gr.Row(elem_id="txt2img_column_batch"):
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count")
batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size")
@@ -550,12 +546,10 @@ def create_ui():
restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1, elem_id="txt2img_restore_faces")
tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling")
enable_hr = gr.Checkbox(label='Hires. fix', value=False, elem_id="txt2img_enable_hr")
-
+
elif category == "hires_fix":
- with FormGroup(visible=False, elem_id="txt2img_hires_fix_sub-group") as hr_options:
- #with FormRow(elem_id="txt2img_hires_fix_row1", variant="compact"):
- with gr.Row(elem_id="txt2img_hires_fix_row1"):
-
+ with gr.Column(visible=False, elem_id="txt2img_hires_fix_sub-group") as hr_options:
+ with gr.Row(elem_id="txt2img_hires_fix_row1"):
hr_upscaler = gr.Dropdown(label="Upscaler", elem_id="txt2img_hr_upscaler", choices=[*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]], value=shared.latent_upscale_default_mode)
hr_final_resolution = FormHTML(value="", elem_id="txtimg_hr_finalres", label="Upscaled resolution", interactive=False)
@@ -577,13 +571,13 @@ def create_ui():
batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size")
elif category == "override_settings":
- with FormRow(elem_id="txt2img_override_settings_row") as row:
+ with gr.Row(elem_id="txt2img_override_settings_row") as row:
override_settings = create_override_settings_dropdown('txt2img', row)
elif category == "scripts":
- #with FormGroup(elem_id="txt2img_script_container"):
- with gr.Group():
- custom_inputs = modules.scripts.scripts_txt2img.setup_ui()
+ #with FormRow(elem_id="txt2img_script_container"):
+ #with gr.Group():
+ custom_inputs = modules.scripts.scripts_txt2img.setup_ui()
hr_resolution_preview_inputs = [enable_hr, width, height, hr_scale, hr_resize_x, hr_resize_y]
for input in hr_resolution_preview_inputs:
@@ -601,8 +595,6 @@ def create_ui():
show_progress=False,
)
-
-
connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
@@ -647,7 +639,7 @@ def create_ui():
#txt2img_prompt.submit(**txt2img_args)
submit.click(**txt2img_args)
- res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height])
+ res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False)
txt_prompt_img.change(
fn=modules.images.image_data,
@@ -717,12 +709,10 @@ def create_ui():
modules.scripts.scripts_img2img.initialize_scripts(is_img2img=True)
with gr.Blocks(analytics_enabled=False) as img2img_interface:
-
+
img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="binary", visible=False)
-
-
- with FormRow().style(equal_height=False):
+ with gr.Row().style(equal_height=False):
img2img_gallery, generation_info, html_info, html_log = create_output_panel("img2img", opts.outdir_img2img_samples)
gr.Row(elem_id="img2img_splitter")
@@ -741,7 +731,6 @@ def create_ui():
from modules import ui_extra_networks
extra_networks_ui_img2img = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'img2img')
-
copy_image_buttons = []
copy_image_destinations = {}
@@ -802,7 +791,6 @@ def create_ui():
img2img_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs, elem_id="img2img_batch_output_dir")
img2img_batch_inpaint_mask_dir = gr.Textbox(label="Inpaint batch mask directory (required for inpaint batch processing only)", **shared.hide_dirs, elem_id="img2img_batch_inpaint_mask_dir")
-
for category in ordered_ui_categories():
if category == "inpaint":
@@ -816,8 +804,6 @@ def create_ui():
res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn")
height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="img2img_height")
-
-
with FormGroup(elem_id="inpaint_controls_sub-group-collapse", visible=False) as inpaint_controls:
with gr.Row():
@@ -845,7 +831,6 @@ def create_ui():
def copy_image(img):
if isinstance(img, dict) and 'image' in img:
return img['image']
-
return img
for button, name, elem in copy_image_buttons:
@@ -868,25 +853,20 @@ def create_ui():
for category in ordered_ui_categories():
if category == "sampler":
steps, sampler_index = create_sampler_and_steps_selection(samplers_for_img2img, "img2img")
-
- elif category == "dimensions":
+
+ elif category == "dimensions":
#with gr.Row():
-
#with gr.Column(elem_id="img2img_column_size", scale=4):
# width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="img2img_width")
# res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn")
# height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="img2img_height")
-
- if opts.dimensions_and_batch_together:
-
+ if opts.dimensions_and_batch_together:
with gr.Row(elem_id="img2img_column_batch"):
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count")
batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="img2img_batch_size")
-
- elif category == "cfg":
-
- with gr.Row():
+ elif category == "cfg":
+ with gr.Row():
cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0, elem_id="img2img_cfg_scale")
image_cfg_scale = gr.Slider(minimum=0, maximum=3.0, step=0.05, label='Image CFG Scale', value=1.5, elem_id="img2img_image_cfg_scale", visible=shared.sd_model and shared.sd_model.cond_stage_key == "edit")
denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.75, elem_id="img2img_denoising_strength")
@@ -902,19 +882,18 @@ def create_ui():
elif category == "batch":
if not opts.dimensions_and_batch_together:
- with FormRow(elem_id="img2img_column_batch"):
+ with gr.Row(elem_id="img2img_column_batch"):
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count")
batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="img2img_batch_size")
elif category == "override_settings":
- with FormRow(elem_id="img2img_override_settings_row") as row:
+ with gr.Row(elem_id="img2img_override_settings_row") as row:
override_settings = create_override_settings_dropdown('img2img', row)
elif category == "scripts":
- with FormGroup(elem_id="img2img_script_container"):
- custom_inputs = modules.scripts.scripts_img2img.setup_ui()
+ #with FormGroup(elem_id="img2img_script_container"):
+ custom_inputs = modules.scripts.scripts_img2img.setup_ui()
-
connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
@@ -996,7 +975,7 @@ def create_ui():
#img2img_prompt.submit(**img2img_args)
submit.click(**img2img_args)
- res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height])
+ res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False)
img2img_interrogate.click(
fn=lambda *args: process_interrogate(interrogate, *args),
@@ -1072,7 +1051,7 @@ def create_ui():
with gr.Column(elem_id="png_2img_results"):
with gr.Row():
buttons = parameters_copypaste.create_buttons(["txt2img", "img2img", "inpaint", "extras"])
-
+
html = gr.HTML()
generation_info = gr.Textbox(visible=False, elem_id="pnginfo_generation_info")
html2 = gr.HTML()
@@ -1081,7 +1060,7 @@ def create_ui():
with gr.Column(variant='panel', elem_id="png_2img_settings"):
with gr.Column(elem_id="png_2img_settings_scroll"):
image = gr.Image(elem_id="pnginfo_image", label="Source", source="upload", interactive=True, type="pil")
-
+
for tabname, button in buttons.items():
parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding(
paste_button=button, tabname=tabname, source_text_component=generation_info, source_image_component=image,
@@ -1141,6 +1120,7 @@ def create_ui():
with FormRow():
with gr.Column():
config_source = gr.Radio(choices=["A, B or C", "B", "C", "Don't"], value="A, B or C", label="Copy config from", type="index", elem_id="modelmerger_config_method")
+
with gr.Column():
with gr.Box():
with gr.Row(elem_id="modelmerger_bake_in_vae_row-collapse-all"):
@@ -1273,6 +1253,7 @@ def create_ui():
# train_embedding = gr.Button(value="Train Embedding", variant='primary', elem_id="train_train_embedding")
# interrupt_training = gr.Button(value="Interrupt", elem_id="train_interrupt_training")
# train_hypernetwork = gr.Button(value="Train Hypernetwork", variant='primary', elem_id="train_train_hypernetwork")
+
with gr.Column(elem_id="train_2img_settings_scroll"):
gr.HTML(value="Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images [wiki]
")
with FormRow():
@@ -1337,11 +1318,11 @@ def create_ui():
script_callbacks.ui_train_tabs_callback(params)
- # with gr.Column(elem_id='ti_gallery_container'):
- # ti_output = gr.Text(elem_id="ti_output", value="", show_label=False)
- # ti_gallery = gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(grid=4)
- # ti_progress = gr.HTML(elem_id="ti_progress", value="")
- # ti_outcome = gr.HTML(elem_id="ti_error", value="")
+ # with gr.Column(elem_id='ti_gallery_container'):
+ # ti_output = gr.Text(elem_id="ti_output", value="", show_label=False)
+ # ti_gallery = gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(grid=4)
+ # ti_progress = gr.HTML(elem_id="ti_progress", value="")
+ # ti_outcome = gr.HTML(elem_id="ti_error", value="")
create_embedding.click(
fn=modules.textual_inversion.ui.create_embedding,
@@ -1516,27 +1497,27 @@ def create_ui():
if info.refresh is not None:
if is_quicksettings:
- with FormRow(elem_id=f'row_{elem_id}'):
+ with gr.Row(elem_id=f'row_{elem_id}'):
with gr.Box():
with gr.Row(elem_id=f'{elem_id}_row-collapse-one'):
res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
create_refresh_button(res, info.refresh, info.component_args, "refresh_" + key)
- with FormRow():
+
+ with gr.Row():
gr.Checkbox(label='', elem_id=f'{section}_add2quick_{elem_id}', value=True, interactive=True)
else:
- with FormRow(elem_id=f'row_{elem_id}'):
+ with gr.Row(elem_id=f'row_{elem_id}'):
with gr.Box():
with gr.Row(elem_id=f'{elem_id}_row-collapse-one'):
res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
create_refresh_button(res, info.refresh, info.component_args, "refresh_" + key)
- with FormRow():
+ with gr.Row():
gr.Checkbox(label='', elem_id=f'{section}_add2quick_{elem_id}', value=False, interactive=True)
else:
- with FormRow(elem_id=f'row_{elem_id}'):
+ with gr.Row(elem_id=f'row_{elem_id}'):
res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
gr.Checkbox(label='', elem_id=f'{section}_add2quick_{elem_id}', value=is_quicksettings, interactive=True)
-
return res
components = []
@@ -1593,8 +1574,7 @@ def create_ui():
previous_section = None
current_tab = None
current_row = None
- with gr.Tabs(elem_id="settings"):
-
+ with gr.Tabs(elem_id="settings"):
for i, (k, item) in enumerate(opts.data_labels.items()):
section_must_be_skipped = item.section[0] is None
@@ -1631,11 +1611,33 @@ def create_ui():
request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications")
download_localization = gr.Button(value='Download localization template', elem_id="download_localization")
reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary', elem_id="settings_reload_script_bodies")
+ with gr.Row():
+ unload_sd_model = gr.Button(value='Unload SD checkpoint to free VRAM', elem_id="sett_unload_sd_model")
+ reload_sd_model = gr.Button(value='Reload the last SD checkpoint back into VRAM', elem_id="sett_reload_sd_model")
with gr.TabItem("Licenses"):
gr.HTML(shared.html("licenses.html"), elem_id="licenses")
gr.Button(value="Show all pages", elem_id="settings_show_all_pages")
+
+
+ def unload_sd_weights():
+ modules.sd_models.unload_model_weights()
+
+ def reload_sd_weights():
+ modules.sd_models.reload_model_weights()
+
+ unload_sd_model.click(
+ fn=unload_sd_weights,
+ inputs=[],
+ outputs=[]
+ )
+
+ reload_sd_model.click(
+ fn=reload_sd_weights,
+ inputs=[],
+ outputs=[]
+ )
request_notifications.click(
fn=lambda: None,
@@ -1681,6 +1683,16 @@ def create_ui():
(train_interface, "Train", "ti"),
]
+ interfaces += script_callbacks.ui_tabs_callback()
+ interfaces += [(settings_interface, "Settings", "settings")]
+
+ extensions_interface = ui_extensions.create_ui()
+ interfaces += [(extensions_interface, "Extensions", "extensions")]
+
+ # shared.tab_names = []
+ # for _interface, label, _ifid in interfaces:
+ # shared.tab_names.append(label)
+
css = ""
for cssfile in modules.scripts.list_files_with_name("style.css"):
@@ -1694,27 +1706,8 @@ def create_ui():
with open(os.path.join(data_path, "user.css"), "r", encoding="utf8") as file:
css += file.read() + "\n"
- if not cmd_opts.no_progressbar_hiding:
- css += css_hide_progressbar
-
- interfaces += script_callbacks.ui_tabs_callback()
- interfaces += [(settings_interface, "Settings", "settings")]
-
- extensions_interface = ui_extensions.create_ui()
- interfaces += [(extensions_interface, "Extensions", "extensions")]
-
- # it doesn't work for all tabs only for txt2img and img2img :( js to the rescue
- # def change_tab(selected):
- # print(selected)
- # return gr.Tabs.update(selected=selected)
-
-
- # shared.tab_names = []
- # for _interface, label, _ifid in interfaces:
- # shared.tab_names.append(label)
-
-
- with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo:
+
+ with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo:
with gr.Row(elem_id="header-top"):
gr.Row(elem_id="nav_menu")
gr.Row(elem_id="nav_menu_header_tabs")
@@ -1751,7 +1744,6 @@ def create_ui():
for interface, label, ifid in interfaces:
# if label in shared.opts.hidden_tabs:
# continue
-
with gr.TabItem(label, id=ifid, elem_id='tab_' + ifid):
interface.render()
@@ -1760,7 +1752,7 @@ def create_ui():
footer = shared.html("footer.html")
footer = footer.format(versions=versions_html())
- gr.HTML(footer, elem_id="footer")
+ gr.HTML(footer)
text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False)
settings_submit.click(
@@ -1771,11 +1763,13 @@ def create_ui():
for i, k, item in quicksettings_list:
component = component_dict[k]
-
+ info = opts.data_labels[k]
+
component.change(
fn=lambda value, k=k: run_settings_single(value, key=k),
inputs=[component],
outputs=[component, text_settings],
+ show_progress=info.refresh is not None,
)
text_settings.change(
@@ -1796,7 +1790,7 @@ def create_ui():
_js="function(v){ var res = desiredCheckpointName; desiredCheckpointName = ''; return [res || v, null]; }",
inputs=[component_dict['sd_model_checkpoint'], dummy_component],
outputs=[component_dict['sd_model_checkpoint'], text_settings],
- )
+ )
component_keys = [k for k in opts.data_labels.keys() if k in component_dict]
@@ -1807,6 +1801,7 @@ def create_ui():
fn=get_settings_values,
inputs=[],
outputs=[component_dict[k] for k in component_keys],
+ queue=False,
)
def modelmerger(*args):
@@ -1929,25 +1924,60 @@ def create_ui():
return demo
-def reload_javascript():
+def webpath(fn):
+ if fn.startswith(script_path):
+ web_path = os.path.relpath(fn, script_path).replace('\\', '/')
+ else:
+ web_path = os.path.abspath(fn)
+
+ return f'file={web_path}?{os.path.getmtime(fn)}'
+
+
+def javascript_html():
script_js = os.path.join(script_path, "script.js")
- head = f'\n'
+ head = f'\n'
inline = f"{localization.localization_js(shared.opts.localization)};"
if cmd_opts.theme is not None:
inline += f"set_theme('{cmd_opts.theme}');"
for script in modules.scripts.list_scripts("javascript", ".js"):
- head += f'\n'
+ head += f'\n'
for script in modules.scripts.list_scripts("javascript", ".mjs"):
- head += f'\n'
+ head += f'\n'
head += f'\n'
+ return head
+
+
+def css_html():
+ head = ""
+
+ def stylesheet(fn):
+ return f' '
+
+ for cssfile in modules.scripts.list_files_with_name("style.css"):
+ if not os.path.isfile(cssfile):
+ continue
+
+ head += stylesheet(cssfile)
+
+ if os.path.exists(os.path.join(data_path, "user.css")):
+ head += stylesheet(os.path.join(data_path, "user.css"))
+
+ return head
+
+
+def reload_javascript():
+ js = javascript_html()
+ #css = css_html()
+
def template_response(*args, **kwargs):
res = shared.GradioTemplateResponseOriginal(*args, **kwargs)
- res.body = res.body.replace(b'', f'{head}'.encode("utf8"))
+ res.body = res.body.replace(b'', f'{js}'.encode("utf8"))
+ #res.body = res.body.replace(b'