From 477199357f4f5f02d62857a0cf432a3ed19e6418 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 13 May 2023 20:15:37 +0300 Subject: [PATCH 1/9] add an option to always refer to lora by filenames never refer to lora by an alias if multiple loras have same alias or the alias is called none --- extensions-builtin/Lora/lora.py | 6 ++++++ extensions-builtin/Lora/scripts/lora_script.py | 1 + extensions-builtin/Lora/ui_extra_networks_lora.py | 8 +++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/extensions-builtin/Lora/lora.py b/extensions-builtin/Lora/lora.py index ba1293dfc88..6fa80006897 100644 --- a/extensions-builtin/Lora/lora.py +++ b/extensions-builtin/Lora/lora.py @@ -393,6 +393,8 @@ def lora_MultiheadAttention_load_state_dict(self, *args, **kwargs): def list_available_loras(): available_loras.clear() available_lora_aliases.clear() + forbidden_lora_aliases.clear() + forbidden_lora_aliases.update({"none": 1}) os.makedirs(shared.cmd_opts.lora_dir, exist_ok=True) @@ -406,6 +408,9 @@ def list_available_loras(): available_loras[name] = entry + if entry.alias in available_lora_aliases: + forbidden_lora_aliases[entry.alias.lower()] = 1 + available_lora_aliases[name] = entry available_lora_aliases[entry.alias] = entry @@ -445,6 +450,7 @@ def infotext_pasted(infotext, params): available_loras = {} available_lora_aliases = {} +forbidden_lora_aliases = {} loaded_loras = [] list_available_loras() diff --git a/extensions-builtin/Lora/scripts/lora_script.py b/extensions-builtin/Lora/scripts/lora_script.py index 7db971fd59b..060bda0594c 100644 --- a/extensions-builtin/Lora/scripts/lora_script.py +++ b/extensions-builtin/Lora/scripts/lora_script.py @@ -54,6 +54,7 @@ def 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": ["None"] + [x for x in lora.available_loras]}, refresh=lora.list_available_loras), + "lora_preferred_name": shared.OptionInfo("Alias from file", "When adding to prompt, refer to lora by", gr.Radio, {"choices": ["Alias from file", "Filename"]}), })) diff --git a/extensions-builtin/Lora/ui_extra_networks_lora.py b/extensions-builtin/Lora/ui_extra_networks_lora.py index a0edbc1ebf6..2050e3faabd 100644 --- a/extensions-builtin/Lora/ui_extra_networks_lora.py +++ b/extensions-builtin/Lora/ui_extra_networks_lora.py @@ -15,13 +15,19 @@ def refresh(self): def list_items(self): for name, lora_on_disk in lora.available_loras.items(): path, ext = os.path.splitext(lora_on_disk.filename) + + if shared.opts.lora_preferred_name == "Filename" or lora_on_disk.alias.lower() in lora.forbidden_lora_aliases: + alias = name + else: + alias = lora_on_disk.alias + yield { "name": name, "filename": path, "preview": self.find_preview(path), "description": self.find_description(path), "search_term": self.search_terms_from_path(lora_on_disk.filename), - "prompt": json.dumps(f""), + "prompt": json.dumps(f""), "local_preview": f"{path}.{shared.opts.samples_format}", "metadata": json.dumps(lora_on_disk.metadata, indent=4) if lora_on_disk.metadata else None, } From 7e3539df6f4e3979e080ed5d76faa3649c10f76f Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 13 May 2023 20:21:11 +0300 Subject: [PATCH 2/9] fix upscalers disappearing after the user reloads UI --- modules/modelloader.py | 27 ++++++++++----------------- webui.py | 6 +----- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/modules/modelloader.py b/modules/modelloader.py index cb85ac4ffc8..a70aa0e37f0 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -117,20 +117,6 @@ def move_files(src_path: str, dest_path: str, ext_filter: str = None): pass -builtin_upscaler_classes = [] -forbidden_upscaler_classes = set() - - -def list_builtin_upscalers(): - builtin_upscaler_classes.clear() - builtin_upscaler_classes.extend(Upscaler.__subclasses__()) - -def forbid_loaded_nonbuiltin_upscalers(): - for cls in Upscaler.__subclasses__(): - if cls not in builtin_upscaler_classes: - forbidden_upscaler_classes.add(cls) - - def load_upscalers(): # We can only do this 'magic' method to dynamically load upscalers if they are referenced, # so we'll try to import any _model.py files before looking in __subclasses__ @@ -146,10 +132,17 @@ def load_upscalers(): datas = [] commandline_options = vars(shared.cmd_opts) - for cls in Upscaler.__subclasses__(): - if cls in forbidden_upscaler_classes: - continue + # some of upscaler classes will not go away after reloading their modules, and we'll end + # up with two copies of those classes. The newest copy will always be the last in the list, + # so we go from end to beginning and ignore duplicates + used_classes = {} + for cls in reversed(Upscaler.__subclasses__()): + classname = str(cls) + if classname not in used_classes: + used_classes[classname] = cls + + for cls in reversed(used_classes.values()): name = cls.__name__ cmd_name = f"{name.lower().replace('upscaler', '')}_models_path" scaler = cls(commandline_options.get(cmd_name, None)) diff --git a/webui.py b/webui.py index 727ebd31d10..e8f0a63dd9f 100644 --- a/webui.py +++ b/webui.py @@ -181,14 +181,11 @@ def initialize(): gfpgan.setup_model(cmd_opts.gfpgan_models_path) startup_timer.record("setup gfpgan") - modelloader.list_builtin_upscalers() - startup_timer.record("list builtin upscalers") - modules.scripts.load_scripts() startup_timer.record("load scripts") modelloader.load_upscalers() - #startup_timer.record("load upscalers") #Is this necessary? I don't know. + startup_timer.record("load upscalers") #Is this necessary? I don't know. modules.sd_vae.refresh_vae_list() startup_timer.record("refresh VAE") @@ -388,7 +385,6 @@ def fastapi_setup(self): localization.list_localizations(cmd_opts.localizations_dir) - modelloader.forbid_loaded_nonbuiltin_upscalers() modules.scripts.reload_scripts() startup_timer.record("load scripts") From 063848798c4d4df6d3e108f4cc00c35ca38f5ebd Mon Sep 17 00:00:00 2001 From: AUTOMATIC1111 <16777216c@gmail.com> Date: Sat, 13 May 2023 19:45:18 +0300 Subject: [PATCH 3/9] Merge pull request #10339 from catboxanon/bf16 Allow bf16 in safe unpickler --- modules/safe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/safe.py b/modules/safe.py index e6c2f2c0b7b..e1a67f7368a 100644 --- a/modules/safe.py +++ b/modules/safe.py @@ -40,7 +40,7 @@ def find_class(self, module, name): return getattr(collections, name) if module == 'torch._utils' and name in ['_rebuild_tensor_v2', '_rebuild_parameter', '_rebuild_device_tensor_from_numpy']: return getattr(torch._utils, name) - if module == 'torch' and name in ['FloatStorage', 'HalfStorage', 'IntStorage', 'LongStorage', 'DoubleStorage', 'ByteStorage', 'float32']: + if module == 'torch' and name in ['FloatStorage', 'HalfStorage', 'IntStorage', 'LongStorage', 'DoubleStorage', 'ByteStorage', 'float32', 'BFloat16Storage']: return getattr(torch, name) if module == 'torch.nn.modules.container' and name in ['ParameterDict']: return getattr(torch.nn.modules.container, name) From 12c78138dd56eef029ce74e371c8e646cb07f6fb Mon Sep 17 00:00:00 2001 From: AUTOMATIC1111 <16777216c@gmail.com> Date: Sat, 13 May 2023 19:43:15 +0300 Subject: [PATCH 4/9] Merge pull request #10324 from catboxanon/offline Allow web UI to be ran fully offline --- modules/shared.py | 9 +++++++-- style.css | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index 4631965b4c0..b3508883a33 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -667,14 +667,19 @@ def reload_gradio_theme(theme_name=None): if not theme_name: theme_name = opts.gradio_theme + default_theme_args = dict( + font=["Source Sans Pro", 'ui-sans-serif', 'system-ui', 'sans-serif'], + font_mono=['IBM Plex Mono', 'ui-monospace', 'Consolas', 'monospace'], + ) + if theme_name == "Default": - gradio_theme = gr.themes.Default() + gradio_theme = gr.themes.Default(**default_theme_args) else: try: gradio_theme = gr.themes.ThemeClass.from_hub(theme_name) except Exception as e: errors.display(e, "changing gradio theme") - gradio_theme = gr.themes.Default() + gradio_theme = gr.themes.Default(**default_theme_args) diff --git a/style.css b/style.css index b823c7ddbc5..31b2ed5a694 100644 --- a/style.css +++ b/style.css @@ -1,3 +1,6 @@ +/* temporary fix to load default gradio font in frontend instead of backend */ + +@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600&display=swap'); /* general gradio fixes */ From 27f7fbf35cd72d547d830f97828ee13d3d2009aa Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 13 May 2023 20:24:48 +0300 Subject: [PATCH 5/9] update readme --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1727864dd5..b586b271cdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## Upcoming 1.2.1 + +### Features: + * add an option to always refer to lora by filenames + +### Bug Fixes: + * never refer to lora by an alias if multiple loras have same alias or the alias is called none + * fix upscalers disappearing after the user reloads UI + * allow bf16 in safe unpickler (resolves problems with loading some loras) + * allow web UI to be ran fully offline + ## 1.2.0 ### Features: From 86ff43b930077aa41439c570fe41ad5de910455d Mon Sep 17 00:00:00 2001 From: AUTOMATIC1111 <16777216c@gmail.com> Date: Sat, 13 May 2023 19:44:55 +0300 Subject: [PATCH 6/9] Merge pull request #10335 from akx/l10n-dis-take-2 Localization fixes --- javascript/localization.js | 60 +++++++++++++++++++++----------------- modules/localization.py | 4 +-- modules/ui.py | 12 ++++---- 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/javascript/localization.js b/javascript/localization.js index 0123b877bdb..86e5ca67cfb 100644 --- a/javascript/localization.js +++ b/javascript/localization.js @@ -109,18 +109,23 @@ function processNode(node){ } function dumpTranslations(){ + if(!hasLocalization()) { + // If we don't have any localization, + // we will not have traversed the app to find + // original_lines, so do that now. + processNode(gradioApp()); + } var dumped = {} if (localization.rtl) { - dumped.rtl = true + dumped.rtl = true; } - Object.keys(original_lines).forEach(function(text){ - if(dumped[text] !== undefined) return - - dumped[text] = localization[text] || text - }) + for (const text in original_lines) { + if(dumped[text] !== undefined) continue; + dumped[text] = localization[text] || text; + } - return dumped + return dumped; } function download_localization() { @@ -137,7 +142,11 @@ function download_localization() { document.body.removeChild(element); } -if(hasLocalization()) { +document.addEventListener("DOMContentLoaded", function () { + if (!hasLocalization()) { + return; + } + onUiUpdate(function (m) { m.forEach(function (mutation) { mutation.addedNodes.forEach(function (node) { @@ -146,26 +155,23 @@ if(hasLocalization()) { }); }) + processNode(gradioApp()) - document.addEventListener("DOMContentLoaded", function () { - processNode(gradioApp()) + if (localization.rtl) { // if the language is from right to left, + (new MutationObserver((mutations, observer) => { // wait for the style to load + mutations.forEach(mutation => { + mutation.addedNodes.forEach(node => { + if (node.tagName === 'STYLE') { + observer.disconnect(); - if (localization.rtl) { // if the language is from right to left, - (new MutationObserver((mutations, observer) => { // wait for the style to load - mutations.forEach(mutation => { - mutation.addedNodes.forEach(node => { - if (node.tagName === 'STYLE') { - observer.disconnect(); - - for (const x of node.sheet.rules) { // find all rtl media rules - if (Array.from(x.media || []).includes('rtl')) { - x.media.appendMedium('all'); // enable them - } + for (const x of node.sheet.rules) { // find all rtl media rules + if (Array.from(x.media || []).includes('rtl')) { + x.media.appendMedium('all'); // enable them } } - }) - }); - })).observe(gradioApp(), { childList: true }); - } - }) -} + } + }) + }); + })).observe(gradioApp(), { childList: true }); + } +}) diff --git a/modules/localization.py b/modules/localization.py index f6a6f2fbdf2..ee9c65e7dce 100644 --- a/modules/localization.py +++ b/modules/localization.py @@ -23,7 +23,7 @@ def list_localizations(dirname): localizations[fn] = file.path -def localization_js(current_localization_name): +def localization_js(current_localization_name: str) -> str: fn = localizations.get(current_localization_name, None) data = {} if fn is not None: @@ -34,4 +34,4 @@ def localization_js(current_localization_name): print(f"Error loading localization from {fn}:", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) - return f"var localization = {json.dumps(data)}\n" + return f"window.localization = {json.dumps(data)}" diff --git a/modules/ui.py b/modules/ui.py index d02f6e82c3a..f07bcc41e43 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1863,12 +1863,11 @@ def webpath(fn): def javascript_html(): - script_js = os.path.join(script_path, "script.js") - head = f'\n' + # Ensure localization is in `window` before scripts + 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}');" + script_js = os.path.join(script_path, "script.js") + head += f'\n' for script in modules.scripts.list_scripts("javascript", ".js"): head += f'\n' @@ -1876,7 +1875,8 @@ def javascript_html(): for script in modules.scripts.list_scripts("javascript", ".mjs"): head += f'\n' - head += f'\n' + if cmd_opts.theme: + head += f'\n' return head From d7e9ac2aff6bfd3c03f9d50a98e31468fd34a77f Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 13 May 2023 20:47:32 +0300 Subject: [PATCH 7/9] update readme --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b586b271cdf..a7bf4c2feaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * fix upscalers disappearing after the user reloads UI * allow bf16 in safe unpickler (resolves problems with loading some loras) * allow web UI to be ran fully offline + * fix localizations not working ## 1.2.0 From b9abdb50a3684e2f7392bf68736ad1ec025045af Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 14 May 2023 13:31:03 +0300 Subject: [PATCH 8/9] add a possible fix for 'LatentDiffusion' object has no attribute 'lora_layer_mapping' --- CHANGELOG.md | 1 + extensions-builtin/Lora/lora.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7bf4c2feaa..881870bb9d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * allow bf16 in safe unpickler (resolves problems with loading some loras) * allow web UI to be ran fully offline * fix localizations not working + * fix error for loras: 'LatentDiffusion' object has no attribute 'lora_layer_mapping' ## 1.2.0 diff --git a/extensions-builtin/Lora/lora.py b/extensions-builtin/Lora/lora.py index 6fa80006897..b5d0c98f97d 100644 --- a/extensions-builtin/Lora/lora.py +++ b/extensions-builtin/Lora/lora.py @@ -133,6 +133,10 @@ def load_lora(name, filename): sd = sd_models.read_state_dict(filename) + # this should not be needed but is here as an emergency fix for an unknown error people are experiencing in 1.2.0 + if not hasattr(shared.sd_model, 'lora_layer_mapping'): + assign_lora_names_to_compvis_modules(shared.sd_model) + keys_failed_to_match = {} is_sd2 = 'model_transformer_resblocks' in shared.sd_model.lora_layer_mapping From dbd13dee3aa7c8e37aa43f30a8272b50ba61e7fe Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 14 May 2023 13:34:50 +0300 Subject: [PATCH 9/9] update readme for release --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 881870bb9d4..8cf444ca730 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Upcoming 1.2.1 +## 1.2.1 ### Features: * add an option to always refer to lora by filenames