diff --git a/CHANGES.md b/CHANGES.md index df8a7b80..09af93d3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,7 @@ Our focus continues to remain on an easy installation experience, and an easy user-interface. While still remaining pretty powerful, in terms of features and speed. ### Detailed changelog +* 2.5.45 - 16 Jul 2023 - (beta-only) Fix the image quality of LoRAs, which had degraded in v2.5.44. * 2.5.44 - 15 Jul 2023 - (beta-only) Support for multiple LoRA files. * 2.5.43 - 9 Jul 2023 - (beta-only) Support for loading Textual Inversion embeddings. You can find the option in the Image Settings panel. Thanks @JeLuf. * 2.5.43 - 9 Jul 2023 - Improve the startup time of the UI. diff --git a/scripts/check_modules.py b/scripts/check_modules.py index c2b50796..8de1ff09 100644 --- a/scripts/check_modules.py +++ b/scripts/check_modules.py @@ -18,7 +18,7 @@ os_name = platform.system() modules_to_check = { "torch": ("1.11.0", "1.13.1", "2.0.0"), "torchvision": ("0.12.0", "0.14.1", "0.15.1"), - "sdkit": "1.0.128", + "sdkit": "1.0.131", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", diff --git a/ui/easydiffusion/app.py b/ui/easydiffusion/app.py index 8e317d83..e3de614d 100644 --- a/ui/easydiffusion/app.py +++ b/ui/easydiffusion/app.py @@ -5,7 +5,7 @@ import shutil import socket import sys import traceback -import shlex +import copy from ruamel.yaml import YAML import urllib @@ -102,7 +102,6 @@ def init_render_threads(): update_render_threads() - def getConfig(default_val=APP_CONFIG_DEFAULTS): config_yaml_path = os.path.join(CONFIG_DIR, "..", "config.yaml") @@ -111,6 +110,11 @@ def getConfig(default_val=APP_CONFIG_DEFAULTS): if os.path.isfile(config_legacy_yaml): shutil.move(config_legacy_yaml, config_yaml_path) + def set_config_on_startup(config: dict): + if (getConfig.__config_on_startup is None): + getConfig.__config_on_startup = copy.deepcopy(config) + config["config_on_startup"] = getConfig.__config_on_startup + if os.path.isfile(config_yaml_path): try: yaml = YAML() @@ -126,9 +130,13 @@ def getConfig(default_val=APP_CONFIG_DEFAULTS): config["net"]["listen_to_network"] = os.getenv("SD_UI_BIND_IP") == "0.0.0.0" else: config["net"]["listen_to_network"] = True + + set_config_on_startup(config) + return config except Exception as e: log.warn(traceback.format_exc()) + set_config_on_startup(default_val) return default_val else: try: @@ -149,8 +157,11 @@ def getConfig(default_val=APP_CONFIG_DEFAULTS): return getConfig(default_val) except Exception as e: log.warn(traceback.format_exc()) + set_config_on_startup(default_val) return default_val +getConfig.__config_on_startup = None + def setConfig(config): try: # config.yaml diff --git a/ui/easydiffusion/utils/save_utils.py b/ui/easydiffusion/utils/save_utils.py index 75d35dc8..d68cf25d 100644 --- a/ui/easydiffusion/utils/save_utils.py +++ b/ui/easydiffusion/utils/save_utils.py @@ -192,7 +192,14 @@ def get_metadata_entries_for_request(req: GenerateImageRequest, task_data: TaskD # if text, format it in the text format expected by the UI is_txt_format = task_data.metadata_output_format and "txt" in task_data.metadata_output_format.lower().split(",") if is_txt_format: - metadata = {TASK_TEXT_MAPPING[key]: val for key, val in metadata.items() if key in TASK_TEXT_MAPPING} + def format_value(value): + if isinstance(value, list): + return ", ".join([ str(it) for it in value ]) + return value + + metadata = { + TASK_TEXT_MAPPING[key]: format_value(val) for key, val in metadata.items() if key in TASK_TEXT_MAPPING + } entries = [metadata.copy() for _ in range(req.num_outputs)] for i, entry in enumerate(entries): @@ -232,7 +239,7 @@ def get_printable_request(req: GenerateImageRequest, task_data: TaskData): used_embeddings.extend(scan_directory(entry.path)) return used_embeddings used_embeddings = scan_directory(os.path.join(app.MODELS_DIR, "embeddings")) - metadata["use_embedding_models"] = ", ".join(used_embeddings) if len(used_embeddings) > 0 else None + metadata["use_embedding_models"] = used_embeddings if len(used_embeddings) > 0 else None # Clean up the metadata if req.init_image is None and "prompt_strength" in metadata: diff --git a/ui/index.html b/ui/index.html index 88745196..e89ef1d4 100644 --- a/ui/index.html +++ b/ui/index.html @@ -31,7 +31,7 @@

