diff --git a/html/locale_en.json b/html/locale_en.json
index 25a6516b9..2c6e77e49 100644
--- a/html/locale_en.json
+++ b/html/locale_en.json
@@ -402,22 +402,22 @@
{"id":"","label":"Directory for temporary images; leave empty for default","localized":"","hint":""},
{"id":"","label":"Enable IPEX Optimize for Intel GPUs","localized":"","hint":""},
{"id":"","label":"Cleanup non-default temporary directory when starting webui","localized":"","hint":""},
- {"id":"","label":"Path to directory with stable diffusion checkpoints","localized":"","hint":""},
- {"id":"","label":"Path to directory with stable diffusion diffusers","localized":"","hint":""},
- {"id":"","label":"Path to directory with VAE files","localized":"","hint":""},
- {"id":"","label":"Embeddings directory for textual inversion","localized":"","hint":""},
- {"id":"","label":"Hypernetwork directory","localized":"","hint":""},
- {"id":"","label":"Path to directory with codeformer model file(s)","localized":"","hint":""},
- {"id":"","label":"Path to directory with GFPGAN model file(s)","localized":"","hint":""},
- {"id":"","label":"Path to directory with ESRGAN model file(s)","localized":"","hint":""},
- {"id":"","label":"Path to directory with BSRGAN model file(s)","localized":"","hint":""},
- {"id":"","label":"Path to directory with RealESRGAN model file(s)","localized":"","hint":""},
- {"id":"","label":"Path to directory with ScuNET model file(s)","localized":"","hint":""},
- {"id":"","label":"Path to directory with SwinIR model file(s)","localized":"","hint":""},
- {"id":"","label":"Path to directory with LDSR model file(s)","localized":"","hint":""},
- {"id":"","label":"Path to directory with CLIP model file(s)","localized":"","hint":""},
- {"id":"","label":"Path to directory with Lora network(s)","localized":"","hint":""},
- {"id":"","label":"Path to directory with LyCORIS network(s)","localized":"","hint":""},
+ {"id":"","label":"Folder with stable diffusion models","localized":"","hint":""},
+ {"id":"","label":"Folder with stable diffusion diffusers","localized":"","hint":""},
+ {"id":"","label":"Folder with VAE files","localized":"","hint":""},
+ {"id":"","label":"Folder with textual inversion embeddings","localized":"","hint":""},
+ {"id":"","label":"Folder with Hypernetwork models","localized":"","hint":""},
+ {"id":"","label":"Folder with codeformer Folder","localized":"","hint":""},
+ {"id":"","label":"Folder with GFPGAN models","localized":"","hint":""},
+ {"id":"","label":"Folder with ESRGAN models","localized":"","hint":""},
+ {"id":"","label":"Folder with BSRGAN models","localized":"","hint":""},
+ {"id":"","label":"Folder with RealESRGAN models","localized":"","hint":""},
+ {"id":"","label":"Folder with ScuNET models","localized":"","hint":""},
+ {"id":"","label":"Folder with SwinIR models","localized":"","hint":""},
+ {"id":"","label":"Folder with LDSR models","localized":"","hint":""},
+ {"id":"","label":"Folder with CLIP models","localized":"","hint":""},
+ {"id":"","label":"Folder with Lora networks","localized":"","hint":""},
+ {"id":"","label":"Folder with LyCORIS networks","localized":"","hint":""},
{"id":"","label":"Path to user-defined styles file","localized":"","hint":""},
{"id":"","label":"Always save all generated images","localized":"","hint":""},
{"id":"","label":"File format for generated images","localized":"","hint":"Select file format for images"},
diff --git a/javascript/black-teal.css b/javascript/black-teal.css
index 1f76b8476..9bbcc4276 100644
--- a/javascript/black-teal.css
+++ b/javascript/black-teal.css
@@ -81,9 +81,10 @@ svg.feather.feather-image, .feather .feather-image { display: none }
.label-wrap { margin: 16px 0px 8px 0px; }
.gradio-slider input[type="number"] { width: 4.5em; font-size: 0.8rem; height: 20px; }
.gradio-button.tool { border: none; background: none; box-shadow: none; filter: hue-rotate(340deg) saturate(0.5); }
-#tab_extensions table td, #tab_extensions table th { border: none; padding: 0.5em; }
-#tab_extensions table { width: 96vw }
-#tab_extensions table thead { background-color: var(--neutral-700); }
+#tab_extensions table td, #tab_extensions table th, #tab_config table td, #tab_config table th { border: none; padding: 0.5em; }
+#tab_extensions table, #tab_config table { width: 96vw }
+#tab_extensions table thead, #tab_config table thead { background-color: var(--neutral-700); }
+#tab_extensions table, #tab_config table { background-color: #222222; }
/* automatic style classes */
.progressDiv { border-radius: var(--radius-sm) !important; position: fixed; top: 44px; right: 26px; max-width: 262px; height: 48px; z-index: 99; box-shadow: var(--button-shadow); }
@@ -108,7 +109,6 @@ svg.feather.feather-image, .feather .feather-image { display: none }
#save-animation { border-radius: var(--radius-sm) !important; margin-bottom: 16px; background-color: #111111; }
#script_list { padding: 4px; margin-top: 20px; margin-bottom: 20px; }
#settings > div.flex-wrap { width: 15em; }
-#tab_extensions table { background-color: #222222; }
#txt2img_cfg_scale { min-width: 200px; }
#txt2img_checkboxes, #img2img_checkboxes { background-color: transparent; }
#txt2img_checkboxes, #img2img_checkboxes { margin-bottom: 0.2em; }
diff --git a/javascript/style.css b/javascript/style.css
index 11e6a5a88..396c2d5ed 100644
--- a/javascript/style.css
+++ b/javascript/style.css
@@ -149,7 +149,6 @@ div#extras_scale_to_tab div.form{ flex-direction: row; }
.global-popup-close:before { content: "×"; }
.global-popup-close{ position: fixed; right: 0.5em; top: 0; cursor: pointer; color: white; font-size: 32pt; }
.global-popup-inner{ display: inline-block; margin: auto; padding: 2em; }
-.ui-defaults-none{ color: #aaa !important; }
/* fullpage image viewer */
@@ -210,8 +209,8 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
.context-menu-items a:hover { background: #a55000; }
/* extensions */
-#tab_extensions table{ border-collapse: collapse; }
-#tab_extensions table td, #tab_extensions table th { border: 1px solid #ccc; padding: 0.25em 0.5em; }
+#tab_extensions table, #tab_config table{ border-collapse: collapse; }
+#tab_extensions table td, #tab_extensions table th, #tab_config table td, #tab_config table th { border: 1px solid #ccc; padding: 0.25em 0.5em; }
#tab_extensions table input[type="checkbox"] { margin-right: 0.5em; appearance: checkbox; }
#tab_extensions button{ max-width: 16em; }
#tab_extensions input[disabled="disabled"]{ opacity: 0.5; }
diff --git a/modules/shared.py b/modules/shared.py
index 277ae33af..f8a2f5d02 100644
--- a/modules/shared.py
+++ b/modules/shared.py
@@ -443,24 +443,24 @@ options_templates.update(options_section(('diffusers', "Diffusers Settings"), {
options_templates.update(options_section(('system-paths', "System Paths"), {
"temp_dir": OptionInfo("", "Directory for temporary images; leave empty for default"),
"clean_temp_dir_at_start": OptionInfo(True, "Cleanup non-default temporary directory when starting webui"),
- "ckpt_dir": OptionInfo(os.path.join(paths.models_path, 'Stable-diffusion'), "Path to directory with stable diffusion checkpoints"),
- "diffusers_dir": OptionInfo(os.path.join(paths.models_path, 'Diffusers'), "Path to directory with stable diffusion diffusers"),
- "vae_dir": OptionInfo(os.path.join(paths.models_path, 'VAE'), "Path to directory with VAE files"),
+ "ckpt_dir": OptionInfo(os.path.join(paths.models_path, 'Stable-diffusion'), "Folder with stable diffusion models"),
+ "diffusers_dir": OptionInfo(os.path.join(paths.models_path, 'Diffusers'), "Folder with Hugggingface models"),
+ "vae_dir": OptionInfo(os.path.join(paths.models_path, 'VAE'), "Folder with VAE files"),
"sd_lora": OptionInfo("", "Add LoRA to prompt", gr.Textbox, {"visible": False}),
- "lora_dir": OptionInfo(os.path.join(paths.models_path, 'Lora'), "Path to directory with LoRA network(s)"),
- "lyco_dir": OptionInfo(os.path.join(paths.models_path, 'LyCORIS'), "Path to directory with LyCORIS network(s)"),
- "styles_dir": OptionInfo(os.path.join(paths.data_path, 'styles.csv'), "Path to user-defined styles file"),
- "embeddings_dir": OptionInfo(os.path.join(paths.models_path, 'embeddings'), "Embeddings directory for textual inversion"),
- "hypernetwork_dir": OptionInfo(os.path.join(paths.models_path, 'hypernetworks'), "Hypernetwork directory"),
- "codeformer_models_path": OptionInfo(os.path.join(paths.models_path, 'Codeformer'), "Path to directory with codeformer model file(s)"),
- "gfpgan_models_path": OptionInfo(os.path.join(paths.models_path, 'GFPGAN'), "Path to directory with GFPGAN model file(s)"),
- "esrgan_models_path": OptionInfo(os.path.join(paths.models_path, 'ESRGAN'), "Path to directory with ESRGAN model file(s)"),
- "bsrgan_models_path": OptionInfo(os.path.join(paths.models_path, 'BSRGAN'), "Path to directory with BSRGAN model file(s)"),
- "realesrgan_models_path": OptionInfo(os.path.join(paths.models_path, 'RealESRGAN'), "Path to directory with RealESRGAN model file(s)"),
- "scunet_models_path": OptionInfo(os.path.join(paths.models_path, 'ScuNET'), "Path to directory with ScuNET model file(s)"),
- "swinir_models_path": OptionInfo(os.path.join(paths.models_path, 'SwinIR'), "Path to directory with SwinIR model file(s)"),
- "ldsr_models_path": OptionInfo(os.path.join(paths.models_path, 'LDSR'), "Path to directory with LDSR model file(s)"),
- "clip_models_path": OptionInfo(os.path.join(paths.models_path, 'CLIP'), "Path to directory with CLIP model file(s)"),
+ "lora_dir": OptionInfo(os.path.join(paths.models_path, 'Lora'), "Folder with LoRA network(s)"),
+ "lyco_dir": OptionInfo(os.path.join(paths.models_path, 'LyCORIS'), "Folder with LyCORIS network(s)"),
+ "styles_dir": OptionInfo(os.path.join(paths.data_path, 'styles.csv'), "File or Folder with user-defined styles"),
+ "embeddings_dir": OptionInfo(os.path.join(paths.models_path, 'embeddings'), "Folder with textual inversion embeddings"),
+ "hypernetwork_dir": OptionInfo(os.path.join(paths.models_path, 'hypernetworks'), "Folder with Hypernetwork models"),
+ "codeformer_models_path": OptionInfo(os.path.join(paths.models_path, 'Codeformer'), "Folder with codeformer models"),
+ "gfpgan_models_path": OptionInfo(os.path.join(paths.models_path, 'GFPGAN'), "Folder with GFPGAN models"),
+ "esrgan_models_path": OptionInfo(os.path.join(paths.models_path, 'ESRGAN'), "Folder with ESRGAN models"),
+ "bsrgan_models_path": OptionInfo(os.path.join(paths.models_path, 'BSRGAN'), "Folder with BSRGAN models"),
+ "realesrgan_models_path": OptionInfo(os.path.join(paths.models_path, 'RealESRGAN'), "Folder with RealESRGAN models"),
+ "scunet_models_path": OptionInfo(os.path.join(paths.models_path, 'ScuNET'), "Folder with ScuNET models"),
+ "swinir_models_path": OptionInfo(os.path.join(paths.models_path, 'SwinIR'), "Folder with SwinIR models"),
+ "ldsr_models_path": OptionInfo(os.path.join(paths.models_path, 'LDSR'), "Folder with LDSR models"),
+ "clip_models_path": OptionInfo(os.path.join(paths.models_path, 'CLIP'), "Folder with CLIP models"),
}))
options_templates.update(options_section(('saving-images', "Image Options"), {
diff --git a/modules/styles.py b/modules/styles.py
index efb2bfc42..54815350f 100644
--- a/modules/styles.py
+++ b/modules/styles.py
@@ -71,7 +71,7 @@ class StyleDatabase:
self.styles[style["name"]] = Style(style["name"], style.get("prompt", ""), style.get("negative", ""), style.get("extra", ""), fn, style.get("preview", ""))
except Exception as e:
log.error(f'Failed to load style: file={fn} error={e}')
- elif os.path.isdir(fn):
+ elif os.path.isdir(fn) and not fn.startswith('.'):
list_folder(fn)
list_folder(self.path)
diff --git a/modules/ui.py b/modules/ui.py
index fdac4969b..34d777990 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -235,11 +235,11 @@ def create_toprow(is_img2img):
with gr.Row():
with gr.Column(scale=80):
with gr.Row():
- prompt = gr.Textbox(elem_id=f"{id_part}_prompt", show_label=False, lines=3, placeholder="Prompt", elem_classes=["prompt"])
+ prompt = gr.Textbox(elem_id=f"{id_part}_prompt", label="Prompt", show_label=False, lines=3, placeholder="Prompt", elem_classes=["prompt"])
with gr.Row():
with gr.Column(scale=80):
with gr.Row():
- negative_prompt = gr.Textbox(elem_id=f"{id_part}_neg_prompt", show_label=False, lines=3, placeholder="Negative prompt", elem_classes=["prompt"])
+ negative_prompt = gr.Textbox(elem_id=f"{id_part}_neg_prompt", label="Negative prompt", show_label=False, lines=3, placeholder="Negative prompt", elem_classes=["prompt"])
button_interrogate = None
button_deepbooru = None
if is_img2img:
@@ -1068,7 +1068,7 @@ def create_ui(startup_timer = None):
with gr.TabItem("Show all pages", variant='primary', elem_id="settings_show_all_pages"):
create_dirty_indicator("show_all_pages", [], interactive=False)
- with gr.TabItem("UI Config", id="system_config", elem_id="system_config_tab"):
+ with gr.TabItem("UI Config", id="system_config", elem_id="tab_config"):
loadsave.create_ui()
create_dirty_indicator("tab_defaults", [], interactive=False)
diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py
index ab6f86724..c789391a1 100644
--- a/modules/ui_extensions.py
+++ b/modules/ui_extensions.py
@@ -290,7 +290,7 @@ def refresh_extensions_list_from_data(search_text, sort_column):
Current version |
|
-
+
"""
if len(extensions_list) == 0:
update_extension_list()
diff --git a/modules/ui_extra_networks_textual_inversion.py b/modules/ui_extra_networks_textual_inversion.py
index 51d077855..520c630d1 100644
--- a/modules/ui_extra_networks_textual_inversion.py
+++ b/modules/ui_extra_networks_textual_inversion.py
@@ -21,12 +21,18 @@ class ExtraNetworksPageTextualInversion(ui_extra_networks.ExtraNetworksPage):
def list_items(self):
if sd_models.model_data.sd_model is None:
embeddings = []
- for root, _dirs, fns in os.walk(shared.opts.embeddings_dir, followlinks=True):
- for fn in fns:
- if fn.lower().endswith(".pt") or fn.lower().endswith(".safetensors"):
- embedding = Embedding(0, fn)
- embedding.filename = os.path.join(root, fn)
+
+ def list_folder(folder):
+ for filename in os.listdir(folder):
+ fn = os.path.join(folder, filename)
+ if os.path.isfile(fn) and (fn.lower().endswith(".pt") or fn.lower().endswith(".safetensors")):
+ embedding = Embedding(0, os.path.basename(fn))
+ embedding.filename = fn
embeddings.append(embedding)
+ elif os.path.isdir(fn) and not fn.startswith('.'):
+ list_folder(fn)
+
+ list_folder(shared.opts.embeddings_dir)
elif shared.backend == shared.Backend.ORIGINAL:
embeddings = list(sd_hijack.model_hijack.embedding_db.word_embeddings.values())
elif hasattr(sd_models.model_data.sd_model, 'embedding_db'):
diff --git a/modules/ui_loadsave.py b/modules/ui_loadsave.py
index b0c647e05..0bd24ff74 100644
--- a/modules/ui_loadsave.py
+++ b/modules/ui_loadsave.py
@@ -112,7 +112,6 @@ class UiLoadsave:
self.write_to_file(self.ui_settings)
def iter_changes(self, values):
- from modules.shared import log
"""
given a dictionary with defaults from a file and current values from gradio elements, returns
an iterator over tuples of values that are not the same between the file and the current;
@@ -138,27 +137,49 @@ class UiLoadsave:
continue
if (new_value == default_value) and (old_value is None):
continue
- log.debug(f'Settings: name={name} component={component} old={old_value} default={default_value} new={new_value}')
yield name, old_value, new_value, default_value
return []
def ui_view(self, *values):
- text = ['| Variable | User value | New value | Default value |
']
- for path, old_value, new_value, default_value in self.iter_changes(values):
+ text = """
+
+
+
+
+
+
+
+
+
+ | Name |
+ Saved value |
+ New value |
+ Default value |
+
+
+ """
+ changed = 0
+ for name, old_value, new_value, default_value in self.iter_changes(values):
+ changed += 1
if old_value is None:
- old_value = "None"
- text.append(f"| {path} | {old_value} | {new_value} | {default_value} |
")
- if len(text) == 1:
- text.append("| No changes |
")
- text.append("")
- return "".join(text)
+ old_value = "None"
+ text += f"| {name} | {old_value} | {new_value} | {default_value} |
"
+ text += "
"
+ if changed == 0:
+ text = 'No changes
'
+ else:
+ text = f'Changed values: {changed}
' + text
+ return text
def ui_apply(self, *values):
+ from modules.shared import log
num_changed = 0
current_ui_settings = self.read_from_file()
- for path, _, new_value, _ in self.iter_changes(values):
+ for name, old_value, new_value, default_value in self.iter_changes(values):
+ component = self.component_mapping[name]
+ log.debug(f'Settings: name={name} component={component} old={old_value} default={default_value} new={new_value}')
num_changed += 1
- current_ui_settings[path] = new_value
+ current_ui_settings[name] = new_value
if num_changed == 0:
return "No changes"
self.write_to_file(current_ui_settings)
@@ -173,12 +194,12 @@ class UiLoadsave:
def create_ui(self):
"""creates ui elements for editing defaults UI, without adding any logic to them"""
- gr.HTML(f"Review changed values and apply them as new user interface defaults
Config file: {self.filename}")
with gr.Row(elem_id="config_row"):
self.ui_defaults_view = gr.Button(value='View changes', elem_id="ui_defaults_view", variant="secondary")
self.ui_defaults_apply = gr.Button(value='Set new defaults', elem_id="ui_defaults_apply", variant="primary")
self.ui_defaults_restore = gr.Button(value='Restore system defaults', elem_id="ui_defaults_restore", variant="primary")
self.ui_defaults_review = gr.HTML("")
+ gr.HTML(f"Review changed values and apply them as new user interface defaults
Config file: {self.filename}")
def setup_ui(self):
"""adds logic to elements created with create_ui; all add_block class must be made before this"""