diff --git a/CHANGES.md b/CHANGES.md index f1360942..df8a7b80 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.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. * 2.5.42 - 4 Jul 2023 - Keyboard shortcuts for the Image Editor. Thanks @JeLuf. diff --git a/scripts/Developer Console.cmd b/scripts/Developer Console.cmd index 0efbda13..e60cf05b 100644 --- a/scripts/Developer Console.cmd +++ b/scripts/Developer Console.cmd @@ -41,6 +41,10 @@ call python --version echo PYTHONPATH=%PYTHONPATH% +if exist "%cd%\profile" ( + set HF_HOME=%cd%\profile\.cache\huggingface +) + @rem done echo. diff --git a/scripts/check_modules.py b/scripts/check_modules.py index 7b431fca..16b518c8 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.116", + "sdkit": "1.0.125", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", diff --git a/scripts/on_sd_start.bat b/scripts/on_sd_start.bat index 3a8a2961..eddae6b8 100644 --- a/scripts/on_sd_start.bat +++ b/scripts/on_sd_start.bat @@ -104,18 +104,21 @@ call python --version @FOR /F "tokens=* USEBACKQ" %%F IN (`python scripts\get_config.py --default=False net listen_to_network`) DO ( if "%%F" EQU "True" ( - @SET ED_BIND_IP=0.0.0.0 + @FOR /F "tokens=* USEBACKQ" %%G IN (`python scripts\get_config.py --default=0.0.0.0 net bind_ip`) DO ( + @SET ED_BIND_IP=%%G + ) ) else ( @SET ED_BIND_IP=127.0.0.1 ) ) + @cd stable-diffusion @rem set any overrides set HF_HUB_DISABLE_SYMLINKS_WARNING=true -@uvicorn main:server_api --app-dir "%SD_UI_PATH%" --port %ED_BIND_PORT% --host %ED_BIND_IP% --log-level error +@python -m uvicorn main:server_api --app-dir "%SD_UI_PATH%" --port %ED_BIND_PORT% --host %ED_BIND_IP% --log-level error @pause diff --git a/scripts/on_sd_start.sh b/scripts/on_sd_start.sh index e54c72bc..e366bd2a 100755 --- a/scripts/on_sd_start.sh +++ b/scripts/on_sd_start.sh @@ -72,7 +72,7 @@ export SD_UI_PATH=`pwd`/ui export ED_BIND_PORT="$( python scripts/get_config.py --default=9000 net listen_port )" case "$( python scripts/get_config.py --default=False net listen_to_network )" in "True") - export ED_BIND_IP=0.0.0.0 + export ED_BIND_IP=$( python scripts/get_config.py --default=0.0.0.0 net bind_ip) ;; "False") export ED_BIND_IP=127.0.0.1 diff --git a/ui/easydiffusion/model_manager.py b/ui/easydiffusion/model_manager.py index d75292c9..bdecc109 100644 --- a/ui/easydiffusion/model_manager.py +++ b/ui/easydiffusion/model_manager.py @@ -2,6 +2,7 @@ import os import shutil from glob import glob import traceback +from typing import Union from easydiffusion import app from easydiffusion.types import TaskData @@ -93,7 +94,14 @@ def unload_all(context: Context): del context.model_load_errors[model_type] -def resolve_model_to_use(model_name: str = None, model_type: str = None, fail_if_not_found: bool = True): +def resolve_model_to_use(model_name: Union[str, list] = None, model_type: str = None, fail_if_not_found: bool = True): + model_names = model_name if isinstance(model_name, list) else [model_name] + model_paths = [resolve_model_to_use_single(m, model_type, fail_if_not_found) for m in model_names] + + return model_paths[0] if len(model_paths) == 1 else model_paths + + +def resolve_model_to_use_single(model_name: str = None, model_type: str = None, fail_if_not_found: bool = True): model_extensions = MODEL_EXTENSIONS.get(model_type, []) default_models = DEFAULT_MODELS.get(model_type, []) config = app.getConfig() diff --git a/ui/easydiffusion/task_manager.py b/ui/easydiffusion/task_manager.py index 608da41d..a91cd9c6 100644 --- a/ui/easydiffusion/task_manager.py +++ b/ui/easydiffusion/task_manager.py @@ -473,15 +473,15 @@ def start_render_thread(device): render_threads.append(rthread) finally: manager_lock.release() - # timeout = DEVICE_START_TIMEOUT - # while not rthread.is_alive() or not rthread in weak_thread_data or not "device" in weak_thread_data[rthread]: - # if rthread in weak_thread_data and "error" in weak_thread_data[rthread]: - # log.error(f"{rthread}, {device}, error: {weak_thread_data[rthread]['error']}") - # return False - # if timeout <= 0: - # return False - # timeout -= 1 - # time.sleep(1) + timeout = DEVICE_START_TIMEOUT + while not rthread.is_alive() or not rthread in weak_thread_data or not "device" in weak_thread_data[rthread]: + if rthread in weak_thread_data and "error" in weak_thread_data[rthread]: + log.error(f"{rthread}, {device}, error: {weak_thread_data[rthread]['error']}") + return False + if timeout <= 0: + return False + timeout -= 1 + time.sleep(1) return True @@ -535,12 +535,12 @@ def update_render_threads(render_devices, active_devices): if not start_render_thread(device): log.warn(f"{device} failed to start.") - # if is_alive() <= 0: # No running devices, probably invalid user config. - # raise EnvironmentError( - # 'ERROR: No active render devices! Please verify the "render_devices" value in config.json' - # ) + if is_alive() <= 0: # No running devices, probably invalid user config. + raise EnvironmentError( + 'ERROR: No active render devices! Please verify the "render_devices" value in config.json' + ) - # log.debug(f"active devices: {get_devices()['active']}") + log.debug(f"active devices: {get_devices()['active']}") def shutdown_event(): # Signal render thread to close on shutdown diff --git a/ui/easydiffusion/types.py b/ui/easydiffusion/types.py index abf8db29..a9e49a24 100644 --- a/ui/easydiffusion/types.py +++ b/ui/easydiffusion/types.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, List, Union from pydantic import BaseModel @@ -22,7 +22,7 @@ class GenerateImageRequest(BaseModel): sampler_name: str = None # "ddim", "plms", "heun", "euler", "euler_a", "dpm2", "dpm2_a", "lms" hypernetwork_strength: float = 0 - lora_alpha: float = 0 + lora_alpha: Union[float, List[float]] = 0 tiling: str = "none" # "none", "x", "y", "xy" @@ -32,15 +32,14 @@ class TaskData(BaseModel): save_to_disk_path: str = None vram_usage_level: str = "balanced" # or "low" or "medium" - use_face_correction: str = None # or "GFPGANv1.3" - use_upscale: str = None # or "RealESRGAN_x4plus" or "RealESRGAN_x4plus_anime_6B" or "latent_upscaler" + use_face_correction: Union[str, List[str]] = None # or "GFPGANv1.3" + use_upscale: Union[str, List[str]] = None upscale_amount: int = 4 # or 2 latent_upscaler_steps: int = 10 - use_stable_diffusion_model: str = "sd-v1-4" - # use_stable_diffusion_config: str = "v1-inference" - use_vae_model: str = None - use_hypernetwork_model: str = None - use_lora_model: str = None + use_stable_diffusion_model: Union[str, List[str]] = "sd-v1-4" + use_vae_model: Union[str, List[str]] = None + use_hypernetwork_model: Union[str, List[str]] = None + use_lora_model: Union[str, List[str]] = None show_only_filtered_image: bool = False block_nsfw: bool = False diff --git a/ui/easydiffusion/utils/save_utils.py b/ui/easydiffusion/utils/save_utils.py index ff2906a6..75d35dc8 100644 --- a/ui/easydiffusion/utils/save_utils.py +++ b/ui/easydiffusion/utils/save_utils.py @@ -1,6 +1,8 @@ import os import re import time +import regex + from datetime import datetime from functools import reduce @@ -30,11 +32,12 @@ TASK_TEXT_MAPPING = { "lora_alpha": "LoRA Strength", "use_hypernetwork_model": "Hypernetwork model", "hypernetwork_strength": "Hypernetwork Strength", + "use_embedding_models": "Embedding models", "tiling": "Seamless Tiling", "use_face_correction": "Use Face Correction", "use_upscale": "Use Upscaling", "upscale_amount": "Upscale By", - "latent_upscaler_steps": "Latent Upscaler Steps" + "latent_upscaler_steps": "Latent Upscaler Steps", } time_placeholders = { @@ -202,6 +205,9 @@ def get_printable_request(req: GenerateImageRequest, task_data: TaskData): req_metadata = req.dict() task_data_metadata = task_data.dict() + app_config = app.getConfig() + using_diffusers = app_config.get("test_diffusers", False) + # Save the metadata in the order defined in TASK_TEXT_MAPPING metadata = {} for key in TASK_TEXT_MAPPING.keys(): @@ -209,6 +215,24 @@ def get_printable_request(req: GenerateImageRequest, task_data: TaskData): metadata[key] = req_metadata[key] elif key in task_data_metadata: metadata[key] = task_data_metadata[key] + elif key is "use_embedding_models" and using_diffusers: + embeddings_extensions = {".pt", ".bin", ".safetensors"} + def scan_directory(directory_path: str): + used_embeddings = [] + for entry in os.scandir(directory_path): + if entry.is_file(): + entry_extension = os.path.splitext(entry.name)[1] + if entry_extension not in embeddings_extensions: + continue + + embedding_name_regex = regex.compile(r"(^|[\s,])" + regex.escape(os.path.splitext(entry.name)[0]) + r"([+-]*$|[\s,]|[+-]+[\s,])") + if embedding_name_regex.search(req.prompt) or embedding_name_regex.search(req.negative_prompt): + used_embeddings.append(entry.path) + elif entry.is_dir(): + 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 # Clean up the metadata if req.init_image is None and "prompt_strength" in metadata: @@ -222,8 +246,7 @@ def get_printable_request(req: GenerateImageRequest, task_data: TaskData): if task_data.use_upscale != "latent_upscaler" and "latent_upscaler_steps" in metadata: del metadata["latent_upscaler_steps"] - app_config = app.getConfig() - if not app_config.get("test_diffusers", False): + if not using_diffusers: for key in (x for x in ["use_lora_model", "lora_alpha", "clip_skip", "tiling", "latent_upscaler_steps"] if x in metadata): del metadata[key] diff --git a/ui/index.html b/ui/index.html index 1ebde256..b45fc396 100644 --- a/ui/index.html +++ b/ui/index.html @@ -31,7 +31,7 @@