Easy Diffusion - v2.5.44 + v2.5.45

@@ -147,7 +147,7 @@ - + Click to learn more about Clip Skip @@ -237,7 +237,10 @@ - + +
+ + @@ -246,15 +249,18 @@
- - - Click to learn more about Seamless Tiling - + + + + + Click to learn more about Seamless Tiling + + -
+ ` + modelContainer.appendChild(modelElement) - let modelName = new ModelDropdown(modelEntry.querySelector(".model_name"), modelType, "None") - let modelStrength = modelEntry.querySelector(".model_strength") + let modelName = new ModelDropdown(modelElement.querySelector(".model_name"), modelType, "None") + let modelStrength = modelElement.querySelector(".model_strength") + let entry = [modelName, modelStrength, modelElement] - modelContainer.appendChild(modelEntry) - modelsList.push([modelName, modelStrength]) -} + let removeBtn = document.createElement("button") + removeBtn.innerHTML = '' -function createLoRAEntries() { - let container = document.querySelector("#lora_model_container .model_entries") - for (let i = 0; i < 3; i++) { - addModelEntry(i, container, loraModels, "lora", 0.5, 0.02) + if (modelsList.length === 0) { + removeBtn.classList.add("displayNone") } + + removeBtn.addEventListener("click", function() { + let entryIdx = modelsList.indexOf(entry) + modelsList.splice(entryIdx, 1) + modelContainer.removeChild(modelElement) + }) + + modelElement.appendChild(removeBtn) + + modelsList.push(entry) + + return modelElement } -createLoRAEntries() + +function createLoraEntry() { + let container = document.querySelector("#lora_model_container .model_entries") + return addModelEntry(container, loraModels, "lora", 0.5, 0.02) +} + +function createLoraEntries() { + let firstEntry = createLoraEntry() + + let addLoraBtn = document.querySelector("#lora_model_container .add_model_entry") + addLoraBtn.addEventListener("click", () => { + createLoraEntry() + }) +} +createLoraEntries() // chrome-like spinners only on hover // function showSpinnerOnlyOnHover(e) { diff --git a/ui/media/js/parameters.js b/ui/media/js/parameters.js index 7ae37bd4..ded09206 100644 --- a/ui/media/js/parameters.js +++ b/ui/media/js/parameters.js @@ -424,6 +424,16 @@ async function getAppConfig() { const testDiffusersEnabled = config.test_diffusers && config.update_branch !== "main" testDiffusers.checked = testDiffusersEnabled + if (config.config_on_startup) { + if (config.config_on_startup?.test_diffusers && config.update_branch !== "main") { + document.body.classList.add("diffusers-enabled-on-startup"); + document.body.classList.remove("diffusers-disabled-on-startup"); + } else { + document.body.classList.add("diffusers-disabled-on-startup"); + document.body.classList.remove("diffusers-enabled-on-startup"); + } + } + if (!testDiffusersEnabled) { document.querySelector("#lora_model_container").style.display = "none" document.querySelector("#tiling_container").style.display = "none"