From 991f9cda4223519354a03b66745a9fcdca51f837 Mon Sep 17 00:00:00 2001 From: JeLuF Date: Sat, 22 Apr 2023 11:42:22 +0200 Subject: [PATCH 001/123] Add splash screen for testDiffusers users The splash screen will only be shown once. The splash screen version number can be used to roll out a new splash screen, which will also be shown only once. Clicking on the EasyAndroidLady icon shows the splash screen again. --- ui/index.html | 49 ++++++++++++++++++++++++++++++++++++++++++- ui/media/css/main.css | 18 ++++++++++++++++ ui/media/js/main.js | 15 +++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/ui/index.html b/ui/index.html index 404d88af..0f163af0 100644 --- a/ui/index.html +++ b/ui/index.html @@ -30,7 +30,7 @@

Easy Diffusion - v2.5.33 + v2.5.33

@@ -399,6 +399,52 @@
+ diff --git a/ui/media/css/main.css b/ui/media/css/main.css index d2b1fc55..7d45c3ca 100644 --- a/ui/media/css/main.css +++ b/ui/media/css/main.css @@ -1310,6 +1310,31 @@ body.wait-pause { border-radius: 5px; } +#splash-screen li { + margin-bottom: 6px; +} + +#splash-screen a +{ + color: #ccf; + text-decoration: none; + font-weight: bold; +} + +#splash-screen a[href^="http"]::after, +#splash-screen a[href^="https://"]::after +{ + content: ""; + width: 11px; + height: 11px; + margin-left: 4px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='lightblue' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z'/%3E%3Cpath fill-rule='evenodd' d='M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z'/%3E%3C/svg%3E"); + background-position: center; + background-repeat: no-repeat; + background-size: contain; + display: inline-block; +} + .jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c { color: var(--button-text-color); } From 0f6caaec3319c82427e1bf2274a58091974b8c9c Mon Sep 17 00:00:00 2001 From: JeLuF Date: Mon, 22 May 2023 10:21:19 +0200 Subject: [PATCH 039/123] get_config: return default value if conf file is corrupted --- scripts/get_config.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/get_config.py b/scripts/get_config.py index 02523364..9cdfb2fe 100644 --- a/scripts/get_config.py +++ b/scripts/get_config.py @@ -1,5 +1,6 @@ import os import argparse +import sys # The config file is in the same directory as this script config_directory = os.path.dirname(__file__) @@ -21,16 +22,16 @@ if os.path.isfile(config_yaml): try: config = yaml.safe_load(configfile) except Exception as e: - print(e) - exit() + print(e, file=sys.stderr) + config = {} elif os.path.isfile(config_json): import json with open(config_json, 'r') as configfile: try: config = json.load(configfile) except Exception as e: - print(e) - exit() + print(e, file=sys.stderr) + config = {} else: config = {} From ea9861d180ed4c91749324b8685fd8335570de5b Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 22 May 2023 16:07:50 +0530 Subject: [PATCH 040/123] Less min VRAM requirement --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c6b047e4..6a629e57 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ Click the download button for your operating system:

**Hardware requirements:** -- **Windows:** NVIDIA graphics card, or run on your CPU. -- **Linux:** NVIDIA or AMD graphics card, or run on your CPU. +- **Windows:** NVIDIA graphics card (minimum 2 GB RAM), or run on your CPU. +- **Linux:** NVIDIA or AMD graphics card (minimum 2 GB RAM), or run on your CPU. - **Mac:** M1 or M2, or run on your CPU. - Minimum 8 GB of system RAM. - Atleast 25 GB of space on the hard disk. @@ -86,7 +86,7 @@ Just delete the `EasyDiffusion` folder to uninstall all the downloaded packages. ### Performance and security - **Fast**: Creates a 512x512 image with euler_a in 5 seconds, on an NVIDIA 3060 12GB. -- **Low Memory Usage**: Create 512x512 images with less than 3 GB of GPU RAM, and 768x768 images with less than 4 GB of GPU RAM! +- **Low Memory Usage**: Create 512x512 images with less than 2 GB of GPU RAM, and 768x768 images with less than 3 GB of GPU RAM! - **Use CPU setting**: If you don't have a compatible graphics card, but still want to run it on your CPU. - **Multi-GPU support**: Automatically spreads your tasks across multiple GPUs (if available), for faster performance! - **Auto scan for malicious models**: Uses picklescan to prevent malicious models. From d60cb61e585ea89928c47403a0a5af7cc1c0a7f6 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 22 May 2023 18:06:38 +0530 Subject: [PATCH 041/123] sdkit 1.0.97 - flatten arguments sent to latent upscaler --- scripts/check_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index 1590f569..8747d173 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.96", + "sdkit": "1.0.97", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", From 0127714929c9eb5567a4dd4a0360df2d771db48f Mon Sep 17 00:00:00 2001 From: JeLuF Date: Mon, 22 May 2023 21:19:31 +0200 Subject: [PATCH 042/123] Add 'ED is ready, go to localhost:9000' msg to log Sometimes the browser window does not open (esp. on Linux and Mac). Show a prominent message to the log so that users don't wait for hours. --- ui/easydiffusion/app.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ui/easydiffusion/app.py b/ui/easydiffusion/app.py index b6318f01..3064e151 100644 --- a/ui/easydiffusion/app.py +++ b/ui/easydiffusion/app.py @@ -10,6 +10,8 @@ import warnings from easydiffusion import task_manager from easydiffusion.utils import log from rich.logging import RichHandler +from rich.console import Console +from rich.panel import Panel from sdkit.utils import log as sdkit_log # hack, so we can overwrite the log config # Remove all handlers associated with the root logger object. @@ -213,11 +215,19 @@ def open_browser(): ui = config.get("ui", {}) net = config.get("net", {}) port = net.get("listen_port", 9000) + if ui.get("open_browser_on_start", True): import webbrowser webbrowser.open(f"http://localhost:{port}") + Console().print(Panel( + "\n" + + "[white]Easy Diffusion is ready to serve requests.\n\n" + + "A new browser tab should have been opened by now.\n" + + f"If not, please open your web browser and navigate to [bold yellow underline]http://localhost:{port}/\n", + title="Easy Diffusion is ready", style="bold yellow on blue")) + def get_image_modifiers(): modifiers_json_path = os.path.join(SD_UI_DIR, "modifiers.json") From 2bab4341a3d658e1d4516b68f66449467265329e Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 23 May 2023 16:53:53 +0530 Subject: [PATCH 043/123] Add 'Latent Upscaler' as an option in the upscaling dropdown --- ui/easydiffusion/model_manager.py | 7 +++-- ui/easydiffusion/renderer.py | 24 +++++++++++++---- ui/easydiffusion/types.py | 3 ++- ui/index.html | 8 ++++-- ui/media/css/main.css | 6 +++++ ui/media/js/main.js | 44 ++++++++++++++++++++++++++++++- 6 files changed, 81 insertions(+), 11 deletions(-) diff --git a/ui/easydiffusion/model_manager.py b/ui/easydiffusion/model_manager.py index 324dcec9..d6a227be 100644 --- a/ui/easydiffusion/model_manager.py +++ b/ui/easydiffusion/model_manager.py @@ -107,12 +107,15 @@ def resolve_model_to_use(model_name: str = None, model_type: str = None): def reload_models_if_necessary(context: Context, task_data: TaskData): + use_upscale_lower = task_data.use_upscale.lower() if task_data.use_upscale else "" + model_paths_in_req = { "stable-diffusion": task_data.use_stable_diffusion_model, "vae": task_data.use_vae_model, "hypernetwork": task_data.use_hypernetwork_model, "gfpgan": task_data.use_face_correction, - "realesrgan": task_data.use_upscale, + "realesrgan": task_data.use_upscale if "realesrgan" in use_upscale_lower else None, + "latent_upscaler": True if task_data.use_upscale == "latent_upscaler" else None, "nsfw_checker": True if task_data.block_nsfw else None, "lora": task_data.use_lora_model, } @@ -142,7 +145,7 @@ def resolve_model_paths(task_data: TaskData): if task_data.use_face_correction: task_data.use_face_correction = resolve_model_to_use(task_data.use_face_correction, "gfpgan") - if task_data.use_upscale: + if task_data.use_upscale and "realesrgan" in task_data.use_upscale.lower(): task_data.use_upscale = resolve_model_to_use(task_data.use_upscale, "realesrgan") diff --git a/ui/easydiffusion/renderer.py b/ui/easydiffusion/renderer.py index e26b4389..c60c42df 100644 --- a/ui/easydiffusion/renderer.py +++ b/ui/easydiffusion/renderer.py @@ -95,7 +95,7 @@ def make_images_internal( task_data.stream_image_progress_interval, ) gc(context) - filtered_images = filter_images(task_data, images, user_stopped) + filtered_images = filter_images(req, task_data, images, user_stopped) if task_data.save_to_disk_path is not None: save_images_to_disk(images, filtered_images, req, task_data) @@ -151,22 +151,36 @@ def generate_images_internal( return images, user_stopped -def filter_images(task_data: TaskData, images: list, user_stopped): +def filter_images(req: GenerateImageRequest, task_data: TaskData, images: list, user_stopped): if user_stopped: return images filters_to_apply = [] + filter_params = {} if task_data.block_nsfw: filters_to_apply.append("nsfw_checker") if task_data.use_face_correction and "gfpgan" in task_data.use_face_correction.lower(): filters_to_apply.append("gfpgan") - if task_data.use_upscale and "realesrgan" in task_data.use_upscale.lower(): - filters_to_apply.append("realesrgan") + if task_data.use_upscale: + if "realesrgan" in task_data.use_upscale.lower(): + filters_to_apply.append("realesrgan") + elif task_data.use_upscale == "latent_upscaler": + filters_to_apply.append("latent_upscaler") + + filter_params["latent_upscaler_options"] = { + "prompt": req.prompt, + "negative_prompt": req.negative_prompt, + "seed": req.seed, + "num_inference_steps": task_data.latent_upscaler_steps, + "guidance_scale": 0, + } + + filter_params["scale"] = task_data.upscale_amount if len(filters_to_apply) == 0: return images - return apply_filters(context, filters_to_apply, images, scale=task_data.upscale_amount) + return apply_filters(context, filters_to_apply, images, **filter_params) def construct_response(images: list, seeds: list, task_data: TaskData, base_seed: int): diff --git a/ui/easydiffusion/types.py b/ui/easydiffusion/types.py index 7a5201ab..a76f489a 100644 --- a/ui/easydiffusion/types.py +++ b/ui/easydiffusion/types.py @@ -32,8 +32,9 @@ class TaskData(BaseModel): 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" + use_upscale: str = None # or "RealESRGAN_x4plus" or "RealESRGAN_x4plus_anime_6B" or "latent_upscaler" 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 diff --git a/ui/index.html b/ui/index.html index 99087eec..5097d84a 100644 --- a/ui/index.html +++ b/ui/index.html @@ -258,14 +258,18 @@
  • with +
    + +
  • diff --git a/ui/media/css/main.css b/ui/media/css/main.css index ba513237..8f4f49fa 100644 --- a/ui/media/css/main.css +++ b/ui/media/css/main.css @@ -1303,6 +1303,12 @@ body.wait-pause { display:none !important; } +#latent_upscaler_settings { + padding-top: 3pt; + padding-bottom: 3pt; + padding-left: 5pt; +} + /* TOAST NOTIFICATIONS */ .toast-notification { position: fixed; diff --git a/ui/media/js/main.js b/ui/media/js/main.js index 0ce32f2b..23ed5f46 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -86,6 +86,9 @@ let gfpganModelField = new ModelDropdown(document.querySelector("#gfpgan_model") let useUpscalingField = document.querySelector("#use_upscale") let upscaleModelField = document.querySelector("#upscale_model") let upscaleAmountField = document.querySelector("#upscale_amount") +let latentUpscalerSettings = document.querySelector("#latent_upscaler_settings") +let latentUpscalerStepsSlider = document.querySelector("#latent_upscaler_steps_slider") +let latentUpscalerStepsField = document.querySelector("#latent_upscaler_steps") let stableDiffusionModelField = new ModelDropdown(document.querySelector("#stable_diffusion_model"), "stable-diffusion") let clipSkipField = document.querySelector("#clip_skip") let vaeModelField = new ModelDropdown(document.querySelector("#vae_model"), "vae", "None") @@ -239,7 +242,7 @@ function setServerStatus(event) { break } if (SD.serverState.devices) { - document.dispatchEvent(new CustomEvent("system_info_update", { detail: SD.serverState.devices})) + document.dispatchEvent(new CustomEvent("system_info_update", { detail: SD.serverState.devices })) } } @@ -1268,6 +1271,10 @@ function getCurrentUserRequest() { if (useUpscalingField.checked) { newTask.reqBody.use_upscale = upscaleModelField.value newTask.reqBody.upscale_amount = upscaleAmountField.value + if (upscaleModelField.value === "latent_upscaler") { + newTask.reqBody.upscale_amount = "2" + newTask.reqBody.latent_upscaler_steps = latentUpscalerStepsField.value + } } if (hypernetworkModelField.value) { newTask.reqBody.use_hypernetwork_model = hypernetworkModelField.value @@ -1582,6 +1589,20 @@ useUpscalingField.addEventListener("change", function(e) { upscaleAmountField.disabled = !this.checked }) +function onUpscaleModelChange() { + let upscale4x = document.querySelector("#upscale_amount_4x") + if (upscaleModelField.value === "latent_upscaler") { + upscale4x.disabled = true + upscaleAmountField.value = "2" + latentUpscalerSettings.classList.remove("displayNone") + } else { + upscale4x.disabled = false + latentUpscalerSettings.classList.add("displayNone") + } +} +upscaleModelField.addEventListener("change", onUpscaleModelChange) +onUpscaleModelChange() + makeImageBtn.addEventListener("click", makeImage) document.onkeydown = function(e) { @@ -1591,6 +1612,27 @@ document.onkeydown = function(e) { } } +/********************* Latent Upscaler Steps **************************/ +function updateLatentUpscalerSteps() { + latentUpscalerStepsField.value = latentUpscalerStepsSlider.value + latentUpscalerStepsField.dispatchEvent(new Event("change")) +} + +function updateLatentUpscalerStepsSlider() { + if (latentUpscalerStepsField.value < 1) { + latentUpscalerStepsField.value = 1 + } else if (latentUpscalerStepsField.value > 50) { + latentUpscalerStepsField.value = 50 + } + + latentUpscalerStepsSlider.value = latentUpscalerStepsField.value + latentUpscalerStepsSlider.dispatchEvent(new Event("change")) +} + +latentUpscalerStepsSlider.addEventListener("input", updateLatentUpscalerSteps) +latentUpscalerStepsField.addEventListener("input", updateLatentUpscalerStepsSlider) +updateLatentUpscalerSteps() + /********************* Guidance **************************/ function updateGuidanceScale() { guidanceScaleField.value = guidanceScaleSlider.value / 10 From a87dca1ef4b0c2bd6a0380866b1ca76acbc26c89 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 23 May 2023 16:55:42 +0530 Subject: [PATCH 044/123] changelog --- CHANGES.md | 1 + ui/index.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 9b2b72c1..d8e5c3f0 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.38 - 23 May 2023 - Add Latent Upscaler as another option for upscaling images. Thanks @JeLuf for the implementation of the Latent Upscaler model. * 2.5.37 - 19 May 2023 - (beta-only) Two more samplers: DDPM and DEIS. Also disables the samplers that aren't working yet in the Diffusers version. Thanks @ogmaresca. * 2.5.37 - 19 May 2023 - (beta-only) Support CLIP-Skip. You can set this option under the models dropdown. Thanks @JeLuf. * 2.5.37 - 19 May 2023 - (beta-only) More VRAM optimizations for all modes in diffusers. The VRAM usage for diffusers in "low" and "balanced" should now be equal or less than the non-diffusers version. Performs softmax in half precision, like sdkit does. diff --git a/ui/index.html b/ui/index.html index 5097d84a..dc4eb7f0 100644 --- a/ui/index.html +++ b/ui/index.html @@ -30,7 +30,7 @@

    Easy Diffusion - v2.5.37 + v2.5.38

    From eba83386c1e69ac2d02c8e11c7b59251a518664b Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Wed, 24 May 2023 10:08:00 +0530 Subject: [PATCH 045/123] make a note about a flood fill library --- ui/media/js/image-editor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/media/js/image-editor.js b/ui/media/js/image-editor.js index af19daeb..e7de9f2b 100644 --- a/ui/media/js/image-editor.js +++ b/ui/media/js/image-editor.js @@ -834,6 +834,7 @@ function pixelCompare(int1, int2) { } // adapted from https://ben.akrin.com/canvas_fill/fill_04.html +// May 2023 - look at using a library instead of custom code: https://github.com/shaneosullivan/example-canvas-fill function flood_fill(editor, the_canvas_context, x, y, color) { pixel_stack = [{ x: x, y: y }] pixels = the_canvas_context.getImageData(0, 0, editor.width, editor.height) From 30c07eab6b5fd131fa0858d7582d690fbdb7b76a Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Wed, 24 May 2023 15:30:55 +0530 Subject: [PATCH 046/123] Cleaner reporting of errors in the UI; Suggest increasing the page size if that's the error --- ui/media/js/main.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/ui/media/js/main.js b/ui/media/js/main.js index 23ed5f46..473ed780 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -296,6 +296,7 @@ function logError(msg, res, outputMsg) { logMsg(msg, "error", outputMsg) console.log("request error", res) + console.trace() setStatus("request", "error", "error") } @@ -787,11 +788,6 @@ function getTaskUpdater(task, reqBody, outputContainer) { } msg += "" logError(msg, event, outputMsg) - } else { - let msg = `Unexpected Read Error:
    Error:${
    -                            this.exception
    -                        }
    EventInfo: ${JSON.stringify(event, undefined, 4)}
    ` - logError(msg, event, outputMsg) } break } @@ -888,15 +884,15 @@ function onTaskCompleted(task, reqBody, instance, outputContainer, stepUpdate) { 1. If you have set an initial image, please try reducing its dimension to ${MAX_INIT_IMAGE_DIMENSION}x${MAX_INIT_IMAGE_DIMENSION} or smaller.
    2. Try picking a lower level in the 'GPU Memory Usage' setting (in the 'Settings' tab).
    3. Try generating a smaller image.
    ` - } else if (msg.toLowerCase().includes("DefaultCPUAllocator: not enough memory")) { + } else if (msg.includes("DefaultCPUAllocator: not enough memory")) { msg += `

    Reason: Your computer is running out of system RAM! -
    +

    Suggestions:
    1. Try closing unnecessary programs and browser tabs.
    2. If that doesn't help, please increase your computer's virtual memory by following these steps for - Windows, or + Windows or Linux.
    3. Try restarting your computer.
    ` } From 8554b0eab2a355c5472c42ccad039b01c7f18d67 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Wed, 24 May 2023 16:02:53 +0530 Subject: [PATCH 047/123] Better reporting of model load errors - sends the report to the browser UI during the next image rendering task --- ui/easydiffusion/model_manager.py | 23 ++++++++++++++++++++++- ui/easydiffusion/renderer.py | 1 + ui/easydiffusion/task_manager.py | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/ui/easydiffusion/model_manager.py b/ui/easydiffusion/model_manager.py index d6a227be..0a1f1b5c 100644 --- a/ui/easydiffusion/model_manager.py +++ b/ui/easydiffusion/model_manager.py @@ -53,15 +53,21 @@ def load_default_models(context: Context): scan_model=context.model_paths[model_type] != None and not context.model_paths[model_type].endswith(".safetensors"), ) + if model_type in context.model_load_errors: + del context.model_load_errors[model_type] except Exception as e: log.error(f"[red]Error while loading {model_type} model: {context.model_paths[model_type]}[/red]") log.exception(e) del context.model_paths[model_type] + context.model_load_errors[model_type] = str(e) # storing the entire Exception can lead to memory leaks + def unload_all(context: Context): for model_type in KNOWN_MODEL_TYPES: unload_model(context, model_type) + if model_type in context.model_load_errors: + del context.model_load_errors[model_type] def resolve_model_to_use(model_name: str = None, model_type: str = None): @@ -132,7 +138,14 @@ def reload_models_if_necessary(context: Context, task_data: TaskData): context.model_paths[model_type] = model_path_in_req action_fn = unload_model if context.model_paths[model_type] is None else load_model - action_fn(context, model_type, scan_model=False) # we've scanned them already + try: + action_fn(context, model_type, scan_model=False) # we've scanned them already + if model_type in context.model_load_errors: + del context.model_load_errors[model_type] + except Exception as e: + log.exception(e) + if action_fn == load_model: + context.model_load_errors[model_type] = str(e) # storing the entire Exception can lead to memory leaks def resolve_model_paths(task_data: TaskData): @@ -149,6 +162,14 @@ def resolve_model_paths(task_data: TaskData): task_data.use_upscale = resolve_model_to_use(task_data.use_upscale, "realesrgan") +def fail_if_models_did_not_load(context: Context): + for model_type in KNOWN_MODEL_TYPES: + if model_type in context.model_load_errors: + e = context.model_load_errors[model_type] + raise Exception(f"Could not load the {model_type} model! Reason: " + e) + # concat 'e', don't use in format string (injection attack) + + def set_vram_optimizations(context: Context): config = app.getConfig() vram_usage_level = config.get("vram_usage_level", "balanced") diff --git a/ui/easydiffusion/renderer.py b/ui/easydiffusion/renderer.py index c60c42df..e2dae34f 100644 --- a/ui/easydiffusion/renderer.py +++ b/ui/easydiffusion/renderer.py @@ -33,6 +33,7 @@ def init(device): context.stop_processing = False context.temp_images = {} context.partial_x_samples = None + context.model_load_errors = {} from easydiffusion import app diff --git a/ui/easydiffusion/task_manager.py b/ui/easydiffusion/task_manager.py index c11acbec..a91cd9c6 100644 --- a/ui/easydiffusion/task_manager.py +++ b/ui/easydiffusion/task_manager.py @@ -336,6 +336,7 @@ def thread_render(device): current_state = ServerStates.LoadingModel model_manager.resolve_model_paths(task.task_data) model_manager.reload_models_if_necessary(renderer.context, task.task_data) + model_manager.fail_if_models_did_not_load(renderer.context) current_state = ServerStates.Rendering task.response = renderer.make_images( From db265309a57d576f2ec08433c56c33b8f8bb27a4 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Wed, 24 May 2023 16:24:29 +0530 Subject: [PATCH 048/123] Show an explanation for why the CPU toggle is disabled; utility class for alert() and confirm() that matches the ED theme; code formatting --- ui/media/js/main.js | 19 +++------ ui/media/js/parameters.js | 19 +++++++-- ui/media/js/utils.js | 90 +++++++++++++++++++++++++-------------- 3 files changed, 79 insertions(+), 49 deletions(-) diff --git a/ui/media/js/main.js b/ui/media/js/main.js index 473ed780..ecd8ad73 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -261,20 +261,11 @@ function shiftOrConfirm(e, prompt, fn) { if (e.shiftKey || !confirmDangerousActionsField.checked) { fn(e) } else { - $.confirm({ - theme: "modern", - title: prompt, - useBootstrap: false, - animateFromElement: false, - content: - 'Tip: To skip this dialog, use shift-click or disable the "Confirm dangerous actions" setting in the Settings tab.', - buttons: { - yes: () => { - fn(e) - }, - cancel: () => {}, - }, - }) + confirm( + 'Tip: To skip this dialog, use shift-click or disable the "Confirm dangerous actions" setting in the Settings tab.', + prompt, + fn + ) } } diff --git a/ui/media/js/parameters.js b/ui/media/js/parameters.js index f51b5290..4c7240eb 100644 --- a/ui/media/js/parameters.js +++ b/ui/media/js/parameters.js @@ -191,7 +191,8 @@ var PARAMETERS = [ id: "listen_port", type: ParameterType.custom, label: "Network port", - note: "Port that this server listens to. The '9000' part in 'http://localhost:9000'. Please restart the program after changing this.", + note: + "Port that this server listens to. The '9000' part in 'http://localhost:9000'. Please restart the program after changing this.", icon: "fa-anchor", render: (parameter) => { return `` @@ -396,14 +397,14 @@ async function getAppConfig() { document.querySelector("#lora_model_container").style.display = "none" document.querySelector("#lora_alpha_container").style.display = "none" - document.querySelectorAll("#sampler_name option.diffusers-only").forEach(option => { + document.querySelectorAll("#sampler_name option.diffusers-only").forEach((option) => { option.style.display = "none" }) } else { document.querySelector("#lora_model_container").style.display = "" document.querySelector("#lora_alpha_container").style.display = loraModelField.value ? "" : "none" - document.querySelectorAll("#sampler_name option.k_diffusion-only").forEach(option => { + document.querySelectorAll("#sampler_name option.k_diffusion-only").forEach((option) => { option.disabled = true }) document.querySelector("#clip_skip_config").classList.remove("displayNone") @@ -568,6 +569,16 @@ async function getSystemInfo() { if (allDeviceIds.length === 0) { useCPUField.checked = true useCPUField.disabled = true // no compatible GPUs, so make the CPU mandatory + + getParameterSettingsEntry("use_cpu").addEventListener("click", function() { + alert( + "Sorry, we could not find a compatible graphics card! Easy Diffusion supports graphics cards with minimum 2 GB of RAM. " + + "Only NVIDIA cards are supported on Windows. NVIDIA and AMD cards are supported on Linux.

    " + + "If you have a compatible graphics card, please try updating to the latest drivers.

    " + + "Only the CPU can be used for generating images, without a compatible graphics card.", + "No compatible graphics card found!" + ) + }) } autoPickGPUsField.checked = devices["config"] === "auto" @@ -586,7 +597,7 @@ async function getSystemInfo() { $("#use_gpus").val(activeDeviceIds) } - document.dispatchEvent(new CustomEvent("system_info_update", { detail: devices})) + document.dispatchEvent(new CustomEvent("system_info_update", { detail: devices })) setHostInfo(res["hosts"]) let force = false if (res["enforce_output_dir"] !== undefined) { diff --git a/ui/media/js/utils.js b/ui/media/js/utils.js index d1578d8e..16778b2d 100644 --- a/ui/media/js/utils.js +++ b/ui/media/js/utils.js @@ -843,57 +843,85 @@ function createTab(request) { /* TOAST NOTIFICATIONS */ function showToast(message, duration = 5000, error = false) { - const toast = document.createElement("div"); - toast.classList.add("toast-notification"); + const toast = document.createElement("div") + toast.classList.add("toast-notification") if (error === true) { - toast.classList.add("toast-notification-error"); + toast.classList.add("toast-notification-error") } - toast.innerHTML = message; - document.body.appendChild(toast); + toast.innerHTML = message + document.body.appendChild(toast) // Set the position of the toast on the screen - const toastCount = document.querySelectorAll(".toast-notification").length; - const toastHeight = toast.offsetHeight; + const toastCount = document.querySelectorAll(".toast-notification").length + const toastHeight = toast.offsetHeight const previousToastsHeight = Array.from(document.querySelectorAll(".toast-notification")) .slice(0, -1) // exclude current toast - .reduce((totalHeight, toast) => totalHeight + toast.offsetHeight + 10, 0); // add 10 pixels for spacing - toast.style.bottom = `${10 + previousToastsHeight}px`; - toast.style.right = "10px"; + .reduce((totalHeight, toast) => totalHeight + toast.offsetHeight + 10, 0) // add 10 pixels for spacing + toast.style.bottom = `${10 + previousToastsHeight}px` + toast.style.right = "10px" // Delay the removal of the toast until animation has completed const removeToast = () => { - toast.classList.add("hide"); + toast.classList.add("hide") const removeTimeoutId = setTimeout(() => { - toast.remove(); + toast.remove() // Adjust the position of remaining toasts - const remainingToasts = document.querySelectorAll(".toast-notification"); - const removedToastBottom = toast.getBoundingClientRect().bottom; - + const remainingToasts = document.querySelectorAll(".toast-notification") + const removedToastBottom = toast.getBoundingClientRect().bottom + remainingToasts.forEach((toast) => { if (toast.getBoundingClientRect().bottom < removedToastBottom) { - toast.classList.add("slide-down"); + toast.classList.add("slide-down") } - }); - + }) + // Wait for the slide-down animation to complete setTimeout(() => { // Remove the slide-down class after the animation has completed - const slidingToasts = document.querySelectorAll(".slide-down"); + const slidingToasts = document.querySelectorAll(".slide-down") slidingToasts.forEach((toast) => { - toast.classList.remove("slide-down"); - }); - + toast.classList.remove("slide-down") + }) + // Adjust the position of remaining toasts again, in case there are multiple toasts being removed at once - const remainingToastsDown = document.querySelectorAll(".toast-notification"); - let heightSoFar = 0; + const remainingToastsDown = document.querySelectorAll(".toast-notification") + let heightSoFar = 0 remainingToastsDown.forEach((toast) => { - toast.style.bottom = `${10 + heightSoFar}px`; - heightSoFar += toast.offsetHeight + 10; // add 10 pixels for spacing - }); - }, 0); // The duration of the slide-down animation (in milliseconds) - }, 500); - }; + toast.style.bottom = `${10 + heightSoFar}px` + heightSoFar += toast.offsetHeight + 10 // add 10 pixels for spacing + }) + }, 0) // The duration of the slide-down animation (in milliseconds) + }, 500) + } // Remove the toast after specified duration - setTimeout(removeToast, duration); + setTimeout(removeToast, duration) +} + +function alert(msg, title) { + title = title || "" + $.alert({ + theme: "modern", + title: title, + useBootstrap: false, + animateFromElement: false, + content: msg, + }) +} + +function confirm(msg, title, fn) { + title = title || "" + $.confirm({ + theme: "modern", + title: title, + useBootstrap: false, + animateFromElement: false, + content: msg, + buttons: { + yes: () => { + fn(e) + }, + cancel: () => {}, + }, + }) } From 3d7e16cfd944540a0e5b9a0f0c8c10b760f6cf7d Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Wed, 24 May 2023 16:29:58 +0530 Subject: [PATCH 049/123] changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index d8e5c3f0..a1e49336 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.38 - 24 May 2023 - Better reporting of errors, and show an explanation if the user cannot disable the "Use CPU" setting. * 2.5.38 - 23 May 2023 - Add Latent Upscaler as another option for upscaling images. Thanks @JeLuf for the implementation of the Latent Upscaler model. * 2.5.37 - 19 May 2023 - (beta-only) Two more samplers: DDPM and DEIS. Also disables the samplers that aren't working yet in the Diffusers version. Thanks @ogmaresca. * 2.5.37 - 19 May 2023 - (beta-only) Support CLIP-Skip. You can set this option under the models dropdown. Thanks @JeLuf. From 3ea74af76d32f005eaed7df6bc9245e99f99ffd6 Mon Sep 17 00:00:00 2001 From: JeLuF Date: Wed, 24 May 2023 19:29:54 +0200 Subject: [PATCH 050/123] Fix confirmation dialog By splitting the confirmation function into two halves, the closure was lost --- ui/media/js/main.js | 2 +- ui/media/js/utils.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ui/media/js/main.js b/ui/media/js/main.js index ecd8ad73..fa37600a 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -264,7 +264,7 @@ function shiftOrConfirm(e, prompt, fn) { confirm( 'Tip: To skip this dialog, use shift-click or disable the "Confirm dangerous actions" setting in the Settings tab.', prompt, - fn + () => { fn(e) } ) } } diff --git a/ui/media/js/utils.js b/ui/media/js/utils.js index 16778b2d..6ddb0ae6 100644 --- a/ui/media/js/utils.js +++ b/ui/media/js/utils.js @@ -918,9 +918,7 @@ function confirm(msg, title, fn) { animateFromElement: false, content: msg, buttons: { - yes: () => { - fn(e) - }, + yes: fn, cancel: () => {}, }, }) From 9dfa300083eba3b5f059c889f7c55e6468a27271 Mon Sep 17 00:00:00 2001 From: JeLuF Date: Thu, 25 May 2023 00:16:14 +0200 Subject: [PATCH 051/123] Add seamless tiling support --- ui/easydiffusion/types.py | 1 + ui/index.html | 9 +++++++++ ui/media/js/auto-save.js | 1 + ui/media/js/dnd.js | 8 ++++++++ ui/media/js/engine.js | 3 ++- ui/media/js/main.js | 7 +++++++ 6 files changed, 28 insertions(+), 1 deletion(-) diff --git a/ui/easydiffusion/types.py b/ui/easydiffusion/types.py index a76f489a..e4426714 100644 --- a/ui/easydiffusion/types.py +++ b/ui/easydiffusion/types.py @@ -23,6 +23,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 + tiling: str = "none" # "none", "x", "y", "xy" class TaskData(BaseModel): diff --git a/ui/index.html b/ui/index.html index dc4eb7f0..4814446b 100644 --- a/ui/index.html +++ b/ui/index.html @@ -236,6 +236,15 @@
    + + + Click to learn more about Seamless Tiling +
    - +
    - + Click to learn more about samplers From 69d937e0b1e1eb94855fa2b3b155e8b3b5df3ac4 Mon Sep 17 00:00:00 2001 From: Olivia Godone-Maresca Date: Fri, 26 May 2023 19:51:30 -0400 Subject: [PATCH 059/123] Add tiling and latent upscaler steps to metadata Also fix txt metadata labels when also embedding metadata --- ui/easydiffusion/utils/save_utils.py | 26 ++++++++++++++++---------- ui/media/js/auto-save.js | 1 + ui/media/js/dnd.js | 8 ++++++++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/ui/easydiffusion/utils/save_utils.py b/ui/easydiffusion/utils/save_utils.py index 24b2198c..6a6f7239 100644 --- a/ui/easydiffusion/utils/save_utils.py +++ b/ui/easydiffusion/utils/save_utils.py @@ -30,9 +30,11 @@ TASK_TEXT_MAPPING = { "lora_alpha": "LoRA Strength", "use_hypernetwork_model": "Hypernetwork model", "hypernetwork_strength": "Hypernetwork Strength", + "tiling": "Seamless Tiling", "use_face_correction": "Use Face Correction", "use_upscale": "Use Upscaling", "upscale_amount": "Upscale By", + "latent_upscaler_steps": "Latent Upscaler Steps" } time_placeholders = { @@ -169,21 +171,23 @@ def save_images_to_disk(images: list, filtered_images: list, req: GenerateImageR output_quality=task_data.output_quality, output_lossless=task_data.output_lossless, ) - if task_data.metadata_output_format.lower() in ["json", "txt", "embed"]: - save_dicts( - metadata_entries, - save_dir_path, - file_name=make_filter_filename, - output_format=task_data.metadata_output_format, - file_format=task_data.output_format, - ) + if task_data.metadata_output_format: + for metadata_output_format in task_data.metadata_output_format.split(","): + if metadata_output_format.lower() in ["json", "txt", "embed"]: + save_dicts( + metadata_entries, + save_dir_path, + file_name=make_filter_filename, + output_format=task_data.metadata_output_format, + file_format=task_data.output_format, + ) def get_metadata_entries_for_request(req: GenerateImageRequest, task_data: TaskData): metadata = get_printable_request(req, task_data) # if text, format it in the text format expected by the UI - is_txt_format = task_data.metadata_output_format.lower() == "txt" + 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} @@ -215,10 +219,12 @@ def get_printable_request(req: GenerateImageRequest, task_data: TaskData): del metadata["hypernetwork_strength"] if task_data.use_lora_model is None and "lora_alpha" in metadata: del metadata["lora_alpha"] + if task_data.use_upscale is not "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): - for key in (x for x in ["use_lora_model", "lora_alpha", "clip_skip"] if x in metadata): + 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] return metadata diff --git a/ui/media/js/auto-save.js b/ui/media/js/auto-save.js index 1424a301..bbcbf9a5 100644 --- a/ui/media/js/auto-save.js +++ b/ui/media/js/auto-save.js @@ -35,6 +35,7 @@ const SETTINGS_IDS_LIST = [ "gfpgan_model", "use_upscale", "upscale_amount", + "latent_upscaler_steps", "block_nsfw", "show_only_filtered_image", "upscale_model", diff --git a/ui/media/js/dnd.js b/ui/media/js/dnd.js index a303301e..09def0b8 100644 --- a/ui/media/js/dnd.js +++ b/ui/media/js/dnd.js @@ -221,6 +221,14 @@ const TASK_MAPPING = { readUI: () => upscaleAmountField.value, parse: (val) => val, }, + latent_upscaler_steps: { + name: "Latent Upscaler Steps", + setUI: (latent_upscaler_steps) => { + latentUpscalerStepsField.value = latent_upscaler_steps + }, + readUI: () => latentUpscalerStepsField.value, + parse: (val) => val, + }, sampler_name: { name: "Sampler", setUI: (sampler_name) => { From 6826435046421e350c2b92608e61f0e3694a702c Mon Sep 17 00:00:00 2001 From: patriceac <48073125+patriceac@users.noreply.github.com> Date: Sat, 27 May 2023 00:26:25 -0700 Subject: [PATCH 060/123] Fix restore task to UI flow Fixes a regression introduced by https://github.com/cmdr2/stable-diffusion-ui/pull/1304 --- ui/media/js/dnd.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/media/js/dnd.js b/ui/media/js/dnd.js index a303301e..bac15bba 100644 --- a/ui/media/js/dnd.js +++ b/ui/media/js/dnd.js @@ -43,7 +43,6 @@ const TASK_MAPPING = { name: "Prompt", setUI: (prompt) => { promptField.value = prompt - promptField.dispatchEvent(new Event("input")) }, readUI: () => promptField.value, parse: (val) => val, @@ -422,6 +421,7 @@ function restoreTaskToUI(task, fieldsToSkip) { if (!("original_prompt" in task.reqBody)) { promptField.value = task.reqBody.prompt } + promptField.dispatchEvent(new Event("input")) // properly reset checkboxes if (!("use_face_correction" in task.reqBody)) { From 2080d6e27b66ebffa1b0ff112112d498e6caca68 Mon Sep 17 00:00:00 2001 From: JeLuF Date: Sun, 28 May 2023 00:50:23 +0200 Subject: [PATCH 061/123] Share ED via Cloudflare's ArgoTunnel Shares the Easy Diffusion instance via https://try.cloudflare.com/ --- scripts/check_modules.py | 1 + ui/easydiffusion/server.py | 54 ++++++++++++++++++++++++++++++++++++++ ui/index.html | 11 ++++++-- ui/media/css/auto-save.css | 8 +++--- ui/media/css/main.css | 9 +++++++ ui/media/js/engine.js | 4 +++ ui/media/js/main.js | 32 ++++++++++++++++++++++ ui/media/js/parameters.js | 46 +++++++++++++++++++++++++++++--- 8 files changed, 157 insertions(+), 8 deletions(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index 8747d173..534e1e58 100644 --- a/scripts/check_modules.py +++ b/scripts/check_modules.py @@ -23,6 +23,7 @@ modules_to_check = { "rich": "12.6.0", "uvicorn": "0.19.0", "fastapi": "0.85.1", + "pycloudflared": "0.2.0", # "xformers": "0.0.16", } diff --git a/ui/easydiffusion/server.py b/ui/easydiffusion/server.py index a1aab6c0..b9ffe5f9 100644 --- a/ui/easydiffusion/server.py +++ b/ui/easydiffusion/server.py @@ -15,6 +15,7 @@ from fastapi import FastAPI, HTTPException from fastapi.staticfiles import StaticFiles from pydantic import BaseModel, Extra from starlette.responses import FileResponse, JSONResponse, StreamingResponse +from pycloudflared import try_cloudflare log.info(f"started in {app.SD_DIR}") log.info(f"started at {datetime.datetime.now():%x %X}") @@ -113,6 +114,14 @@ def init(): def get_image(task_id: int, img_id: int): return get_image_internal(task_id, img_id) + @server_api.post("/tunnel/cloudflare/start") + def start_cloudflare_tunnel(req: dict): + return start_cloudflare_tunnel_internal(req) + + @server_api.post("/tunnel/cloudflare/stop") + def stop_cloudflare_tunnel(req: dict): + return stop_cloudflare_tunnel_internal(req) + @server_api.get("/") def read_root(): return FileResponse(os.path.join(app.SD_UI_DIR, "index.html"), headers=NOCACHE_HEADERS) @@ -211,6 +220,8 @@ def ping_internal(session_id: str = None): session = task_manager.get_cached_session(session_id, update_ttl=True) response["tasks"] = {id(t): t.status for t in session.tasks} response["devices"] = task_manager.get_devices() + if cloudflare.address != None: + response["cloudflare"] = cloudflare.address return JSONResponse(response, headers=NOCACHE_HEADERS) @@ -322,3 +333,46 @@ def get_image_internal(task_id: int, img_id: int): return StreamingResponse(img_data, media_type="image/jpeg") except KeyError as e: raise HTTPException(status_code=500, detail=str(e)) + +#---- Cloudflare Tunnel ---- +class CloudflareTunnel: + def __init__(self): + config = app.getConfig() + self.Urls = None + self.port = config["net"]["listen_port"] + + def start(self): + self.Urls = try_cloudflare(self.port) + + def stop(self): + if self.Urls != None: + try_cloudflare.terminate(self.port) + self.Urls = None + + @property + def address(self): + if self.Urls != None: + return self.Urls.tunnel + else: + return None + +cloudflare = CloudflareTunnel() + +def start_cloudflare_tunnel_internal(req: dict): + try: + cloudflare.start() + log.info(f"- Started cloudflare tunnel. Using address: {cloudflare.address}") + return JSONResponse({"address":cloudflare.address}) + except Exception as e: + log.error(str(e)) + log.error(traceback.format_exc()) + return HTTPException(status_code=500, detail=str(e)) + +def stop_cloudflare_tunnel_internal(req: dict): + try: + cloudflare.stop() + except Exception as e: + log.error(str(e)) + log.error(traceback.format_exc()) + return HTTPException(status_code=500, detail=str(e)) + diff --git a/ui/index.html b/ui/index.html index dc4eb7f0..18837b59 100644 --- a/ui/index.html +++ b/ui/index.html @@ -347,10 +347,16 @@

    System Settings

    -
    +



    +
    +

    Share Easy Diffusion

    +
    +
    +
    +

    System Info

    @@ -525,7 +531,8 @@ async function init() { SD.init({ events: { statusChange: setServerStatus, - idle: onIdle + idle: onIdle, + ping: tunnelUpdate } }) diff --git a/ui/media/css/auto-save.css b/ui/media/css/auto-save.css index 80aa48d8..119a7e10 100644 --- a/ui/media/css/auto-save.css +++ b/ui/media/css/auto-save.css @@ -69,13 +69,15 @@ } .parameters-table > div:first-child { - border-radius: 12px 12px 0px 0px; + border-top-left-radius: 12px; + border-top-right-radius: 12px; } .parameters-table > div:last-child { - border-radius: 0px 0px 12px 12px; + border-bottom-left-radius: 12px; + border-bottom-right-radius: 12px; } .parameters-table .fa-fire { color: #F7630C; -} \ No newline at end of file +} diff --git a/ui/media/css/main.css b/ui/media/css/main.css index 8f4f49fa..47a88601 100644 --- a/ui/media/css/main.css +++ b/ui/media/css/main.css @@ -1309,6 +1309,15 @@ body.wait-pause { padding-left: 5pt; } +#cloudflare-address { + background-color: var(--background-color3); + padding: 6px; + border-radius: var(--input-border-radius); + border: var(--input-border-size) solid var(--input-border-color); + margin-top: 0.2em; + margin-bottom: 0.2em; +} + /* TOAST NOTIFICATIONS */ .toast-notification { position: fixed; diff --git a/ui/media/js/engine.js b/ui/media/js/engine.js index eccae6ac..506451d6 100644 --- a/ui/media/js/engine.js +++ b/ui/media/js/engine.js @@ -186,6 +186,7 @@ const EVENT_TASK_START = "taskStart" const EVENT_TASK_END = "taskEnd" const EVENT_TASK_ERROR = "task_error" + const EVENT_PING = "ping" const EVENT_UNEXPECTED_RESPONSE = "unexpectedResponse" const EVENTS_TYPES = [ EVENT_IDLE, @@ -196,6 +197,7 @@ EVENT_TASK_START, EVENT_TASK_END, EVENT_TASK_ERROR, + EVENT_PING, EVENT_UNEXPECTED_RESPONSE, ] @@ -240,6 +242,7 @@ setServerStatus("error", "offline") return false } + // Set status switch (serverState.status) { case ServerStates.init: @@ -261,6 +264,7 @@ break } serverState.time = Date.now() + await eventSource.fireEvent(EVENT_PING, serverState) return true } catch (e) { console.error(e) diff --git a/ui/media/js/main.js b/ui/media/js/main.js index ecd8ad73..d08d7c4a 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -1951,6 +1951,38 @@ resumeBtn.addEventListener("click", function() { document.body.classList.remove("wait-pause") }) +function tunnelUpdate(event) { + if ("cloudflare" in event) { + document.getElementById('cloudflare-off').classList.add("displayNone") + document.getElementById('cloudflare-on').classList.remove("displayNone") + document.getElementById('cloudflare-address').innerHTML = event.cloudflare + document.getElementById('toggle-cloudflare-tunnel').innerHTML = "Stop" + } else { + document.getElementById('cloudflare-on').classList.add("displayNone") + document.getElementById('cloudflare-off').classList.remove("displayNone") + document.getElementById('toggle-cloudflare-tunnel').innerHTML = "Start" + } +} + +document.getElementById('toggle-cloudflare-tunnel').addEventListener("click", async function() { + let command = "stop" + if (document.getElementById('toggle-cloudflare-tunnel').innerHTML == "Start") { + command = "start" + } + showToast(`Cloudflare tunnel ${command} initiated. Please wait.`) + + let res = await fetch("/tunnel/cloudflare/"+command, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({}), + }) + res = await res.json() + + console.log(`Cloudflare tunnel ${command} result:`, res) +}) + /* Pause function */ document.querySelectorAll(".tab").forEach(linkTabContents) diff --git a/ui/media/js/parameters.js b/ui/media/js/parameters.js index 4c7240eb..cab32cc8 100644 --- a/ui/media/js/parameters.js +++ b/ui/media/js/parameters.js @@ -11,6 +11,12 @@ var ParameterType = { custom: "custom", } +/** + * Element shortcuts + */ +let parametersTable = document.querySelector("#system-settings-table") +let networkParametersTable = document.querySelector("#system-settings-network-table") + /** * JSDoc style * @typedef {object} Parameter @@ -186,6 +192,7 @@ var PARAMETERS = [ icon: "fa-network-wired", default: true, saveInAppConfig: true, + table: networkParametersTable, }, { id: "listen_port", @@ -198,6 +205,7 @@ var PARAMETERS = [ return `` }, saveInAppConfig: true, + table: networkParametersTable, }, { id: "use_beta_channel", @@ -218,6 +226,21 @@ var PARAMETERS = [ default: false, saveInAppConfig: true, }, + { + id: "cloudflare", + type: ParameterType.custom, + label: "Cloudflare tunnel", + note: `Create a VPN tunnel to share your Easy Diffusion instance with your friends. This will + generate a web server address on the public Internet for your Easy Diffusion instance. +
    This Easy Diffusion server is available on the Internet using the + address:
    + Anyone knowing this address can access your server. The address of your server will change each time + you share a session.
    + Uses Cloudflare services.`, + icon: ["fa-brands", "fa-cloudflare"], + render: () => '', + table: networkParametersTable, + } ] function getParameterSettingsEntry(id) { @@ -266,7 +289,6 @@ function getParameterElement(parameter) { } } -let parametersTable = document.querySelector("#system-settings .parameters-table") /** * fill in the system settings popup table * @param {Array | undefined} parameters @@ -293,7 +315,10 @@ function initParameters(parameters) { noteElements.push(noteElement) } - const icon = parameter.icon ? [createElement("i", undefined, ["fa", parameter.icon])] : [] + if (typeof(parameter.icon) == "string") { + parameter.icon = [parameter.icon] + } + const icon = parameter.icon ? [createElement("i", undefined, ["fa", ...parameter.icon])] : [] const label = typeof parameter.label === "function" ? parameter.label(parameter) : parameter.label const labelElement = createElement("label", { for: parameter.id }) @@ -313,7 +338,13 @@ function initParameters(parameters) { elementWrapper, ] ) - parametersTable.appendChild(newrow) + + let p = parametersTable + if (parameter.table) { + p = parameter.table + } + p.appendChild(newrow) + parameter.settingsEntry = newrow }) } @@ -665,8 +696,17 @@ saveSettingsBtn.addEventListener("click", function() { }) const savePromise = changeAppConfig(updateAppConfigRequest) + showToast("Settings saved") saveSettingsBtn.classList.add("active") Promise.all([savePromise, asyncDelay(300)]).then(() => saveSettingsBtn.classList.remove("active")) }) +listenToNetworkField.addEventListener("change", debounce( ()=>{ + saveSettingsBtn.click() +}, 1000)) + +listenPortField.addEventListener("change", debounce( ()=>{ + saveSettingsBtn.click() +}, 1000)) + document.addEventListener("system_info_update", (e) => setDeviceInfo(e.detail)) From 9ce076eb0d0df21395a54f2d66538dec83fa9b1f Mon Sep 17 00:00:00 2001 From: JeLuF Date: Sun, 28 May 2023 01:18:39 +0200 Subject: [PATCH 062/123] Copy address button --- ui/media/css/main.css | 6 ++++++ ui/media/js/main.js | 2 +- ui/media/js/parameters.js | 10 +++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ui/media/css/main.css b/ui/media/css/main.css index 47a88601..cdb67703 100644 --- a/ui/media/css/main.css +++ b/ui/media/css/main.css @@ -1316,6 +1316,12 @@ body.wait-pause { border: var(--input-border-size) solid var(--input-border-color); margin-top: 0.2em; margin-bottom: 0.2em; + display: inline-block; +} + +#copy-cloudflare-address { + padding: 4px 8px; + margin-left: 0.5em; } /* TOAST NOTIFICATIONS */ diff --git a/ui/media/js/main.js b/ui/media/js/main.js index d08d7c4a..c3f0c016 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -1955,7 +1955,7 @@ function tunnelUpdate(event) { if ("cloudflare" in event) { document.getElementById('cloudflare-off').classList.add("displayNone") document.getElementById('cloudflare-on').classList.remove("displayNone") - document.getElementById('cloudflare-address').innerHTML = event.cloudflare + cloudflareAddressField.innerHTML = event.cloudflare document.getElementById('toggle-cloudflare-tunnel').innerHTML = "Stop" } else { document.getElementById('cloudflare-on').classList.add("displayNone") diff --git a/ui/media/js/parameters.js b/ui/media/js/parameters.js index cab32cc8..cb66383c 100644 --- a/ui/media/js/parameters.js +++ b/ui/media/js/parameters.js @@ -233,7 +233,7 @@ var PARAMETERS = [ note: `Create a VPN tunnel to share your Easy Diffusion instance with your friends. This will generate a web server address on the public Internet for your Easy Diffusion instance.
    This Easy Diffusion server is available on the Internet using the - address:
    + address:
    Anyone knowing this address can access your server. The address of your server will change each time you share a session.
    Uses Cloudflare services.`, @@ -709,4 +709,12 @@ listenPortField.addEventListener("change", debounce( ()=>{ saveSettingsBtn.click() }, 1000)) +let copyCloudflareAddressBtn = document.querySelector("#copy-cloudflare-address") +let cloudflareAddressField = document.getElementById("cloudflare-address") + +copyCloudflareAddressBtn.addEventListener("click", (e) => { + navigator.clipboard.writeText(cloudflareAddressField.innerHTML) + showToast("Copied server address to clipboard") +}) + document.addEventListener("system_info_update", (e) => setDeviceInfo(e.detail)) From 30dcc7477f12d22d2dc8b17b9c61fc80e3e56bc7 Mon Sep 17 00:00:00 2001 From: JeLuF Date: Sun, 28 May 2023 01:43:58 +0200 Subject: [PATCH 063/123] Fix GFPGAN settings import The word None which many txt metadata files contain as value for the GFPGAN field should not be considered to be a model name. If the value is None, disable the checkbox --- ui/media/js/dnd.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/ui/media/js/dnd.js b/ui/media/js/dnd.js index 8b66a3a4..f8fd8ccc 100644 --- a/ui/media/js/dnd.js +++ b/ui/media/js/dnd.js @@ -172,16 +172,22 @@ const TASK_MAPPING = { name: "Use Face Correction", setUI: (use_face_correction) => { const oldVal = gfpganModelField.value - gfpganModelField.value = getModelPath(use_face_correction, [".pth"]) - if (gfpganModelField.value) { - // Is a valid value for the field. - useFaceCorrectionField.checked = true - gfpganModelField.disabled = false - } else { - // Not a valid value, restore the old value and disable the filter. + console.log("use face correction", use_face_correction) + if (use_face_correction == null || use_face_correction == "None") { gfpganModelField.disabled = true - gfpganModelField.value = oldVal useFaceCorrectionField.checked = false + } else { + gfpganModelField.value = getModelPath(use_face_correction, [".pth"]) + if (gfpganModelField.value) { + // Is a valid value for the field. + useFaceCorrectionField.checked = true + gfpganModelField.disabled = false + } else { + // Not a valid value, restore the old value and disable the filter. + gfpganModelField.disabled = true + gfpganModelField.value = oldVal + useFaceCorrectionField.checked = false + } } //useFaceCorrectionField.checked = parseBoolean(use_face_correction) From 7202ffba6e9645cbbd4e668e475ca3bbfb1a7d41 Mon Sep 17 00:00:00 2001 From: JeLuF Date: Sun, 28 May 2023 02:36:56 +0200 Subject: [PATCH 064/123] Fix #1312 - invert model A and B ratio in merge --- ui/plugins/ui/merge.plugin.js | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/ui/plugins/ui/merge.plugin.js b/ui/plugins/ui/merge.plugin.js index 5ce97b2d..d3ddedbf 100644 --- a/ui/plugins/ui/merge.plugin.js +++ b/ui/plugins/ui/merge.plugin.js @@ -403,16 +403,19 @@ // Batch main loop for (let i = 0; i < iterations; i++) { let alpha = (start + i * step) / 100 - switch (document.querySelector("#merge-interpolation").value) { - case "SmoothStep": - alpha = smoothstep(alpha) - break - case "SmootherStep": - alpha = smootherstep(alpha) - break - case "SmoothestStep": - alpha = smootheststep(alpha) - break + + if (isTabActive(tabSettingsBatch)) { + switch (document.querySelector("#merge-interpolation").value) { + case "SmoothStep": + alpha = smoothstep(alpha) + break + case "SmootherStep": + alpha = smootherstep(alpha) + break + case "SmoothestStep": + alpha = smootheststep(alpha) + break + } } addLogMessage(`merging batch job ${i + 1}/${iterations}, alpha = ${alpha.toFixed(5)}...`) @@ -420,7 +423,8 @@ request["out_path"] += "-" + alpha.toFixed(5) + "." + document.querySelector("#merge-format").value addLogMessage(`  filename: ${request["out_path"]}`) - request["ratio"] = alpha + // sdkit documentation: "ratio - the ratio of the second model. 1 means only the second model will be used." + request["ratio"] = 1-alpha let res = await fetch("/model/merge", { method: "POST", headers: { "Content-Type": "application/json" }, From 7830ec7ca2b9d4715cd9d2cd9238d2d40f07d619 Mon Sep 17 00:00:00 2001 From: Olivia Godone-Maresca Date: Sun, 28 May 2023 14:39:36 -0400 Subject: [PATCH 065/123] Fix SyntaxWarning on startup Fixes ``` /ssd2/easydiffusion/ui/easydiffusion/utils/save_utils.py:222: SyntaxWarning: "is not" with a literal. Did you mean "!="? if task_data.use_upscale is not "latent_upscaler" and "latent_upscaler_steps" in metadata: ``` --- ui/easydiffusion/utils/save_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/easydiffusion/utils/save_utils.py b/ui/easydiffusion/utils/save_utils.py index 6a6f7239..ff2906a6 100644 --- a/ui/easydiffusion/utils/save_utils.py +++ b/ui/easydiffusion/utils/save_utils.py @@ -219,7 +219,7 @@ def get_printable_request(req: GenerateImageRequest, task_data: TaskData): del metadata["hypernetwork_strength"] if task_data.use_lora_model is None and "lora_alpha" in metadata: del metadata["lora_alpha"] - if task_data.use_upscale is not "latent_upscaler" and "latent_upscaler_steps" in metadata: + if task_data.use_upscale != "latent_upscaler" and "latent_upscaler_steps" in metadata: del metadata["latent_upscaler_steps"] app_config = app.getConfig() From 0860e35d17e15c3cf879b657fd5788b06192c6e4 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Thu, 1 Jun 2023 16:50:01 +0530 Subject: [PATCH 066/123] sdkit 1.0.101 - CodeFormer as an option to improve faces --- scripts/check_models.py | 4 ++++ scripts/check_modules.py | 2 +- ui/easydiffusion/model_manager.py | 20 +++++++++++++------- ui/easydiffusion/renderer.py | 3 +++ ui/easydiffusion/types.py | 3 ++- ui/index.html | 9 +++++++-- ui/media/css/main.css | 4 ++-- ui/media/js/main.js | 27 ++++++++++++++++++++++++--- ui/media/js/searchable-models.js | 13 ++++++++++++- 9 files changed, 68 insertions(+), 17 deletions(-) diff --git a/scripts/check_models.py b/scripts/check_models.py index 4b8d68c6..a2186727 100644 --- a/scripts/check_models.py +++ b/scripts/check_models.py @@ -24,6 +24,9 @@ models_to_check = { "vae": [ {"file_name": "vae-ft-mse-840000-ema-pruned.ckpt", "model_id": "vae-ft-mse-840000-ema-pruned"}, ], + "codeformer": [ + {"file_name": "codeformer.pth", "model_id": "codeformer-0.1.0"}, + ], } MODEL_EXTENSIONS = { # copied from easydiffusion/model_manager.py "stable-diffusion": [".ckpt", ".safetensors"], @@ -32,6 +35,7 @@ MODEL_EXTENSIONS = { # copied from easydiffusion/model_manager.py "gfpgan": [".pth"], "realesrgan": [".pth"], "lora": [".ckpt", ".safetensors"], + "codeformer": [".pth"], } diff --git a/scripts/check_modules.py b/scripts/check_modules.py index 3686ca00..416c3cc2 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.98", + "sdkit": "1.0.101", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", diff --git a/ui/easydiffusion/model_manager.py b/ui/easydiffusion/model_manager.py index 2a8b57fd..458dae7f 100644 --- a/ui/easydiffusion/model_manager.py +++ b/ui/easydiffusion/model_manager.py @@ -13,6 +13,7 @@ KNOWN_MODEL_TYPES = [ "gfpgan", "realesrgan", "lora", + "codeformer", ] MODEL_EXTENSIONS = { "stable-diffusion": [".ckpt", ".safetensors"], @@ -21,6 +22,7 @@ MODEL_EXTENSIONS = { "gfpgan": [".pth"], "realesrgan": [".pth"], "lora": [".ckpt", ".safetensors"], + "codeformer": [".pth"], } DEFAULT_MODELS = { "stable-diffusion": [ # needed to support the legacy installations @@ -133,6 +135,9 @@ def reload_models_if_necessary(context: Context, task_data: TaskData): if context.model_paths.get(model_type) != path } + if task_data.codeformer_upscale_faces and "realesrgan" not in models_to_reload.keys(): + models_to_reload["realesrgan"] = resolve_model_to_use(DEFAULT_MODELS["realesrgan"][0], "realesrgan") + if set_vram_optimizations(context) or set_clip_skip(context, task_data): # reload SD models_to_reload["stable-diffusion"] = model_paths_in_req["stable-diffusion"] @@ -159,7 +164,12 @@ def resolve_model_paths(task_data: TaskData): task_data.use_lora_model = resolve_model_to_use(task_data.use_lora_model, model_type="lora") if task_data.use_face_correction: - task_data.use_face_correction = resolve_model_to_use(task_data.use_face_correction, "gfpgan") + if "gfpgan" in task_data.use_face_correction.lower(): + model_type = "gfpgan" + elif "codeformer" in task_data.use_face_correction.lower(): + model_type = "codeformer" + + task_data.use_face_correction = resolve_model_to_use(task_data.use_face_correction, model_type) if task_data.use_upscale and "realesrgan" in task_data.use_upscale.lower(): task_data.use_upscale = resolve_model_to_use(task_data.use_upscale, "realesrgan") @@ -240,17 +250,12 @@ def is_malicious_model(file_path): def getModels(): models = { - "active": { - "stable-diffusion": "sd-v1-4", - "vae": "", - "hypernetwork": "", - "lora": "", - }, "options": { "stable-diffusion": ["sd-v1-4"], "vae": [], "hypernetwork": [], "lora": [], + "codeformer": [], }, } @@ -307,6 +312,7 @@ def getModels(): listModels(model_type="hypernetwork") listModels(model_type="gfpgan") listModels(model_type="lora") + listModels(model_type="codeformer") if models_scanned > 0: log.info(f"[green]Scanned {models_scanned} models. Nothing infected[/]") diff --git a/ui/easydiffusion/renderer.py b/ui/easydiffusion/renderer.py index 1ebd05ec..4be6e6bf 100644 --- a/ui/easydiffusion/renderer.py +++ b/ui/easydiffusion/renderer.py @@ -34,6 +34,7 @@ def init(device): context.temp_images = {} context.partial_x_samples = None context.model_load_errors = {} + context.enable_codeformer = True from easydiffusion import app @@ -162,6 +163,8 @@ def filter_images(req: GenerateImageRequest, task_data: TaskData, images: list, filters_to_apply.append("nsfw_checker") if task_data.use_face_correction and "codeformer" in task_data.use_face_correction.lower(): filters_to_apply.append("codeformer") + + filter_params["upscale_faces"] = task_data.codeformer_upscale_faces elif task_data.use_face_correction and "gfpgan" in task_data.use_face_correction.lower(): filters_to_apply.append("gfpgan") if task_data.use_upscale: diff --git a/ui/easydiffusion/types.py b/ui/easydiffusion/types.py index e4426714..4559a23a 100644 --- a/ui/easydiffusion/types.py +++ b/ui/easydiffusion/types.py @@ -23,7 +23,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 - tiling: str = "none" # "none", "x", "y", "xy" + tiling: str = "none" # "none", "x", "y", "xy" class TaskData(BaseModel): @@ -51,6 +51,7 @@ class TaskData(BaseModel): stream_image_progress: bool = False stream_image_progress_interval: int = 5 clip_skip: bool = False + codeformer_upscale_faces: bool = False class MergeRequest(BaseModel): diff --git a/ui/index.html b/ui/index.html index 21ec2550..4167a873 100644 --- a/ui/index.html +++ b/ui/index.html @@ -263,7 +263,12 @@
    • Render Settings
    • -
    • +
    • +
      +
      + +
      +
    • -
      +
    • diff --git a/ui/media/css/main.css b/ui/media/css/main.css index 8f4f49fa..e2d1f79a 100644 --- a/ui/media/css/main.css +++ b/ui/media/css/main.css @@ -1303,7 +1303,7 @@ body.wait-pause { display:none !important; } -#latent_upscaler_settings { +.sub-settings { padding-top: 3pt; padding-bottom: 3pt; padding-left: 5pt; @@ -1322,7 +1322,7 @@ body.wait-pause { box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); z-index: 9999; animation: slideInRight 0.5s ease forwards; - transition: bottom 0.5s ease; // Add a transition to smoothly reposition the toasts + transition: bottom 0.5s ease; /* Add a transition to smoothly reposition the toasts */ } .toast-notification-error { diff --git a/ui/media/js/main.js b/ui/media/js/main.js index 8628732b..ef27cf1b 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -87,7 +87,7 @@ let promptStrengthField = document.querySelector("#prompt_strength") let samplerField = document.querySelector("#sampler_name") let samplerSelectionContainer = document.querySelector("#samplerSelection") let useFaceCorrectionField = document.querySelector("#use_face_correction") -let gfpganModelField = new ModelDropdown(document.querySelector("#gfpgan_model"), "gfpgan") +let gfpganModelField = new ModelDropdown(document.querySelector("#gfpgan_model"), ["codeformer", "gfpgan"]) let useUpscalingField = document.querySelector("#use_upscale") let upscaleModelField = document.querySelector("#upscale_model") let upscaleAmountField = document.querySelector("#upscale_amount") @@ -270,7 +270,9 @@ function shiftOrConfirm(e, prompt, fn) { confirm( 'Tip: To skip this dialog, use shift-click or disable the "Confirm dangerous actions" setting in the Settings tab.', prompt, - () => { fn(e) } + () => { + fn(e) + } ) } } @@ -1261,6 +1263,10 @@ function getCurrentUserRequest() { } if (useFaceCorrectionField.checked) { newTask.reqBody.use_face_correction = gfpganModelField.value + + if (gfpganModelField.value.includes("codeformer")) { + newTask.reqBody.codeformer_upscale_faces = document.querySelector("#codeformer_upscale_faces").checked + } } if (useUpscalingField.checked) { newTask.reqBody.use_upscale = upscaleModelField.value @@ -1574,18 +1580,33 @@ metadataOutputFormatField.disabled = !saveToDiskField.checked gfpganModelField.disabled = !useFaceCorrectionField.checked useFaceCorrectionField.addEventListener("change", function(e) { gfpganModelField.disabled = !this.checked + + onFixFaceModelChange() }) +function onFixFaceModelChange() { + let codeformerSettings = document.querySelector("#codeformer_settings") + if (gfpganModelField.value === "codeformer" && !gfpganModelField.disabled) { + codeformerSettings.classList.remove("displayNone") + } else { + codeformerSettings.classList.add("displayNone") + } +} +gfpganModelField.addEventListener("change", onFixFaceModelChange) +onFixFaceModelChange() + upscaleModelField.disabled = !useUpscalingField.checked upscaleAmountField.disabled = !useUpscalingField.checked useUpscalingField.addEventListener("change", function(e) { upscaleModelField.disabled = !this.checked upscaleAmountField.disabled = !this.checked + + onUpscaleModelChange() }) function onUpscaleModelChange() { let upscale4x = document.querySelector("#upscale_amount_4x") - if (upscaleModelField.value === "latent_upscaler") { + if (upscaleModelField.value === "latent_upscaler" && !upscaleModelField.disabled) { upscale4x.disabled = true upscaleAmountField.value = "2" latentUpscalerSettings.classList.remove("displayNone") diff --git a/ui/media/js/searchable-models.js b/ui/media/js/searchable-models.js index 9a723d15..f0d06b80 100644 --- a/ui/media/js/searchable-models.js +++ b/ui/media/js/searchable-models.js @@ -90,7 +90,12 @@ class ModelDropdown { if (modelsOptions !== undefined) { // reuse models from cache (only useful for plugins, which are loaded after models) - this.inputModels = modelsOptions[this.modelKey] + this.inputModels = [] + let modelKeys = Array.isArray(this.modelKey) ? this.modelKey : [this.modelKey] + for (let i = 0; i < modelKeys.length; i++) { + let key = modelKeys[i] + this.inputModels.push(...modelsOptions[key]) + } this.populateModels() } document.addEventListener( @@ -98,6 +103,12 @@ class ModelDropdown { this.bind(function(e) { // reload the models this.inputModels = modelsOptions[this.modelKey] + this.inputModels = [] + let modelKeys = Array.isArray(this.modelKey) ? this.modelKey : [this.modelKey] + for (let i = 0; i < modelKeys.length; i++) { + let key = modelKeys[i] + this.inputModels.push(...modelsOptions[key]) + } this.populateModels() }, this) ) From dd95df8f022a51bb8e5b097b94fca34e9fd5105a Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Fri, 2 Jun 2023 16:34:29 +0530 Subject: [PATCH 067/123] Refactor the default model download code, remove check_models.py, don't check in legacy paths since that's already migrated during initialization; Download CodeFormer's model only when it's used for the first time --- scripts/check_models.py | 105 -------------------------- scripts/on_sd_start.bat | 7 -- scripts/on_sd_start.sh | 6 -- ui/easydiffusion/app.py | 45 +++++++++-- ui/easydiffusion/model_manager.py | 120 +++++++++++++++++++++--------- 5 files changed, 121 insertions(+), 162 deletions(-) delete mode 100644 scripts/check_models.py diff --git a/scripts/check_models.py b/scripts/check_models.py deleted file mode 100644 index a2186727..00000000 --- a/scripts/check_models.py +++ /dev/null @@ -1,105 +0,0 @@ -# this script runs inside the legacy "stable-diffusion" folder - -from sdkit.models import download_model, get_model_info_from_db -from sdkit.utils import hash_file_quick - -import os -import shutil -from glob import glob -import traceback - -models_base_dir = os.path.abspath(os.path.join("..", "models")) - -models_to_check = { - "stable-diffusion": [ - {"file_name": "sd-v1-4.ckpt", "model_id": "1.4"}, - ], - "gfpgan": [ - {"file_name": "GFPGANv1.4.pth", "model_id": "1.4"}, - ], - "realesrgan": [ - {"file_name": "RealESRGAN_x4plus.pth", "model_id": "x4plus"}, - {"file_name": "RealESRGAN_x4plus_anime_6B.pth", "model_id": "x4plus_anime_6"}, - ], - "vae": [ - {"file_name": "vae-ft-mse-840000-ema-pruned.ckpt", "model_id": "vae-ft-mse-840000-ema-pruned"}, - ], - "codeformer": [ - {"file_name": "codeformer.pth", "model_id": "codeformer-0.1.0"}, - ], -} -MODEL_EXTENSIONS = { # copied from easydiffusion/model_manager.py - "stable-diffusion": [".ckpt", ".safetensors"], - "vae": [".vae.pt", ".ckpt", ".safetensors"], - "hypernetwork": [".pt", ".safetensors"], - "gfpgan": [".pth"], - "realesrgan": [".pth"], - "lora": [".ckpt", ".safetensors"], - "codeformer": [".pth"], -} - - -def download_if_necessary(model_type: str, file_name: str, model_id: str): - model_path = os.path.join(models_base_dir, model_type, file_name) - expected_hash = get_model_info_from_db(model_type=model_type, model_id=model_id)["quick_hash"] - - other_models_exist = any_model_exists(model_type) - known_model_exists = os.path.exists(model_path) - known_model_is_corrupt = known_model_exists and hash_file_quick(model_path) != expected_hash - - if known_model_is_corrupt or (not other_models_exist and not known_model_exists): - print("> download", model_type, model_id) - download_model(model_type, model_id, download_base_dir=models_base_dir) - - -def init(): - migrate_legacy_model_location() - - for model_type, models in models_to_check.items(): - for model in models: - try: - download_if_necessary(model_type, model["file_name"], model["model_id"]) - except: - traceback.print_exc() - fail(model_type) - - print(model_type, "model(s) found.") - - -### utilities -def any_model_exists(model_type: str) -> bool: - extensions = MODEL_EXTENSIONS.get(model_type, []) - for ext in extensions: - if any(glob(f"{models_base_dir}/{model_type}/**/*{ext}", recursive=True)): - return True - - return False - - -def migrate_legacy_model_location(): - 'Move the models inside the legacy "stable-diffusion" folder, to their respective folders' - - for model_type, models in models_to_check.items(): - for model in models: - file_name = model["file_name"] - if os.path.exists(file_name): - dest_dir = os.path.join(models_base_dir, model_type) - os.makedirs(dest_dir, exist_ok=True) - shutil.move(file_name, os.path.join(dest_dir, file_name)) - - -def fail(model_name): - print( - f"""Error downloading the {model_name} model. Sorry about that, please try to: -1. Run this installer again. -2. If that doesn't fix it, please try to download the file manually. The address to download from, and the destination to save to are printed above this message. -3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB -4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues -Thanks!""" - ) - exit(1) - - -### start - -init() diff --git a/scripts/on_sd_start.bat b/scripts/on_sd_start.bat index ba205c9e..d2ef7321 100644 --- a/scripts/on_sd_start.bat +++ b/scripts/on_sd_start.bat @@ -79,13 +79,6 @@ call WHERE uvicorn > .tmp @echo conda_sd_ui_deps_installed >> ..\scripts\install_status.txt ) -@rem Download the required models -call python ..\scripts\check_models.py -if "%ERRORLEVEL%" NEQ "0" ( - pause - exit /b -) - @>nul findstr /m "sd_install_complete" ..\scripts\install_status.txt @if "%ERRORLEVEL%" NEQ "0" ( @echo sd_weights_downloaded >> ..\scripts\install_status.txt diff --git a/scripts/on_sd_start.sh b/scripts/on_sd_start.sh index 820c36ed..55f4da25 100755 --- a/scripts/on_sd_start.sh +++ b/scripts/on_sd_start.sh @@ -51,12 +51,6 @@ if ! command -v uvicorn &> /dev/null; then fail "UI packages not found!" fi -# Download the required models -if ! python ../scripts/check_models.py; then - read -p "Press any key to continue" - exit 1 -fi - if [ `grep -c sd_install_complete ../scripts/install_status.txt` -gt "0" ]; then echo sd_weights_downloaded >> ../scripts/install_status.txt echo sd_install_complete >> ../scripts/install_status.txt diff --git a/ui/easydiffusion/app.py b/ui/easydiffusion/app.py index 3064e151..38e3392c 100644 --- a/ui/easydiffusion/app.py +++ b/ui/easydiffusion/app.py @@ -90,8 +90,8 @@ def init(): os.makedirs(USER_SERVER_PLUGINS_DIR, exist_ok=True) # https://pytorch.org/docs/stable/storage.html - warnings.filterwarnings('ignore', category=UserWarning, message='TypedStorage is deprecated') - + warnings.filterwarnings("ignore", category=UserWarning, message="TypedStorage is deprecated") + load_server_plugins() update_render_threads() @@ -221,12 +221,41 @@ def open_browser(): webbrowser.open(f"http://localhost:{port}") - Console().print(Panel( - "\n" + - "[white]Easy Diffusion is ready to serve requests.\n\n" + - "A new browser tab should have been opened by now.\n" + - f"If not, please open your web browser and navigate to [bold yellow underline]http://localhost:{port}/\n", - title="Easy Diffusion is ready", style="bold yellow on blue")) + Console().print( + Panel( + "\n" + + "[white]Easy Diffusion is ready to serve requests.\n\n" + + "A new browser tab should have been opened by now.\n" + + f"If not, please open your web browser and navigate to [bold yellow underline]http://localhost:{port}/\n", + title="Easy Diffusion is ready", + style="bold yellow on blue", + ) + ) + + +def fail_and_die(fail_type: str, data: str): + suggestions = [ + "Run this installer again.", + "If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB", + "If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues", + ] + + if fail_type == "model_download": + fail_label = f"Error downloading the {data} model" + suggestions.insert( + 1, + "If that doesn't fix it, please try to download the file manually. The address to download from, and the destination to save to are printed above this message.", + ) + else: + fail_label = "Error while installing Easy Diffusion" + + msg = [f"{fail_label}. Sorry about that, please try to:"] + for i, suggestion in enumerate(suggestions): + msg.append(f"{i+1}. {suggestion}") + msg.append("Thanks!") + + print("\n".join(msg)) + exit(1) def get_image_modifiers(): diff --git a/ui/easydiffusion/model_manager.py b/ui/easydiffusion/model_manager.py index 458dae7f..c4447033 100644 --- a/ui/easydiffusion/model_manager.py +++ b/ui/easydiffusion/model_manager.py @@ -1,10 +1,14 @@ import os +import shutil +from glob import glob +import traceback from easydiffusion import app from easydiffusion.types import TaskData from easydiffusion.utils import log from sdkit import Context -from sdkit.models import load_model, scan_model, unload_model +from sdkit.models import load_model, scan_model, unload_model, download_model, get_model_info_from_db +from sdkit.utils import hash_file_quick KNOWN_MODEL_TYPES = [ "stable-diffusion", @@ -25,12 +29,19 @@ MODEL_EXTENSIONS = { "codeformer": [".pth"], } DEFAULT_MODELS = { - "stable-diffusion": [ # needed to support the legacy installations - "custom-model", # only one custom model file was supported initially, creatively named 'custom-model' - "sd-v1-4", # Default fallback. + "stable-diffusion": [ + {"file_name": "sd-v1-4.ckpt", "model_id": "1.4"}, + ], + "gfpgan": [ + {"file_name": "GFPGANv1.4.pth", "model_id": "1.4"}, + ], + "realesrgan": [ + {"file_name": "RealESRGAN_x4plus.pth", "model_id": "x4plus"}, + {"file_name": "RealESRGAN_x4plus_anime_6B.pth", "model_id": "x4plus_anime_6"}, + ], + "vae": [ + {"file_name": "vae-ft-mse-840000-ema-pruned.ckpt", "model_id": "vae-ft-mse-840000-ema-pruned"}, ], - "gfpgan": ["GFPGANv1.3"], - "realesrgan": ["RealESRGAN_x4plus"], } MODELS_TO_LOAD_ON_START = ["stable-diffusion", "vae", "hypernetwork", "lora"] @@ -39,6 +50,8 @@ known_models = {} def init(): make_model_folders() + migrate_legacy_model_location() # if necessary + download_default_models_if_necessary() getModels() # run this once, to cache the picklescan results @@ -77,7 +90,7 @@ def resolve_model_to_use(model_name: str = None, model_type: str = None): default_models = DEFAULT_MODELS.get(model_type, []) config = app.getConfig() - model_dirs = [os.path.join(app.MODELS_DIR, model_type), app.SD_DIR] + model_dir = os.path.join(app.MODELS_DIR, model_type) if not model_name: # When None try user configured model. # config = getConfig() if "model" in config and model_type in config["model"]: @@ -85,31 +98,25 @@ def resolve_model_to_use(model_name: str = None, model_type: str = None): if model_name: # Check models directory - models_dir_path = os.path.join(app.MODELS_DIR, model_type, model_name) + model_path = os.path.join(model_dir, model_name) + if os.path.exists(model_path): + return model_path for model_extension in model_extensions: - if os.path.exists(models_dir_path + model_extension): - return models_dir_path + model_extension + if os.path.exists(model_path + model_extension): + return model_path + model_extension if os.path.exists(model_name + model_extension): return os.path.abspath(model_name + model_extension) - # Default locations - if model_name in default_models: - default_model_path = os.path.join(app.SD_DIR, model_name) - for model_extension in model_extensions: - if os.path.exists(default_model_path + model_extension): - return default_model_path + model_extension - # Can't find requested model, check the default paths. - for default_model in default_models: - for model_dir in model_dirs: - default_model_path = os.path.join(model_dir, default_model) - for model_extension in model_extensions: - if os.path.exists(default_model_path + model_extension): - if model_name is not None: - log.warn( - f"Could not find the configured custom model {model_name}{model_extension}. Using the default one: {default_model_path}{model_extension}" - ) - return default_model_path + model_extension + if model_type == "stable-diffusion": + for default_model in default_models: + default_model_path = os.path.join(model_dir, default_model["file_name"]) + if os.path.exists(default_model_path): + if model_name is not None: + log.warn( + f"Could not find the configured custom model {model_name}. Using the default one: {default_model_path}" + ) + return default_model_path return None @@ -136,7 +143,9 @@ def reload_models_if_necessary(context: Context, task_data: TaskData): } if task_data.codeformer_upscale_faces and "realesrgan" not in models_to_reload.keys(): - models_to_reload["realesrgan"] = resolve_model_to_use(DEFAULT_MODELS["realesrgan"][0], "realesrgan") + models_to_reload["realesrgan"] = resolve_model_to_use( + DEFAULT_MODELS["realesrgan"][0]["file_name"], "realesrgan" + ) if set_vram_optimizations(context) or set_clip_skip(context, task_data): # reload SD models_to_reload["stable-diffusion"] = model_paths_in_req["stable-diffusion"] @@ -168,6 +177,7 @@ def resolve_model_paths(task_data: TaskData): model_type = "gfpgan" elif "codeformer" in task_data.use_face_correction.lower(): model_type = "codeformer" + download_if_necessary("codeformer", "codeformer.pth", "codeformer-0.1.0") task_data.use_face_correction = resolve_model_to_use(task_data.use_face_correction, model_type) if task_data.use_upscale and "realesrgan" in task_data.use_upscale.lower(): @@ -179,7 +189,31 @@ def fail_if_models_did_not_load(context: Context): if model_type in context.model_load_errors: e = context.model_load_errors[model_type] raise Exception(f"Could not load the {model_type} model! Reason: " + e) - # concat 'e', don't use in format string (injection attack) + + +def download_default_models_if_necessary(): + for model_type, models in DEFAULT_MODELS.items(): + for model in models: + try: + download_if_necessary(model_type, model["file_name"], model["model_id"]) + except: + traceback.print_exc() + app.fail_and_die(fail_type="model_download", data=model_type) + + print(model_type, "model(s) found.") + + +def download_if_necessary(model_type: str, file_name: str, model_id: str): + model_path = os.path.join(app.MODELS_DIR, model_type, file_name) + expected_hash = get_model_info_from_db(model_type=model_type, model_id=model_id)["quick_hash"] + + other_models_exist = any_model_exists(model_type) + known_model_exists = os.path.exists(model_path) + known_model_is_corrupt = known_model_exists and hash_file_quick(model_path) != expected_hash + + if known_model_is_corrupt or (not other_models_exist and not known_model_exists): + print("> download", model_type, model_id) + download_model(model_type, model_id, download_base_dir=app.MODELS_DIR) def set_vram_optimizations(context: Context): @@ -193,6 +227,26 @@ def set_vram_optimizations(context: Context): return False +def migrate_legacy_model_location(): + 'Move the models inside the legacy "stable-diffusion" folder, to their respective folders' + + for model_type, models in DEFAULT_MODELS.items(): + for model in models: + file_name = model["file_name"] + legacy_path = os.path.join(app.SD_DIR, file_name) + if os.path.exists(legacy_path): + shutil.move(legacy_path, os.path.join(app.MODELS_DIR, model_type, file_name)) + + +def any_model_exists(model_type: str) -> bool: + extensions = MODEL_EXTENSIONS.get(model_type, []) + for ext in extensions: + if any(glob(f"{app.MODELS_DIR}/{model_type}/**/*{ext}", recursive=True)): + return True + + return False + + def set_clip_skip(context: Context, task_data: TaskData): clip_skip = task_data.clip_skip @@ -255,7 +309,7 @@ def getModels(): "vae": [], "hypernetwork": [], "lora": [], - "codeformer": [], + "codeformer": ["codeformer"], }, } @@ -312,14 +366,8 @@ def getModels(): listModels(model_type="hypernetwork") listModels(model_type="gfpgan") listModels(model_type="lora") - listModels(model_type="codeformer") if models_scanned > 0: log.info(f"[green]Scanned {models_scanned} models. Nothing infected[/]") - # legacy - custom_weight_path = os.path.join(app.SD_DIR, "custom-model.ckpt") - if os.path.exists(custom_weight_path): - models["options"]["stable-diffusion"].append("custom-model") - return models From 51d52d3a0795d59986420db5e40e512d9508dd1c Mon Sep 17 00:00:00 2001 From: JeLuF Date: Fri, 2 Jun 2023 23:41:53 +0200 Subject: [PATCH 068/123] Tiled image download plugin --- ui/plugins/ui/tiled-image-download.plugin.js | 325 +++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 ui/plugins/ui/tiled-image-download.plugin.js diff --git a/ui/plugins/ui/tiled-image-download.plugin.js b/ui/plugins/ui/tiled-image-download.plugin.js new file mode 100644 index 00000000..aaceab46 --- /dev/null +++ b/ui/plugins/ui/tiled-image-download.plugin.js @@ -0,0 +1,325 @@ +;(function(){ + "use strict"; + const PAPERSIZE = [ + {id: "a3p", width: 297, height: 420, unit: "mm"}, + {id: "a3l", width: 420, height: 297, unit: "mm"}, + {id: "a4p", width: 210, height: 297, unit: "mm"}, + {id: "a4l", width: 297, height: 210, unit: "mm"}, + {id: "ll", width: 279, height: 216, unit: "mm"}, + {id: "lp", width: 216, height: 279, unit: "mm"}, + {id: "hd", width: 1920, height: 1080, unit: "pixels"}, + {id: "4k", width: 3840, height: 2160, unit: "pixels"}, + ] + + // ---- Register plugin + PLUGINS['IMAGE_INFO_BUTTONS'].push({ + html: ' Download tiled image', + on_click: onDownloadTiledImage, + filter: (req, img) => req.tiling != "none", + }) + + var thisImage + + function onDownloadTiledImage(req, img) { + document.getElementById("download-tiled-image-dialog").showModal() + thisImage = new Image() + thisImage.src = img.src + thisImage.dataset["prompt"] = img.dataset["prompt"] + } + + // ---- Add HTML + document.getElementById('container').lastElementChild.insertAdjacentHTML("afterend", + ` +

      Download tiled image

      +
      +
      +
      + + Number of tiles + + + Image dimensions + +
      +
      +
      +
      + + +
      +
      +
      +
      +
      + + + +
      +
      + +
      +
      + Some standard sizes:
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      +
      + + Tile placement + +
      +
      +
      +
      + +
      + +
      + +
      +
      +
      +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      `) + + let downloadTiledImageDialog = document.getElementById("download-tiled-image-dialog") + let dtim1_width = document.getElementById("dtim1-width") + let dtim1_height = document.getElementById("dtim1-height") + let dtim2_width = document.getElementById("dtim2-width") + let dtim2_height = document.getElementById("dtim2-height") + let dtim2_unit = document.getElementById("dtim2-unit") + let dtim2_dpi = document.getElementById("dtim2-dpi") + let tabTiledTilesOptions = document.getElementById("tab-image-tiles") + let tabTiledSizeOptions = document.getElementById("tab-image-size") + + linkTabContents(tabTiledTilesOptions) + linkTabContents(tabTiledSizeOptions) + + prettifyInputs(downloadTiledImageDialog) + + // ---- Predefined image dimensions + PAPERSIZE.forEach( function(p) { + document.getElementById("dtim2-" + p.id).addEventListener("click", (e) => { + dtim2_unit.value = p.unit + dtim2_width.value = p.width + dtim2_height.value = p.height + }) + }) + + // ---- Close popup + document.getElementById("dti-cancel").addEventListener("click", (e) => downloadTiledImageDialog.close()) + downloadTiledImageDialog.addEventListener('click', function (event) { + var rect = downloadTiledImageDialog.getBoundingClientRect(); + var isInDialog=(rect.top <= event.clientY && event.clientY <= rect.top + rect.height + && rect.left <= event.clientX && event.clientX <= rect.left + rect.width); + if (!isInDialog) { + downloadTiledImageDialog.close(); + } + }); + + // ---- Stylesheet + const styleSheet = document.createElement("style") + styleSheet.textContent = ` + dialog { + background: var(--background-color2); + color: var(--text-color); + border-radius: 7px; + border: 1px solid var(--background-color3); + } + + dialog::backdrop { + background: rgba(0, 0, 0, 0.5); + } + + + button[disabled] { + opacity: 0.5; + } + + .method-2-dpi { + margin-top: 1em; + margin-bottom: 1em; + } + + .method-2-paper button { + width: 10em; + padding: 4px; + margin: 4px; + } + + .download-tiled-image .tab-content { + background: var(--background-color1); + border-radius: 3pt; + } + + .dtim-container { display: grid; + grid-template-columns: auto auto; + grid-template-rows: auto auto; + gap: 1em 0px; + grid-auto-flow: row; + grid-template-areas: + "dtim-tab dtim-tab dtim-plc" + "dtim-ok dtim-newtab dtim-cancel"; + } + + .download-tiled-image-top { + justify-self: center; + grid-area: dtim-tab; + } + + .download-tiled-image-placement { + justify-self: center; + grid-area: dtim-plc; + margin-left: 1em; + } + + .dtim-ok { + justify-self: center; + align-self: start; + grid-area: dtim-ok; + } + + .dtim-newtab { + justify-self: center; + align-self: start; + grid-area: dtim-newtab; + } + + .dtim-cancel { + justify-self: center; + align-self: start; + grid-area: dtim-cancel; + } + + #tab-content-image-placement img { + margin: 4px; + opacity: 0.3; + border: solid 2px var(--background-color1); + } + + #tab-content-image-placement img:hover { + margin: 4px; + opacity: 1; + border: solid 2px var(--accent-color); + filter: brightness(2); + } + + #tab-content-image-placement img.active { + margin: 4px; + opacity: 1; + border: solid 2px var(--background-color1); + } + + ` + document.head.appendChild(styleSheet) + + // ---- Placement widget + + function updatePlacementWidget(event) { + document.querySelector("#tab-content-image-placement img.active").classList.remove("active") + event.target.classList.add("active") + } + + document.querySelectorAll("#tab-content-image-placement img").forEach( + (i) => i.addEventListener("click", updatePlacementWidget) + ) + + function getPlacement() { + return document.querySelector("#tab-content-image-placement img.active").id.substr(5) + } + + // ---- Make the image + function downloadTiledImage(image, width, height, offsetX=0, offsetY=0, new_tab=false) { + + const canvas = document.createElement('canvas') + canvas.width = width + canvas.height = height + const context = canvas.getContext('2d') + + const w = image.width + const h = image.height + + for (var x = offsetX; x < width; x += w) { + for (var y = offsetY; y < height; y += h) { + context.drawImage(image, x, y, w, h) + } + } + if (new_tab) { + var newTab = window.open("") + newTab.document.write(`${width}×${height}, "${image.dataset["prompt"]}"`) + } else { + const link = document.createElement('a') + link.href = canvas.toDataURL() + link.download = image.dataset["prompt"].replace(/[^a-zA-Z0-9]+/g, "-").substr(0,22)+crypto.randomUUID()+".png" + link.click() + } + } + + function onDownloadTiledImageClick(e, newtab=false) { + var width, height, offsetX, offsetY + + if (isTabActive(tabTiledTilesOptions)) { + width = thisImage.width * dtim1_width.value + height = thisImage.height * dtim1_height.value + } else { + if ( dtim2_unit.value == "pixels" ) { + width = dtim2_width.value + height= dtim2_height.value + } else if ( dtim2_unit.value == "mm" ) { + width = Math.floor( dtim2_width.value * dtim2_dpi.value / 25.4 ) + height = Math.floor( dtim2_height.value * dtim2_dpi.value / 25.4 ) + } else { // inch + width = Math.floor( dtim2_width.value * dtim2_dpi.value ) + height = Math.floor( dtim2_height.value * dtim2_dpi.value ) + } + } + + var placement = getPlacement() + if (placement == "1tl") { + offsetX = 0 + offsetY = 0 + } else if (placement == "1tr") { + offsetX = width - thisImage.width * Math.ceil( width / thisImage.width ) + offsetY = 0 + } else if (placement == "1bl") { + offsetX = 0 + offsetY = height - thisImage.height * Math.ceil( height / thisImage.height ) + } else if (placement == "1br") { + offsetX = width - thisImage.width * Math.ceil( width / thisImage.width ) + offsetY = height - thisImage.height * Math.ceil( height / thisImage.height ) + } else if (placement == "4center") { + offsetX = width/2 - thisImage.width * Math.ceil( width/2 / thisImage.width ) + offsetY = height/2 - thisImage.height * Math.ceil( height/2 / thisImage.height ) + } else if (placement == "1center") { + offsetX = width/2 - thisImage.width/2 - thisImage.width * Math.ceil( (width/2 - thisImage.width/2) / thisImage.width ) + offsetY = height/2 - thisImage.height/2 - thisImage.height * Math.ceil( (height/2 - thisImage.height/2) / thisImage.height ) + } + downloadTiledImage(thisImage, width, height, offsetX, offsetY, newtab) + } + + document.getElementById("dti-ok").addEventListener("click", onDownloadTiledImageClick) + document.getElementById("dti-newtab").addEventListener("click", (e) => onDownloadTiledImageClick(e,true)) + +})() From 6dcf7539bb9b92bc70c0d3af85bd4fc7282e30bb Mon Sep 17 00:00:00 2001 From: JeLuF Date: Sat, 3 Jun 2023 00:04:13 +0200 Subject: [PATCH 069/123] close window --- ui/plugins/ui/tiled-image-download.plugin.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/plugins/ui/tiled-image-download.plugin.js b/ui/plugins/ui/tiled-image-download.plugin.js index aaceab46..0fe00c2e 100644 --- a/ui/plugins/ui/tiled-image-download.plugin.js +++ b/ui/plugins/ui/tiled-image-download.plugin.js @@ -317,6 +317,7 @@ offsetY = height/2 - thisImage.height/2 - thisImage.height * Math.ceil( (height/2 - thisImage.height/2) / thisImage.height ) } downloadTiledImage(thisImage, width, height, offsetX, offsetY, newtab) + downloadTiledImageDialog.close() } document.getElementById("dti-ok").addEventListener("click", onDownloadTiledImageClick) From 1d5309decbfb2a2f2cac491eae53ccc32c179463 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Sat, 3 Jun 2023 10:02:34 +0530 Subject: [PATCH 070/123] changelog --- CHANGES.md | 1 + ui/index.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 2e45c279..88ded3b5 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.40 - 3 Jun 2023 - Added CodeFormer as another option for fixing faces and eyes. CodeFormer tends to perform better than GFPGAN for many images. Thanks @patriceac for the implementation, and for contacting the CodeFormer team (who were supportive of it being integrated into Easy Diffusion). * 2.5.39 - 25 May 2023 - (beta-only) Seamless Tiling - make seamlessly tiled images, e.g. rock and grass textures. Thanks @JeLuf. * 2.5.38 - 24 May 2023 - Better reporting of errors, and show an explanation if the user cannot disable the "Use CPU" setting. * 2.5.38 - 23 May 2023 - Add Latent Upscaler as another option for upscaling images. Thanks @JeLuf for the implementation of the Latent Upscaler model. diff --git a/ui/index.html b/ui/index.html index 4167a873..eaa007f6 100644 --- a/ui/index.html +++ b/ui/index.html @@ -30,7 +30,7 @@

      Easy Diffusion - v2.5.39 + v2.5.40

    From 6ca7247c027327552e05f8e27423c3e72495caa8 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Sat, 3 Jun 2023 10:11:03 +0530 Subject: [PATCH 071/123] Enable face upscaling by default --- ui/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/index.html b/ui/index.html index eaa007f6..88917b68 100644 --- a/ui/index.html +++ b/ui/index.html @@ -266,7 +266,7 @@
  • - +
  • From 401fc30617302c347ad5dba1413a212d55bdd0e4 Mon Sep 17 00:00:00 2001 From: Olivia Godone-Maresca Date: Sat, 3 Jun 2023 14:54:17 -0400 Subject: [PATCH 072/123] Allow LoRA strengths between -2 and 2 --- ui/index.html | 2 +- ui/media/js/main.js | 8 ++++---- ui/media/js/utils.js | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ui/index.html b/ui/index.html index 88917b68..6cc6978c 100644 --- a/ui/index.html +++ b/ui/index.html @@ -227,7 +227,7 @@ -
    +
    diff --git a/ui/media/js/main.js b/ui/media/js/main.js index ef27cf1b..e4043fa0 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -1725,10 +1725,10 @@ function updateLoraAlpha() { } function updateLoraAlphaSlider() { - if (loraAlphaField.value < 0) { - loraAlphaField.value = 0 - } else if (loraAlphaField.value > 1) { - loraAlphaField.value = 1 + if (loraAlphaField.value < -2) { + loraAlphaField.value = -2 + } else if (loraAlphaField.value > 2) { + loraAlphaField.value = 2 } loraAlphaSlider.value = loraAlphaField.value * 100 diff --git a/ui/media/js/utils.js b/ui/media/js/utils.js index 6ddb0ae6..871ba714 100644 --- a/ui/media/js/utils.js +++ b/ui/media/js/utils.js @@ -402,12 +402,12 @@ function debounce(func, wait, immediate) { function preventNonNumericalInput(e) { e = e || window.event - let charCode = typeof e.which == "undefined" ? e.keyCode : e.which - let charStr = String.fromCharCode(charCode) - let re = e.target.getAttribute("pattern") || "^[0-9]+$" - re = new RegExp(re) + const charCode = typeof e.which == "undefined" ? e.keyCode : e.which + const charStr = String.fromCharCode(charCode) + const newInputValue = `${e.target.value}${charStr}` + const re = new RegExp(e.target.getAttribute("pattern") || "^[0-9]+$") - if (!charStr.match(re)) { + if (!re.test(charStr) && !re.test(newInputValue)) { e.preventDefault() } } From 8a2c09c6de4a6a421472146f6609463b5ef6e219 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 5 Jun 2023 09:00:50 +0530 Subject: [PATCH 073/123] Fix for rabbit hole plugin --- ui/media/js/searchable-models.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ui/media/js/searchable-models.js b/ui/media/js/searchable-models.js index f0d06b80..855cfc61 100644 --- a/ui/media/js/searchable-models.js +++ b/ui/media/js/searchable-models.js @@ -94,7 +94,8 @@ class ModelDropdown { let modelKeys = Array.isArray(this.modelKey) ? this.modelKey : [this.modelKey] for (let i = 0; i < modelKeys.length; i++) { let key = modelKeys[i] - this.inputModels.push(...modelsOptions[key]) + let k = Array.isArray(modelsOptions[key]) ? modelsOptions[key] : [modelsOptions[key]] + this.inputModels.push(...k) } this.populateModels() } @@ -107,7 +108,8 @@ class ModelDropdown { let modelKeys = Array.isArray(this.modelKey) ? this.modelKey : [this.modelKey] for (let i = 0; i < modelKeys.length; i++) { let key = modelKeys[i] - this.inputModels.push(...modelsOptions[key]) + let k = Array.isArray(modelsOptions[key]) ? modelsOptions[key] : [modelsOptions[key]] + this.inputModels.push(...k) } this.populateModels() }, this) From a10aa92634f5743319a7ad1e2faf3f68c875fdf8 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 5 Jun 2023 15:08:57 +0530 Subject: [PATCH 074/123] Fix a bug where the realesrgan model would get unloaded after the first request in a batch while using Codeformer with upscaling of faces --- scripts/check_modules.py | 2 +- ui/easydiffusion/model_manager.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index 416c3cc2..cbd6d0c1 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.101", + "sdkit": "1.0.102", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", diff --git a/ui/easydiffusion/model_manager.py b/ui/easydiffusion/model_manager.py index c4447033..29cf529b 100644 --- a/ui/easydiffusion/model_manager.py +++ b/ui/easydiffusion/model_manager.py @@ -142,10 +142,12 @@ def reload_models_if_necessary(context: Context, task_data: TaskData): if context.model_paths.get(model_type) != path } - if task_data.codeformer_upscale_faces and "realesrgan" not in models_to_reload.keys(): - models_to_reload["realesrgan"] = resolve_model_to_use( - DEFAULT_MODELS["realesrgan"][0]["file_name"], "realesrgan" - ) + if task_data.codeformer_upscale_faces: + if "realesrgan" not in models_to_reload and "realesrgan" not in context.models: + default_realesrgan = DEFAULT_MODELS["realesrgan"][0]["file_name"] + models_to_reload["realesrgan"] = resolve_model_to_use(default_realesrgan, "realesrgan") + elif "realesrgan" in models_to_reload and models_to_reload["realesrgan"] is None: + del models_to_reload["realesrgan"] # don't unload realesrgan if set_vram_optimizations(context) or set_clip_skip(context, task_data): # reload SD models_to_reload["stable-diffusion"] = model_paths_in_req["stable-diffusion"] From c72b287c823c573e6361f040f733ec3f6c055bf3 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 5 Jun 2023 15:22:37 +0530 Subject: [PATCH 075/123] Show a more helpful error message in the logs when the system runs out of RAM --- ui/easydiffusion/model_manager.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/easydiffusion/model_manager.py b/ui/easydiffusion/model_manager.py index 29cf529b..9953fd74 100644 --- a/ui/easydiffusion/model_manager.py +++ b/ui/easydiffusion/model_manager.py @@ -72,7 +72,12 @@ def load_default_models(context: Context): del context.model_load_errors[model_type] except Exception as e: log.error(f"[red]Error while loading {model_type} model: {context.model_paths[model_type]}[/red]") - log.exception(e) + if "DefaultCPUAllocator: not enough memory" in str(e): + log.error( + f"[red]Your PC is low on system RAM. Please add some virtual memory (or swap space) by following the instructions at this link: https://www.ibm.com/docs/en/opw/8.2.0?topic=tuning-optional-increasing-paging-file-size-windows-computers[/red]" + ) + else: + log.exception(e) del context.model_paths[model_type] context.model_load_errors[model_type] = str(e) # storing the entire Exception can lead to memory leaks From b14653cb9e47ad5a6a1c924d7edd597bbd8cb427 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 5 Jun 2023 16:11:48 +0530 Subject: [PATCH 076/123] sdkit 1.0.103 - Pin the versions of diffusers models used; Use cpu offloading for balanced and low while upscaling using latent upscaler --- scripts/check_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index cbd6d0c1..f8ca8ce3 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.102", + "sdkit": "1.0.103", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", From 046c00d844be9908d10c38d40dfc6a7e45984757 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 5 Jun 2023 16:13:41 +0530 Subject: [PATCH 077/123] changelog --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 88ded3b5..86b4dce1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,8 @@ 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.40 - 4 Jun 2023 - Reduce the VRAM usage of Latent Upscaling when using "balanced" VRAM usage mode. +* 2.5.40 - 4 Jun 2023 - Fix the "realesrgan" key error when using CodeFormer with more than 1 image in a batch. * 2.5.40 - 3 Jun 2023 - Added CodeFormer as another option for fixing faces and eyes. CodeFormer tends to perform better than GFPGAN for many images. Thanks @patriceac for the implementation, and for contacting the CodeFormer team (who were supportive of it being integrated into Easy Diffusion). * 2.5.39 - 25 May 2023 - (beta-only) Seamless Tiling - make seamlessly tiled images, e.g. rock and grass textures. Thanks @JeLuf. * 2.5.38 - 24 May 2023 - Better reporting of errors, and show an explanation if the user cannot disable the "Use CPU" setting. From 047390873c2280f1f22725539259049f0899c2cc Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 5 Jun 2023 16:53:18 +0530 Subject: [PATCH 078/123] changelog; show labels next to the lora strength slider --- CHANGES.md | 3 +++ ui/index.html | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 86b4dce1..be96e000 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,9 @@ 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.41 - 4 Jun 2023 - Allow sharing an Easy Diffusion instance via https://try.cloudflare.com/ . You can find this option at the bottom of the Settings tab. Thanks @JeLuf. +* 2.5.41 - 4 Jun 2023 - Show an option to download for tiled images. Shows a button on the generated image. Creates larger images by tiling them with the image generated by Easy Diffusion. Thanks @JeLuf. +* 2.5.41 - 4 Jun 2023 - Allow LoRA strengths between -2 and 2. Thanks @ogmaresca. * 2.5.40 - 4 Jun 2023 - Reduce the VRAM usage of Latent Upscaling when using "balanced" VRAM usage mode. * 2.5.40 - 4 Jun 2023 - Fix the "realesrgan" key error when using CodeFormer with more than 1 image in a batch. * 2.5.40 - 3 Jun 2023 - Added CodeFormer as another option for fixing faces and eyes. CodeFormer tends to perform better than GFPGAN for many images. Thanks @patriceac for the implementation, and for contacting the CodeFormer team (who were supportive of it being integrated into Easy Diffusion). diff --git a/ui/index.html b/ui/index.html index 8558cc2c..30cd1453 100644 --- a/ui/index.html +++ b/ui/index.html @@ -30,7 +30,7 @@

    Easy Diffusion - v2.5.40 + v2.5.41

  • @@ -227,7 +227,10 @@ -
    + + -2 2   +
    + From 79d6ab9915571ecb394cb3f1d60576e079a54af5 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 6 Jun 2023 15:22:27 +0530 Subject: [PATCH 079/123] Update CHANGES.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index be96e000..36e0dde4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -24,7 +24,7 @@ Our focus continues to remain on an easy installation experience, and an easy us ### Detailed changelog * 2.5.41 - 4 Jun 2023 - Allow sharing an Easy Diffusion instance via https://try.cloudflare.com/ . You can find this option at the bottom of the Settings tab. Thanks @JeLuf. * 2.5.41 - 4 Jun 2023 - Show an option to download for tiled images. Shows a button on the generated image. Creates larger images by tiling them with the image generated by Easy Diffusion. Thanks @JeLuf. -* 2.5.41 - 4 Jun 2023 - Allow LoRA strengths between -2 and 2. Thanks @ogmaresca. +* 2.5.41 - 4 Jun 2023 - (beta-only) Allow LoRA strengths between -2 and 2. Thanks @ogmaresca. * 2.5.40 - 4 Jun 2023 - Reduce the VRAM usage of Latent Upscaling when using "balanced" VRAM usage mode. * 2.5.40 - 4 Jun 2023 - Fix the "realesrgan" key error when using CodeFormer with more than 1 image in a batch. * 2.5.40 - 3 Jun 2023 - Added CodeFormer as another option for fixing faces and eyes. CodeFormer tends to perform better than GFPGAN for many images. Thanks @patriceac for the implementation, and for contacting the CodeFormer team (who were supportive of it being integrated into Easy Diffusion). From d0184a15989f8df8cfb752002e4231839bb81a35 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 6 Jun 2023 16:16:21 +0530 Subject: [PATCH 080/123] Allow changing the strength of the codeformer model (1 - fidelity); Improve the styling of the sub-settings --- CHANGES.md | 11 +++++---- ui/easydiffusion/renderer.py | 1 + ui/easydiffusion/types.py | 1 + ui/index.html | 15 +++++------ ui/media/css/main.css | 8 ++++++ ui/media/js/main.js | 48 ++++++++++++++++++++++++++++-------- 6 files changed, 62 insertions(+), 22 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index be96e000..6ae532db 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,11 +22,12 @@ 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.41 - 4 Jun 2023 - Allow sharing an Easy Diffusion instance via https://try.cloudflare.com/ . You can find this option at the bottom of the Settings tab. Thanks @JeLuf. -* 2.5.41 - 4 Jun 2023 - Show an option to download for tiled images. Shows a button on the generated image. Creates larger images by tiling them with the image generated by Easy Diffusion. Thanks @JeLuf. -* 2.5.41 - 4 Jun 2023 - Allow LoRA strengths between -2 and 2. Thanks @ogmaresca. -* 2.5.40 - 4 Jun 2023 - Reduce the VRAM usage of Latent Upscaling when using "balanced" VRAM usage mode. -* 2.5.40 - 4 Jun 2023 - Fix the "realesrgan" key error when using CodeFormer with more than 1 image in a batch. +* 2.5.41 - 6 Jun 2023 - Allow changing the strength of CodeFormer, and slightly improved styling of the CodeFormer options. +* 2.5.41 - 5 Jun 2023 - Allow sharing an Easy Diffusion instance via https://try.cloudflare.com/ . You can find this option at the bottom of the Settings tab. Thanks @JeLuf. +* 2.5.41 - 5 Jun 2023 - Show an option to download for tiled images. Shows a button on the generated image. Creates larger images by tiling them with the image generated by Easy Diffusion. Thanks @JeLuf. +* 2.5.41 - 5 Jun 2023 - Allow LoRA strengths between -2 and 2. Thanks @ogmaresca. +* 2.5.40 - 5 Jun 2023 - Reduce the VRAM usage of Latent Upscaling when using "balanced" VRAM usage mode. +* 2.5.40 - 5 Jun 2023 - Fix the "realesrgan" key error when using CodeFormer with more than 1 image in a batch. * 2.5.40 - 3 Jun 2023 - Added CodeFormer as another option for fixing faces and eyes. CodeFormer tends to perform better than GFPGAN for many images. Thanks @patriceac for the implementation, and for contacting the CodeFormer team (who were supportive of it being integrated into Easy Diffusion). * 2.5.39 - 25 May 2023 - (beta-only) Seamless Tiling - make seamlessly tiled images, e.g. rock and grass textures. Thanks @JeLuf. * 2.5.38 - 24 May 2023 - Better reporting of errors, and show an explanation if the user cannot disable the "Use CPU" setting. diff --git a/ui/easydiffusion/renderer.py b/ui/easydiffusion/renderer.py index 4be6e6bf..ef038715 100644 --- a/ui/easydiffusion/renderer.py +++ b/ui/easydiffusion/renderer.py @@ -165,6 +165,7 @@ def filter_images(req: GenerateImageRequest, task_data: TaskData, images: list, filters_to_apply.append("codeformer") filter_params["upscale_faces"] = task_data.codeformer_upscale_faces + filter_params["codeformer_fidelity"] = task_data.codeformer_fidelity elif task_data.use_face_correction and "gfpgan" in task_data.use_face_correction.lower(): filters_to_apply.append("gfpgan") if task_data.use_upscale: diff --git a/ui/easydiffusion/types.py b/ui/easydiffusion/types.py index 4559a23a..abf8db29 100644 --- a/ui/easydiffusion/types.py +++ b/ui/easydiffusion/types.py @@ -52,6 +52,7 @@ class TaskData(BaseModel): stream_image_progress_interval: int = 5 clip_skip: bool = False codeformer_upscale_faces: bool = False + codeformer_fidelity: float = 0.5 class MergeRequest(BaseModel): diff --git a/ui/index.html b/ui/index.html index 30cd1453..c8f11b4d 100644 --- a/ui/index.html +++ b/ui/index.html @@ -266,11 +266,12 @@
    • Render Settings
    • -
    • +
    • -
      - -
      + + + +
    • @@ -284,9 +285,9 @@ -
      - -
      + + +
    diff --git a/ui/media/css/main.css b/ui/media/css/main.css index bd3cdbe6..9df38f9a 100644 --- a/ui/media/css/main.css +++ b/ui/media/css/main.css @@ -1324,6 +1324,14 @@ body.wait-pause { margin-left: 0.5em; } +.expandedSettingRow { + background: var(--background-color1); + width: 95%; + border-radius: 4pt; + margin-top: 5pt; + margin-bottom: 3pt; +} + /* TOAST NOTIFICATIONS */ .toast-notification { position: fixed; diff --git a/ui/media/js/main.js b/ui/media/js/main.js index 1684046f..5909fdb1 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -94,6 +94,8 @@ let upscaleAmountField = document.querySelector("#upscale_amount") let latentUpscalerSettings = document.querySelector("#latent_upscaler_settings") let latentUpscalerStepsSlider = document.querySelector("#latent_upscaler_steps_slider") let latentUpscalerStepsField = document.querySelector("#latent_upscaler_steps") +let codeformerFidelitySlider = document.querySelector("#codeformer_fidelity_slider") +let codeformerFidelityField = document.querySelector("#codeformer_fidelity") let stableDiffusionModelField = new ModelDropdown(document.querySelector("#stable_diffusion_model"), "stable-diffusion") let clipSkipField = document.querySelector("#clip_skip") let tilingField = document.querySelector("#tiling") @@ -1266,6 +1268,7 @@ function getCurrentUserRequest() { if (gfpganModelField.value.includes("codeformer")) { newTask.reqBody.codeformer_upscale_faces = document.querySelector("#codeformer_upscale_faces").checked + newTask.reqBody.codeformer_fidelity = 1 - parseFloat(codeformerFidelityField.value) } } if (useUpscalingField.checked) { @@ -1588,8 +1591,10 @@ function onFixFaceModelChange() { let codeformerSettings = document.querySelector("#codeformer_settings") if (gfpganModelField.value === "codeformer" && !gfpganModelField.disabled) { codeformerSettings.classList.remove("displayNone") + codeformerSettings.classList.add("expandedSettingRow") } else { codeformerSettings.classList.add("displayNone") + codeformerSettings.classList.remove("expandedSettingRow") } } gfpganModelField.addEventListener("change", onFixFaceModelChange) @@ -1610,9 +1615,11 @@ function onUpscaleModelChange() { upscale4x.disabled = true upscaleAmountField.value = "2" latentUpscalerSettings.classList.remove("displayNone") + latentUpscalerSettings.classList.add("expandedSettingRow") } else { upscale4x.disabled = false latentUpscalerSettings.classList.add("displayNone") + latentUpscalerSettings.classList.remove("expandedSettingRow") } } upscaleModelField.addEventListener("change", onUpscaleModelChange) @@ -1627,6 +1634,27 @@ document.onkeydown = function(e) { } } +/********************* CodeFormer Fidelity **************************/ +function updateCodeformerFidelity() { + codeformerFidelityField.value = codeformerFidelitySlider.value / 10 + codeformerFidelityField.dispatchEvent(new Event("change")) +} + +function updateCodeformerFidelitySlider() { + if (codeformerFidelityField.value < 0) { + codeformerFidelityField.value = 0 + } else if (codeformerFidelityField.value > 1) { + codeformerFidelityField.value = 1 + } + + codeformerFidelitySlider.value = codeformerFidelityField.value * 10 + codeformerFidelitySlider.dispatchEvent(new Event("change")) +} + +codeformerFidelitySlider.addEventListener("input", updateCodeformerFidelity) +codeformerFidelityField.addEventListener("input", updateCodeformerFidelitySlider) +updateCodeformerFidelity() + /********************* Latent Upscaler Steps **************************/ function updateLatentUpscalerSteps() { latentUpscalerStepsField.value = latentUpscalerStepsSlider.value @@ -1981,25 +2009,25 @@ resumeBtn.addEventListener("click", function() { function tunnelUpdate(event) { if ("cloudflare" in event) { - document.getElementById('cloudflare-off').classList.add("displayNone") - document.getElementById('cloudflare-on').classList.remove("displayNone") + document.getElementById("cloudflare-off").classList.add("displayNone") + document.getElementById("cloudflare-on").classList.remove("displayNone") cloudflareAddressField.innerHTML = event.cloudflare - document.getElementById('toggle-cloudflare-tunnel').innerHTML = "Stop" + document.getElementById("toggle-cloudflare-tunnel").innerHTML = "Stop" } else { - document.getElementById('cloudflare-on').classList.add("displayNone") - document.getElementById('cloudflare-off').classList.remove("displayNone") - document.getElementById('toggle-cloudflare-tunnel').innerHTML = "Start" + document.getElementById("cloudflare-on").classList.add("displayNone") + document.getElementById("cloudflare-off").classList.remove("displayNone") + document.getElementById("toggle-cloudflare-tunnel").innerHTML = "Start" } } -document.getElementById('toggle-cloudflare-tunnel').addEventListener("click", async function() { +document.getElementById("toggle-cloudflare-tunnel").addEventListener("click", async function() { let command = "stop" - if (document.getElementById('toggle-cloudflare-tunnel').innerHTML == "Start") { - command = "start" + if (document.getElementById("toggle-cloudflare-tunnel").innerHTML == "Start") { + command = "start" } showToast(`Cloudflare tunnel ${command} initiated. Please wait.`) - let res = await fetch("/tunnel/cloudflare/"+command, { + let res = await fetch("/tunnel/cloudflare/" + command, { method: "POST", headers: { "Content-Type": "application/json", From 6ae5cb28cfcb55a9d0a6507100cd9f4205231982 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 6 Jun 2023 16:37:17 +0530 Subject: [PATCH 081/123] Set the default codeformer strength to 0.5 --- ui/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/index.html b/ui/index.html index c8f11b4d..0c4386de 100644 --- a/ui/index.html +++ b/ui/index.html @@ -269,7 +269,7 @@
  • - +
  • From 05c2de94506057101535ffd56a6583a60bf38e72 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 6 Jun 2023 16:56:37 +0530 Subject: [PATCH 082/123] Fail with an error if the desired model (non-Stable Diffusion) wasn't found --- ui/easydiffusion/model_manager.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/easydiffusion/model_manager.py b/ui/easydiffusion/model_manager.py index 9953fd74..ef5166df 100644 --- a/ui/easydiffusion/model_manager.py +++ b/ui/easydiffusion/model_manager.py @@ -123,6 +123,9 @@ def resolve_model_to_use(model_name: str = None, model_type: str = None): ) return default_model_path + if model_name: + raise Exception(f"Could not find the desired model {model_name}! Is it present in the {model_dir} folder?") + return None From c09512bf12bc75df4e0f3240e509bb0983c5ebec Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 6 Jun 2023 16:57:25 +0530 Subject: [PATCH 083/123] dead code --- ui/easydiffusion/model_manager.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/easydiffusion/model_manager.py b/ui/easydiffusion/model_manager.py index ef5166df..4d58953a 100644 --- a/ui/easydiffusion/model_manager.py +++ b/ui/easydiffusion/model_manager.py @@ -126,8 +126,6 @@ def resolve_model_to_use(model_name: str = None, model_type: str = None): if model_name: raise Exception(f"Could not find the desired model {model_name}! Is it present in the {model_dir} folder?") - return None - def reload_models_if_necessary(context: Context, task_data: TaskData): face_fix_lower = task_data.use_face_correction.lower() if task_data.use_face_correction else "" From 9486c03a89350d3b7e915f1645ddc38c19e6d70e Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 6 Jun 2023 17:10:38 +0530 Subject: [PATCH 084/123] Don't use the default SD model (if the desired model was not found), unless the UI is starting up --- ui/easydiffusion/model_manager.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/easydiffusion/model_manager.py b/ui/easydiffusion/model_manager.py index 4d58953a..de2c10ac 100644 --- a/ui/easydiffusion/model_manager.py +++ b/ui/easydiffusion/model_manager.py @@ -60,7 +60,7 @@ def load_default_models(context: Context): # init default model paths for model_type in MODELS_TO_LOAD_ON_START: - context.model_paths[model_type] = resolve_model_to_use(model_type=model_type) + context.model_paths[model_type] = resolve_model_to_use(model_type=model_type, fail_if_not_found=False) try: load_model( context, @@ -90,7 +90,7 @@ 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): +def resolve_model_to_use(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() @@ -113,7 +113,7 @@ def resolve_model_to_use(model_name: str = None, model_type: str = None): return os.path.abspath(model_name + model_extension) # Can't find requested model, check the default paths. - if model_type == "stable-diffusion": + if model_type == "stable-diffusion" and not fail_if_not_found: for default_model in default_models: default_model_path = os.path.join(model_dir, default_model["file_name"]) if os.path.exists(default_model_path): @@ -123,7 +123,7 @@ def resolve_model_to_use(model_name: str = None, model_type: str = None): ) return default_model_path - if model_name: + if model_name and fail_if_not_found: raise Exception(f"Could not find the desired model {model_name}! Is it present in the {model_dir} folder?") From 0d8e73b206e8fb1cfe6a59768b5db7b1c3b1f3c2 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Wed, 7 Jun 2023 15:10:57 +0530 Subject: [PATCH 085/123] sdkit 1.0.104 - Not all pipelines have vae slicing --- scripts/check_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index 527410c5..5264ec08 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.103", + "sdkit": "1.0.104", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", From 9a0031c47b6b84d20d763949e6bba7aab0df6c01 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Wed, 7 Jun 2023 15:21:16 +0530 Subject: [PATCH 086/123] Don't copy check_models.py, it doesn't exist anymore --- scripts/on_env_start.bat | 1 - scripts/on_env_start.sh | 1 - scripts/on_sd_start.bat | 1 - scripts/on_sd_start.sh | 1 - 4 files changed, 4 deletions(-) diff --git a/scripts/on_env_start.bat b/scripts/on_env_start.bat index 44144cfa..bc92d0e9 100644 --- a/scripts/on_env_start.bat +++ b/scripts/on_env_start.bat @@ -67,7 +67,6 @@ if "%update_branch%"=="" ( @xcopy sd-ui-files\ui ui /s /i /Y /q @copy sd-ui-files\scripts\on_sd_start.bat scripts\ /Y @copy sd-ui-files\scripts\check_modules.py scripts\ /Y -@copy sd-ui-files\scripts\check_models.py scripts\ /Y @copy sd-ui-files\scripts\get_config.py scripts\ /Y @copy "sd-ui-files\scripts\Start Stable Diffusion UI.cmd" . /Y @copy "sd-ui-files\scripts\Developer Console.cmd" . /Y diff --git a/scripts/on_env_start.sh b/scripts/on_env_start.sh index 30465975..366b5dd1 100755 --- a/scripts/on_env_start.sh +++ b/scripts/on_env_start.sh @@ -50,7 +50,6 @@ cp -Rf sd-ui-files/ui . cp sd-ui-files/scripts/on_sd_start.sh scripts/ cp sd-ui-files/scripts/bootstrap.sh scripts/ cp sd-ui-files/scripts/check_modules.py scripts/ -cp sd-ui-files/scripts/check_models.py scripts/ cp sd-ui-files/scripts/get_config.py scripts/ cp sd-ui-files/scripts/start.sh . cp sd-ui-files/scripts/developer_console.sh . diff --git a/scripts/on_sd_start.bat b/scripts/on_sd_start.bat index d2ef7321..f92b9f6f 100644 --- a/scripts/on_sd_start.bat +++ b/scripts/on_sd_start.bat @@ -5,7 +5,6 @@ @copy sd-ui-files\scripts\on_env_start.bat scripts\ /Y @copy sd-ui-files\scripts\check_modules.py scripts\ /Y -@copy sd-ui-files\scripts\check_models.py scripts\ /Y @copy sd-ui-files\scripts\get_config.py scripts\ /Y if exist "%cd%\profile" ( diff --git a/scripts/on_sd_start.sh b/scripts/on_sd_start.sh index 55f4da25..be5161d4 100755 --- a/scripts/on_sd_start.sh +++ b/scripts/on_sd_start.sh @@ -4,7 +4,6 @@ cp sd-ui-files/scripts/functions.sh scripts/ cp sd-ui-files/scripts/on_env_start.sh scripts/ cp sd-ui-files/scripts/bootstrap.sh scripts/ cp sd-ui-files/scripts/check_modules.py scripts/ -cp sd-ui-files/scripts/check_models.py scripts/ cp sd-ui-files/scripts/get_config.py scripts/ source ./scripts/functions.sh From e23f66a697f1afab2310a36f73b0d76adc31cf7c Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Wed, 7 Jun 2023 15:45:21 +0530 Subject: [PATCH 087/123] Fix #1333 - listen_port isn't always present in the config file --- ui/easydiffusion/server.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ui/easydiffusion/server.py b/ui/easydiffusion/server.py index b9ffe5f9..d8940bb5 100644 --- a/ui/easydiffusion/server.py +++ b/ui/easydiffusion/server.py @@ -338,21 +338,22 @@ def get_image_internal(task_id: int, img_id: int): class CloudflareTunnel: def __init__(self): config = app.getConfig() - self.Urls = None - self.port = config["net"]["listen_port"] + self.urls = None + self.port = config.get("net", {}).get("listen_port") def start(self): - self.Urls = try_cloudflare(self.port) + if self.port: + self.urls = try_cloudflare(self.port) def stop(self): - if self.Urls != None: + if self.urls: try_cloudflare.terminate(self.port) - self.Urls = None + self.urls = None @property def address(self): - if self.Urls != None: - return self.Urls.tunnel + if self.urls: + return self.urls.tunnel else: return None From 267c7b85eab7fba34030cadfdb550f68ea81aa06 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Wed, 7 Jun 2023 16:37:44 +0530 Subject: [PATCH 088/123] Use only realesrgan_x4 (not anime) for upscaling in codeformer --- ui/easydiffusion/renderer.py | 64 ++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/ui/easydiffusion/renderer.py b/ui/easydiffusion/renderer.py index ef038715..a57dfc6c 100644 --- a/ui/easydiffusion/renderer.py +++ b/ui/easydiffusion/renderer.py @@ -7,10 +7,12 @@ from easydiffusion import device_manager from easydiffusion.types import GenerateImageRequest from easydiffusion.types import Image as ResponseImage from easydiffusion.types import Response, TaskData, UserInitiatedStop +from easydiffusion.model_manager import DEFAULT_MODELS, resolve_model_to_use from easydiffusion.utils import get_printable_request, log, save_images_to_disk from sdkit import Context from sdkit.filter import apply_filters from sdkit.generate import generate_images +from sdkit.models import load_model from sdkit.utils import ( diffusers_latent_samples_to_images, gc, @@ -157,37 +159,51 @@ def filter_images(req: GenerateImageRequest, task_data: TaskData, images: list, if user_stopped: return images - filters_to_apply = [] - filter_params = {} if task_data.block_nsfw: - filters_to_apply.append("nsfw_checker") - if task_data.use_face_correction and "codeformer" in task_data.use_face_correction.lower(): - filters_to_apply.append("codeformer") + images = apply_filters(context, "nsfw_checker", images) - filter_params["upscale_faces"] = task_data.codeformer_upscale_faces - filter_params["codeformer_fidelity"] = task_data.codeformer_fidelity + if task_data.use_face_correction and "codeformer" in task_data.use_face_correction.lower(): + default_realesrgan = DEFAULT_MODELS["realesrgan"][0]["file_name"] + prev_realesrgan_path = None + if task_data.codeformer_upscale_faces and default_realesrgan not in context.model_paths["realesrgan"]: + prev_realesrgan_path = context.model_paths["realesrgan"] + context.model_paths["realesrgan"] = resolve_model_to_use(default_realesrgan, "realesrgan") + load_model(context, "realesrgan") + + try: + images = apply_filters( + context, + "codeformer", + images, + upscale_faces=task_data.codeformer_upscale_faces, + codeformer_fidelity=task_data.codeformer_fidelity, + ) + finally: + if prev_realesrgan_path: + context.model_paths["realesrgan"] = prev_realesrgan_path + load_model(context, "realesrgan") elif task_data.use_face_correction and "gfpgan" in task_data.use_face_correction.lower(): - filters_to_apply.append("gfpgan") + images = apply_filters(context, "gfpgan", images) + if task_data.use_upscale: if "realesrgan" in task_data.use_upscale.lower(): - filters_to_apply.append("realesrgan") + images = apply_filters(context, "realesrgan", images, scale=task_data.upscale_amount) elif task_data.use_upscale == "latent_upscaler": - filters_to_apply.append("latent_upscaler") + images = apply_filters( + context, + "latent_upscaler", + images, + scale=task_data.upscale_amount, + latent_upscaler_options={ + "prompt": req.prompt, + "negative_prompt": req.negative_prompt, + "seed": req.seed, + "num_inference_steps": task_data.latent_upscaler_steps, + "guidance_scale": 0, + }, + ) - filter_params["latent_upscaler_options"] = { - "prompt": req.prompt, - "negative_prompt": req.negative_prompt, - "seed": req.seed, - "num_inference_steps": task_data.latent_upscaler_steps, - "guidance_scale": 0, - } - - filter_params["scale"] = task_data.upscale_amount - - if len(filters_to_apply) == 0: - return images - - return apply_filters(context, filters_to_apply, images, **filter_params) + return images def construct_response(images: list, seeds: list, task_data: TaskData, base_seed: int): From 48edce72a96d08f646221f79b19d26a6842e20d6 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Wed, 7 Jun 2023 16:38:15 +0530 Subject: [PATCH 089/123] Log the version numbers of only a few important modules --- scripts/check_modules.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index 5264ec08..dc3733e9 100644 --- a/scripts/check_modules.py +++ b/scripts/check_modules.py @@ -26,6 +26,7 @@ modules_to_check = { "pycloudflared": "0.2.0", # "xformers": "0.0.16", } +modules_to_log = ["torch", "torchvision", "sdkit", "stable-diffusion-sdkit"] def version(module_name: str) -> str: @@ -90,7 +91,8 @@ def init(): traceback.print_exc() fail(module_name) - print(f"{module_name}: {version(module_name)}") + if module_name in modules_to_log: + print(f"{module_name}: {version(module_name)}") ### utilities From 5398765fd7eddfe81554233df2acf74022371a9b Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Thu, 8 Jun 2023 15:21:16 +0530 Subject: [PATCH 090/123] Tighten the image editor (to reduce unnecessary empty space and reduce mouse travel) - Thanks @fdwr - #1307 --- ui/media/css/image-editor.css | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/media/css/image-editor.css b/ui/media/css/image-editor.css index ea8112e3..ba046383 100644 --- a/ui/media/css/image-editor.css +++ b/ui/media/css/image-editor.css @@ -96,7 +96,7 @@ .editor-controls-center { /* background: var(--background-color2); */ - flex: 1; + flex: 0; display: flex; justify-content: center; align-items: center; @@ -105,6 +105,8 @@ .editor-controls-center > div { position: relative; background: black; + margin: 20pt; + margin-top: 40pt; } .editor-controls-center canvas { @@ -164,8 +166,10 @@ margin: var(--popup-margin); padding: var(--popup-padding); min-height: calc(99h - (2 * var(--popup-margin))); - max-width: none; + max-width: fit-content; min-width: fit-content; + margin-left: auto; + margin-right: auto; } .image-editor-popup h1 { From 4f799a2bf077b3c22aa186361fb2f8019d424fc9 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Thu, 8 Jun 2023 15:52:41 +0530 Subject: [PATCH 091/123] Use gfpgan as the default model for face restoration --- ui/media/js/main.js | 7 +++++++ ui/media/js/searchable-models.js | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ui/media/js/main.js b/ui/media/js/main.js index 5909fdb1..54e7042a 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -2061,3 +2061,10 @@ prettifyInputs(document) // set the textbox as focused on start promptField.focus() promptField.selectionStart = promptField.value.length + +// use gfpgan as the default model for face restoration +document.addEventListener("refreshModels", function() { + let gfpganIdx = gfpganModelField.inputModels.findIndex((e) => e.toLowerCase().startsWith("gfpgan")) + let gfpganElem = gfpganModelField.modelElements[gfpganIdx] + gfpganModelField.selectModelEntry(gfpganElem) +}) diff --git a/ui/media/js/searchable-models.js b/ui/media/js/searchable-models.js index 855cfc61..2b72aaa6 100644 --- a/ui/media/js/searchable-models.js +++ b/ui/media/js/searchable-models.js @@ -103,7 +103,6 @@ class ModelDropdown { "refreshModels", this.bind(function(e) { // reload the models - this.inputModels = modelsOptions[this.modelKey] this.inputModels = [] let modelKeys = Array.isArray(this.modelKey) ? this.modelKey : [this.modelKey] for (let i = 0; i < modelKeys.length; i++) { From e349fb1a23793c216b5574e3270e97b57a0bd07b Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Thu, 8 Jun 2023 15:55:36 +0530 Subject: [PATCH 092/123] fix --- ui/media/js/main.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/media/js/main.js b/ui/media/js/main.js index 54e7042a..00a49d17 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -2063,8 +2063,8 @@ promptField.focus() promptField.selectionStart = promptField.value.length // use gfpgan as the default model for face restoration -document.addEventListener("refreshModels", function() { - let gfpganIdx = gfpganModelField.inputModels.findIndex((e) => e.toLowerCase().startsWith("gfpgan")) - let gfpganElem = gfpganModelField.modelElements[gfpganIdx] - gfpganModelField.selectModelEntry(gfpganElem) -}) +// document.addEventListener("refreshModels", function() { +// let gfpganIdx = gfpganModelField.inputModels.findIndex((e) => e.toLowerCase().startsWith("gfpgan")) +// let gfpganElem = gfpganModelField.modelElements[gfpganIdx] +// gfpganModelField.selectModelEntry(gfpganElem) +// }) From 924fee394ac76ee85df84d5388b24ed9e14ced94 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Thu, 8 Jun 2023 16:09:11 +0530 Subject: [PATCH 093/123] A better way to make gfpgan show up at the top --- ui/media/js/main.js | 9 +-------- ui/media/js/searchable-models.js | 13 ++++++++++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ui/media/js/main.js b/ui/media/js/main.js index 00a49d17..b44af102 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -87,7 +87,7 @@ let promptStrengthField = document.querySelector("#prompt_strength") let samplerField = document.querySelector("#sampler_name") let samplerSelectionContainer = document.querySelector("#samplerSelection") let useFaceCorrectionField = document.querySelector("#use_face_correction") -let gfpganModelField = new ModelDropdown(document.querySelector("#gfpgan_model"), ["codeformer", "gfpgan"]) +let gfpganModelField = new ModelDropdown(document.querySelector("#gfpgan_model"), ["gfpgan", "codeformer"], "", false) let useUpscalingField = document.querySelector("#use_upscale") let upscaleModelField = document.querySelector("#upscale_model") let upscaleAmountField = document.querySelector("#upscale_amount") @@ -2061,10 +2061,3 @@ prettifyInputs(document) // set the textbox as focused on start promptField.focus() promptField.selectionStart = promptField.value.length - -// use gfpgan as the default model for face restoration -// document.addEventListener("refreshModels", function() { -// let gfpganIdx = gfpganModelField.inputModels.findIndex((e) => e.toLowerCase().startsWith("gfpgan")) -// let gfpganElem = gfpganModelField.modelElements[gfpganIdx] -// gfpganModelField.selectModelEntry(gfpganElem) -// }) diff --git a/ui/media/js/searchable-models.js b/ui/media/js/searchable-models.js index 2b72aaa6..7bdb176a 100644 --- a/ui/media/js/searchable-models.js +++ b/ui/media/js/searchable-models.js @@ -38,6 +38,8 @@ class ModelDropdown { noneEntry //= '' modelFilterInitialized //= undefined + sorted //= true + /* MIMIC A REGULAR INPUT FIELD */ get parentElement() { return this.modelFilter.parentElement @@ -83,10 +85,11 @@ class ModelDropdown { /* SEARCHABLE INPUT */ - constructor(input, modelKey, noneEntry = "") { + constructor(input, modelKey, noneEntry = "", sorted = true) { this.modelFilter = input this.noneEntry = noneEntry this.modelKey = modelKey + this.sorted = sorted if (modelsOptions !== undefined) { // reuse models from cache (only useful for plugins, which are loaded after models) @@ -566,11 +569,15 @@ class ModelDropdown { }) const childFolderNames = Array.from(foldersMap.keys()) - this.sortStringArray(childFolderNames) + if (this.sorted) { + this.sortStringArray(childFolderNames) + } const folderElements = childFolderNames.map((name) => foldersMap.get(name)) const modelNames = Array.from(modelsMap.keys()) - this.sortStringArray(modelNames) + if (this.sorted) { + this.sortStringArray(modelNames) + } const modelElements = modelNames.map((name) => modelsMap.get(name)) if (modelElements.length && folderName) { From f83af28e428a3d5f80ab40eb0cc58c2f5f4af0d3 Mon Sep 17 00:00:00 2001 From: JeLuF Date: Sun, 11 Jun 2023 21:12:22 +0200 Subject: [PATCH 094/123] Set PYTHONNOUSERSITE=y in dev console Make behaviour consistent with on_env_start.sh --- scripts/developer_console.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/developer_console.sh b/scripts/developer_console.sh index 73972568..57846eeb 100755 --- a/scripts/developer_console.sh +++ b/scripts/developer_console.sh @@ -39,6 +39,8 @@ if [ "$0" == "bash" ]; then export PYTHONPATH="$(pwd)/stable-diffusion/env/lib/python3.8/site-packages" fi + export PYTHONNOUSERSITE=y + which python python --version From e213f6cb9559a16fa69a227363924cc19ce586a6 Mon Sep 17 00:00:00 2001 From: ManInDark <61268856+ManInDark@users.noreply.github.com> Date: Mon, 12 Jun 2023 12:48:52 +0200 Subject: [PATCH 095/123] Added calculation as to how many images will be generated with given prompts. --- ui/media/js/main.js | 65 ++++++++++++++++++++++++++++++++++++++++++-- ui/media/js/utils.js | 4 +++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/ui/media/js/main.js b/ui/media/js/main.js index b44af102..cb516a37 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -1327,6 +1327,43 @@ function getPrompts(prompts) { return promptsToMake } +function getPromptsNumber(prompts) { + if (typeof prompts === "undefined") { + prompts = promptField.value + } + if (prompts.trim() === "" && activeTags.length === 0) { + return [""] + } + + let promptsToMake = [] + let numberOfPrompts = 0 + if (prompts.trim() !== "") { // this needs to stay sort of the same, as the prompts have to be passed through to the other functions + prompts = prompts.split("\n") + prompts = prompts.map((prompt) => prompt.trim()) + prompts = prompts.filter((prompt) => prompt !== "") + + promptsToMake = applySetOperator(prompts) // switched those around as Set grows in a linear fashion and permute in 2^n, and one has to be computed for the other to be calculated + numberOfPrompts = applyPermuteOperatorNumber(promptsToMake) + } + const newTags = activeTags.filter((tag) => tag.inactive === undefined || tag.inactive === false) + if (newTags.length > 0) { + const promptTags = newTags.map((x) => x.name).join(", ") + if (numberOfPrompts > 0) { + // promptsToMake = promptsToMake.map((prompt) => `${prompt}, ${promptTags}`) + // nothing changes, as all prompts just get modified + } else { + // promptsToMake.push(promptTags) + numberOfPrompts = 1 + } + } + + // Why is this applied twice? It does not do anything here, as everything should have already been done earlier + // promptsToMake = applyPermuteOperator(promptsToMake) + // promptsToMake = applySetOperator(promptsToMake) + + return numberOfPrompts +} + function applySetOperator(prompts) { let promptsToMake = [] let braceExpander = new BraceExpander() @@ -1338,7 +1375,7 @@ function applySetOperator(prompts) { return promptsToMake } -function applyPermuteOperator(prompts) { +function applyPermuteOperator(prompts) { // prompts is array of input, trimmed, filtered and split by \n let promptsToMake = [] prompts.forEach((prompt) => { let promptMatrix = prompt.split("|") @@ -1357,6 +1394,26 @@ function applyPermuteOperator(prompts) { return promptsToMake } +// returns how many prompts would have to be made with the given prompts +function applyPermuteOperatorNumber(prompts) { // prompts is array of input, trimmed, filtered and split by \n + let numberOfPrompts = 0 + prompts.forEach((prompt) => { + let promptCounter = 1 + let promptMatrix = prompt.split("|") + promptMatrix.shift() + + promptMatrix = promptMatrix.map((p) => p.trim()) + promptMatrix = promptMatrix.filter((p) => p !== "") + + if (promptMatrix.length > 0) { + promptCounter *= permutePromptsNumber(promptMatrix) + } + numberOfPrompts += promptCounter + }) + + return numberOfPrompts +} + function permutePrompts(promptBase, promptMatrix) { let prompts = [] let permutations = permute(promptMatrix) @@ -1378,6 +1435,10 @@ function permutePrompts(promptBase, promptMatrix) { return prompts } +function permutePromptsNumber(promptMatrix) { // this should calculate how many different prompts can be made with the prompt matrix + return permuteNumber(promptMatrix) +} + // create a file name with embedded prompt and metadata // for easier cateloging and comparison function createFileName(prompt, seed, steps, guidance, outputFormat) { @@ -1546,7 +1607,7 @@ heightField.addEventListener("change", onDimensionChange) function renameMakeImageButton() { let totalImages = - Math.max(parseInt(numOutputsTotalField.value), parseInt(numOutputsParallelField.value)) * getPrompts().length + Math.max(parseInt(numOutputsTotalField.value), parseInt(numOutputsParallelField.value)) * getPromptsNumber() let imageLabel = "Image" if (totalImages > 1) { imageLabel = totalImages + " Images" diff --git a/ui/media/js/utils.js b/ui/media/js/utils.js index 871ba714..111a12e1 100644 --- a/ui/media/js/utils.js +++ b/ui/media/js/utils.js @@ -153,6 +153,10 @@ function permute(arr) { return permutations } +function permuteNumber(arr) { + return Math.pow(2, arr.length) +} + // https://stackoverflow.com/a/8212878 function millisecondsToStr(milliseconds) { function numberEnding(number) { From 3e34cdc8845fa91fd16018bf70a94569d97db7bb Mon Sep 17 00:00:00 2001 From: ManInDark <61268856+ManInDark@users.noreply.github.com> Date: Mon, 12 Jun 2023 13:25:12 +0200 Subject: [PATCH 096/123] Added sets to the readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6a629e57..5366772f 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ Just delete the `EasyDiffusion` folder to uninstall all the downloaded packages. - **Attention/Emphasis**: () in the prompt increases the model's attention to enclosed words, and [] decreases it. - **Weighted Prompts**: Use weights for specific words in your prompt to change their importance, e.g. `red:2.4 dragon:1.2`. - **Prompt Matrix**: Quickly create multiple variations of your prompt, e.g. `a photograph of an astronaut riding a horse | illustration | cinematic lighting`. +- **Prompt Set**: Quickly create multiple variations of your prompt, e.g. `a photograph of an astronaut on the {moon,earth}` - **1-click Upscale/Face Correction**: Upscale or correct an image after it has been generated. - **Make Similar Images**: Click to generate multiple variations of a generated image. - **NSFW Setting**: A setting in the UI to control *NSFW content*. From 9a81d17d33f6c15c23dc26bb92993ed38bac5ab0 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 12 Jun 2023 16:57:36 +0530 Subject: [PATCH 097/123] Fix for multi-gpu bug in codeformer --- scripts/check_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index dc3733e9..1931b4f0 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.104", + "sdkit": "1.0.105", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", From 324ffdefba3537bfcbe2c88a1000055c5d05b83f Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 12 Jun 2023 16:58:11 +0530 Subject: [PATCH 098/123] changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index cc2cfb04..178ec12f 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.41 - 12 Jun 2023 - Fix multi-gpu bug with CodeFormer. * 2.5.41 - 6 Jun 2023 - Allow changing the strength of CodeFormer, and slightly improved styling of the CodeFormer options. * 2.5.41 - 5 Jun 2023 - Allow sharing an Easy Diffusion instance via https://try.cloudflare.com/ . You can find this option at the bottom of the Settings tab. Thanks @JeLuf. * 2.5.41 - 5 Jun 2023 - Show an option to download for tiled images. Shows a button on the generated image. Creates larger images by tiling them with the image generated by Easy Diffusion. Thanks @JeLuf. From eb96bfe8a49c9c10ed4a6c4fc751a5481a6bcaac Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 13 Jun 2023 13:39:23 +0530 Subject: [PATCH 099/123] sdkit 1.0.106 - fix errors with multi-gpu in low vram mode --- scripts/check_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index 1931b4f0..6275de45 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.105", + "sdkit": "1.0.106", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", From 41d8847592446af5ed06c28752475d8d7e08f792 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 13 Jun 2023 13:39:58 +0530 Subject: [PATCH 100/123] changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 178ec12f..b53ac141 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.41 - 13 Jun 2023 - Fix multi-gpu bug with "low" VRAM usage mode while generating images. * 2.5.41 - 12 Jun 2023 - Fix multi-gpu bug with CodeFormer. * 2.5.41 - 6 Jun 2023 - Allow changing the strength of CodeFormer, and slightly improved styling of the CodeFormer options. * 2.5.41 - 5 Jun 2023 - Allow sharing an Easy Diffusion instance via https://try.cloudflare.com/ . You can find this option at the bottom of the Settings tab. Thanks @JeLuf. From 6ae4314b798efe7d3e952e111fd9fc1b6d73c4f4 Mon Sep 17 00:00:00 2001 From: ManInDark <61268856+ManInDark@users.noreply.github.com> Date: Tue, 13 Jun 2023 16:09:54 +0200 Subject: [PATCH 101/123] Incorporated proposal by @JeLuF in #1324 --- ui/media/js/main.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/ui/media/js/main.js b/ui/media/js/main.js index cb516a37..a7cccc55 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -1342,6 +1342,16 @@ function getPromptsNumber(prompts) { prompts = prompts.map((prompt) => prompt.trim()) prompts = prompts.filter((prompt) => prompt !== "") + // estimate number of prompts + let estimatedNumberOfPrompts = 0 + prompts.forEach((prompt) => { + estimatedNumberOfPrompts += (prompt.match(/{[^}]*}/g) || []).map((e) => e.match(/,/g).length + 1).reduce( (p,a) => p*a, 1) * (2**(prompt.match(/\|/g) || []).length) + }) + + if (estimatedNumberOfPrompts >= 10000) { + return 10000 + } + promptsToMake = applySetOperator(prompts) // switched those around as Set grows in a linear fashion and permute in 2^n, and one has to be computed for the other to be calculated numberOfPrompts = applyPermuteOperatorNumber(promptsToMake) } @@ -1613,9 +1623,15 @@ function renameMakeImageButton() { imageLabel = totalImages + " Images" } if (SD.activeTasks.size == 0) { - makeImageBtn.innerText = "Make " + imageLabel + if (totalImages >= 10000) + makeImageBtn.innerText = "Make tens of thousands of images" + else + makeImageBtn.innerText = "Make " + imageLabel } else { - makeImageBtn.innerText = "Enqueue Next " + imageLabel + if (totalImages >= 10000) + makeImageBtn.innerText = "Enqueue tens of thousands of images" + else + makeImageBtn.innerText = "Enqueue Next " + imageLabel } } numOutputsTotalField.addEventListener("change", renameMakeImageButton) From ed59972b032b49e497e57985be92926659dc6441 Mon Sep 17 00:00:00 2001 From: ManInDark <61268856+ManInDark@users.noreply.github.com> Date: Wed, 14 Jun 2023 11:57:06 +0200 Subject: [PATCH 102/123] Changed all links as mentioned in #1339 --- CHANGES.md | 12 ++++----- CONTRIBUTING.md | 4 +-- How to install and run.txt | 6 ++--- PRIVACY.md | 2 +- README BEFORE YOU RUN THIS.txt | 2 +- README.md | 14 +++++------ build.bat | 2 +- build.sh | 2 +- scripts/bootstrap.bat | 2 +- scripts/check_modules.py | 4 +-- scripts/functions.sh | 4 +-- scripts/on_env_start.bat | 4 +-- scripts/on_env_start.sh | 2 +- scripts/on_sd_start.bat | 4 +-- ui/easydiffusion/app.py | 2 +- ui/index.html | 36 +++++++++++++-------------- ui/plugins/ui/release-notes.plugin.js | 4 +-- 17 files changed, 53 insertions(+), 53 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b53ac141..d222d795 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,13 +8,13 @@ - **Full support for Stable Diffusion 2.1 (including CPU)** - supports loading v1.4 or v2.0 or v2.1 models seamlessly. No need to enable "Test SD2", and no need to add `sd2_` to your SD 2.0 model file names. Works on CPU as well. - **Memory optimized Stable Diffusion 2.1** - you can now use Stable Diffusion 2.1 models, with the same low VRAM optimizations that we've always had for SD 1.4. Please note, the SD 2.0 and 2.1 models require more GPU and System RAM, as compared to the SD 1.4 and 1.5 models. - **11 new samplers!** - explore the new samplers, some of which can generate great images in less than 10 inference steps! We've added the Karras and UniPC samplers. Thanks @Schorny for the UniPC samplers. -- **Model Merging** - You can now merge two models (`.ckpt` or `.safetensors`) and output `.ckpt` or `.safetensors` models, optionally in `fp16` precision. Details: https://github.com/cmdr2/stable-diffusion-ui/wiki/Model-Merging . Thanks @JeLuf. +- **Model Merging** - You can now merge two models (`.ckpt` or `.safetensors`) and output `.ckpt` or `.safetensors` models, optionally in `fp16` precision. Details: https://github.com/easydiffusion/easydiffusion/wiki/Model-Merging . Thanks @JeLuf. - **Fast loading/unloading of VAEs** - No longer needs to reload the entire Stable Diffusion model, each time you change the VAE - **Database of known models** - automatically picks the right configuration for known models. E.g. we automatically detect and apply "v" parameterization (required for some SD 2.0 models), and "fp32" attention precision (required for some SD 2.1 models). - **Color correction for img2img** - an option to preserve the color profile (histogram) of the initial image. This is especially useful if you're getting red-tinted images after inpainting/masking. - **Three GPU Memory Usage Settings** - `High` (fastest, maximum VRAM usage), `Balanced` (default - almost as fast, significantly lower VRAM usage), `Low` (slowest, very low VRAM usage). The `Low` setting is applied automatically for GPUs with less than 4 GB of VRAM. - **Find models in sub-folders** - This allows you to organize your models into sub-folders inside `models/stable-diffusion`, instead of keeping them all in a single folder. Thanks @patriceac and @ogmaresca. -- **Custom Modifier Categories** - Ability to create custom modifiers with thumbnails, and custom categories (and hierarchy of categories). Details: https://github.com/cmdr2/stable-diffusion-ui/wiki/Custom-Modifiers . Thanks @ogmaresca. +- **Custom Modifier Categories** - Ability to create custom modifiers with thumbnails, and custom categories (and hierarchy of categories). Details: https://github.com/easydiffusion/easydiffusion/wiki/Custom-Modifiers . Thanks @ogmaresca. - **Embed metadata, or save as TXT/JSON** - You can now embed the metadata directly into the images, or save them as text or json files (choose in the Settings tab). Thanks @patriceac. - **Major rewrite of the code** - Most of the codebase has been reorganized and rewritten, to make it more manageable and easier for new developers to contribute features. We've separated our core engine into a new project called `sdkit`, which allows anyone to easily integrate Stable Diffusion (and related modules like GFPGAN etc) into their programming projects (via a simple `pip install sdkit`): https://github.com/easydiffusion/sdkit/ - **Name change** - Last, and probably the least, the UI is now called "Easy Diffusion". It indicates the focus of this project - an easy way for people to play with Stable Diffusion. @@ -67,7 +67,7 @@ Our focus continues to remain on an easy installation experience, and an easy us * 2.5.24 - 11 Mar 2023 - Button to load an image mask from a file. * 2.5.24 - 10 Mar 2023 - Logo change. Image credit: @lazlo_vii. * 2.5.23 - 8 Mar 2023 - Experimental support for Mac M1/M2. Thanks @michaelgallacher, @JeLuf and vishae! -* 2.5.23 - 8 Mar 2023 - Ability to create custom modifiers with thumbnails, and custom categories (and hierarchy of categories). More details - https://github.com/cmdr2/stable-diffusion-ui/wiki/Custom-Modifiers . Thanks @ogmaresca. +* 2.5.23 - 8 Mar 2023 - Ability to create custom modifiers with thumbnails, and custom categories (and hierarchy of categories). More details - https://github.com/easydiffusion/easydiffusion/wiki/Custom-Modifiers . Thanks @ogmaresca. * 2.5.22 - 28 Feb 2023 - Minor styling changes to UI buttons, and the models dropdown. * 2.5.22 - 28 Feb 2023 - Lots of UI-related bug fixes. Thanks @patriceac. * 2.5.21 - 22 Feb 2023 - An option to control the size of the image thumbnails. You can use the `Display options` in the top-right corner to change this. Thanks @JeLuf. @@ -92,7 +92,7 @@ Our focus continues to remain on an easy installation experience, and an easy us * 2.5.14 - 3 Feb 2023 - Fix the 'Make Similar Images' button, which was producing incorrect images (weren't very similar). * 2.5.13 - 1 Feb 2023 - Fix the remaining GPU memory leaks, including a better fix (more comprehensive) for the change in 2.5.12 (27 Jan). * 2.5.12 - 27 Jan 2023 - Fix a memory leak, which made the UI unresponsive after an out-of-memory error. The allocated memory is now freed-up after an error. -* 2.5.11 - 25 Jan 2023 - UI for Merging Models. Thanks @JeLuf. More info: https://github.com/cmdr2/stable-diffusion-ui/wiki/Model-Merging +* 2.5.11 - 25 Jan 2023 - UI for Merging Models. Thanks @JeLuf. More info: https://github.com/easydiffusion/easydiffusion/wiki/Model-Merging * 2.5.10 - 24 Jan 2023 - Reduce the VRAM usage for img2img in 'balanced' mode (without reducing the rendering speed), to make it similar to v2.4 of this UI. * 2.5.9 - 23 Jan 2023 - Fix a bug where img2img would produce poorer-quality images for the same settings, as compared to version 2.4 of this UI. * 2.5.9 - 23 Jan 2023 - Reduce the VRAM usage for 'balanced' mode (without reducing the rendering speed), to make it similar to v2.4 of the UI. @@ -121,8 +121,8 @@ Our focus continues to remain on an easy installation experience, and an easy us - **Automatic scanning for malicious model files** - using `picklescan`, and support for `safetensor` model format. Thanks @JeLuf - **Image Editor** - for drawing simple images for guiding the AI. Thanks @mdiller - **Use pre-trained hypernetworks** - for improving the quality of images. Thanks @C0bra5 -- **Support for custom VAE models**. You can place your VAE files in the `models/vae` folder, and refresh the browser page to use them. More info: https://github.com/cmdr2/stable-diffusion-ui/wiki/VAE-Variational-Auto-Encoder -- **Experimental support for multiple GPUs!** It should work automatically. Just open one browser tab per GPU, and spread your tasks across your GPUs. For e.g. open our UI in two browser tabs if you have two GPUs. You can customize which GPUs it should use in the "Settings" tab, otherwise let it automatically pick the best GPUs. Thanks @madrang . More info: https://github.com/cmdr2/stable-diffusion-ui/wiki/Run-on-Multiple-GPUs +- **Support for custom VAE models**. You can place your VAE files in the `models/vae` folder, and refresh the browser page to use them. More info: https://github.com/easydiffusion/easydiffusion/wiki/VAE-Variational-Auto-Encoder +- **Experimental support for multiple GPUs!** It should work automatically. Just open one browser tab per GPU, and spread your tasks across your GPUs. For e.g. open our UI in two browser tabs if you have two GPUs. You can customize which GPUs it should use in the "Settings" tab, otherwise let it automatically pick the best GPUs. Thanks @madrang . More info: https://github.com/easydiffusion/easydiffusion/wiki/Run-on-Multiple-GPUs - **Cleaner UI design** - Show settings and help in new tabs, instead of dropdown popups (which were buggy). Thanks @mdiller - **Progress bar.** Thanks @mdiller - **Custom Image Modifiers** - You can now save your custom image modifiers! Your saved modifiers can include special characters like `{}, (), [], |` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c01d489a..bb6408c8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ Hi there, these instructions are meant for the developers of this project. -If you only want to use the Stable Diffusion UI, you've downloaded the wrong file. In that case, please download and follow the instructions at https://github.com/cmdr2/stable-diffusion-ui#installation +If you only want to use the Stable Diffusion UI, you've downloaded the wrong file. In that case, please download and follow the instructions at https://github.com/easydiffusion/easydiffusion#installation Thanks @@ -13,7 +13,7 @@ If you would like to contribute to this project, there is a discord for discussi This is in-flux, but one way to get a development environment running for editing the UI of this project is: (swap `.sh` or `.bat` in instructions depending on your environment, and be sure to adjust any paths to match where you're working) -1) Install the project to a new location using the [usual installation process](https://github.com/cmdr2/stable-diffusion-ui#installation), e.g. to `/projects/stable-diffusion-ui-archive` +1) Install the project to a new location using the [usual installation process](https://github.com/easydiffusion/easydiffusion#installation), e.g. to `/projects/stable-diffusion-ui-archive` 2) Start the newly installed project, and check that you can view and generate images on `localhost:9000` 3) Next, please clone the project repository using `git clone` (e.g. to `/projects/stable-diffusion-ui-repo`) 4) Close the server (started in step 2), and edit `/projects/stable-diffusion-ui-archive/scripts/on_env_start.sh` (or `on_env_start.bat`) diff --git a/How to install and run.txt b/How to install and run.txt index e48d217c..af783b64 100644 --- a/How to install and run.txt +++ b/How to install and run.txt @@ -1,6 +1,6 @@ Congrats on downloading Stable Diffusion UI, version 2! -If you haven't downloaded Stable Diffusion UI yet, please download from https://github.com/cmdr2/stable-diffusion-ui#installation +If you haven't downloaded Stable Diffusion UI yet, please download from https://github.com/easydiffusion/easydiffusion#installation After downloading, to install please follow these instructions: @@ -16,9 +16,9 @@ To start the UI in the future, please run the same command mentioned above. If you have any problems, please: -1. Try the troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting +1. Try the troubleshooting steps at https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting 2. Or, seek help from the community at https://discord.com/invite/u9yhsFmEkB -3. Or, file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues +3. Or, file an issue at https://github.com/easydiffusion/easydiffusion/issues Thanks cmdr2 (and contributors to the project) \ No newline at end of file diff --git a/PRIVACY.md b/PRIVACY.md index 6c997997..543a167d 100644 --- a/PRIVACY.md +++ b/PRIVACY.md @@ -3,7 +3,7 @@ This is a summary of whether Easy Diffusion uses your data or tracks you: * The short answer is - Easy Diffusion does *not* use your data, and does *not* track you. * Easy Diffusion does not send your prompts or usage or analytics to anyone. There is no tracking. We don't even know how many people use Easy Diffusion, let alone their prompts. -* Easy Diffusion fetches updates to the code whenever it starts up. It does this by contacting GitHub directly, via SSL (secure connection). Only your computer and GitHub and [this repository](https://github.com/cmdr2/stable-diffusion-ui) are involved, and no third party is involved. Some countries intercepts SSL connections, that's not something we can do much about. GitHub does *not* share statistics (even with me) about how many people fetched code updates. +* Easy Diffusion fetches updates to the code whenever it starts up. It does this by contacting GitHub directly, via SSL (secure connection). Only your computer and GitHub and [this repository](https://github.com/easydiffusion/easydiffusion) are involved, and no third party is involved. Some countries intercepts SSL connections, that's not something we can do much about. GitHub does *not* share statistics (even with me) about how many people fetched code updates. * Easy Diffusion fetches the models from huggingface.co and github.com, if they don't exist on your PC. For e.g. if the safety checker (NSFW) model doesn't exist, it'll try to download it. * Easy Diffusion fetches code packages from pypi.org, which is the standard hosting service for all Python projects. That's where packages installed via `pip install` are stored. * Occasionally, antivirus software are known to *incorrectly* flag and delete some model files, which will result in Easy Diffusion re-downloading `pytorch_model.bin`. This *incorrect deletion* affects other Stable Diffusion UIs as well, like Invoke AI - https://itch.io/post/7509488 diff --git a/README BEFORE YOU RUN THIS.txt b/README BEFORE YOU RUN THIS.txt index e9f81544..a989b835 100644 --- a/README BEFORE YOU RUN THIS.txt +++ b/README BEFORE YOU RUN THIS.txt @@ -3,6 +3,6 @@ Hi there, What you have downloaded is meant for the developers of this project, not for users. If you only want to use the Stable Diffusion UI, you've downloaded the wrong file. -Please download and follow the instructions at https://github.com/cmdr2/stable-diffusion-ui#installation +Please download and follow the instructions at https://github.com/easydiffusion/easydiffusion#installation Thanks \ No newline at end of file diff --git a/README.md b/README.md index 5366772f..b97c35d1 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Does not require technical knowledge, does not require pre-installed software. 1-click install, powerful features, friendly community. -[Installation guide](#installation) | [Troubleshooting guide](https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting) | [![Discord Server](https://img.shields.io/discord/1014774730907209781?label=Discord)](https://discord.com/invite/u9yhsFmEkB) (for support queries, and development discussions) +[Installation guide](#installation) | [Troubleshooting guide](https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting) | [![Discord Server](https://img.shields.io/discord/1014774730907209781?label=Discord)](https://discord.com/invite/u9yhsFmEkB) (for support queries, and development discussions) ![t2i](https://raw.githubusercontent.com/Stability-AI/stablediffusion/main/assets/stable-samples/txt2img/768/merged-0006.png) @@ -11,9 +11,9 @@ Does not require technical knowledge, does not require pre-installed software. 1 Click the download button for your operating system:

    - - - + + +

    **Hardware requirements:** @@ -83,7 +83,7 @@ Just delete the `EasyDiffusion` folder to uninstall all the downloaded packages. - **Use custom VAE models** - **Use pre-trained Hypernetworks** - **Use custom GFPGAN models** -- **UI Plugins**: Choose from a growing list of [community-generated UI plugins](https://github.com/cmdr2/stable-diffusion-ui/wiki/UI-Plugins), or write your own plugin to add features to the project! +- **UI Plugins**: Choose from a growing list of [community-generated UI plugins](https://github.com/easydiffusion/easydiffusion/wiki/UI-Plugins), or write your own plugin to add features to the project! ### Performance and security - **Fast**: Creates a 512x512 image with euler_a in 5 seconds, on an NVIDIA 3060 12GB. @@ -119,10 +119,10 @@ Useful for judging (and stopping) an image quickly, without waiting for it to fi ---- # How to use? -Please refer to our [guide](https://github.com/cmdr2/stable-diffusion-ui/wiki/How-to-Use) to understand how to use the features in this UI. +Please refer to our [guide](https://github.com/easydiffusion/easydiffusion/wiki/How-to-Use) to understand how to use the features in this UI. # Bugs reports and code contributions welcome -If there are any problems or suggestions, please feel free to ask on the [discord server](https://discord.com/invite/u9yhsFmEkB) or [file an issue](https://github.com/cmdr2/stable-diffusion-ui/issues). +If there are any problems or suggestions, please feel free to ask on the [discord server](https://discord.com/invite/u9yhsFmEkB) or [file an issue](https://github.com/easydiffusion/easydiffusion/issues). We could really use help on these aspects (click to view tasks that need your help): * [User Interface](https://github.com/users/cmdr2/projects/1/views/1) diff --git a/build.bat b/build.bat index 6e3f3f81..dc9e622f 100644 --- a/build.bat +++ b/build.bat @@ -2,7 +2,7 @@ @echo "Hi there, what you are running is meant for the developers of this project, not for users." & echo. @echo "If you only want to use the Stable Diffusion UI, you've downloaded the wrong file." -@echo "Please download and follow the instructions at https://github.com/cmdr2/stable-diffusion-ui#installation" & echo. +@echo "Please download and follow the instructions at https://github.com/easydiffusion/easydiffusion#installation" & echo. @echo "If you are actually a developer of this project, please type Y and press enter" & echo. set /p answer=Are you a developer of this project (Y/N)? diff --git a/build.sh b/build.sh index f4538e5c..bddf3c49 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ printf "Hi there, what you are running is meant for the developers of this project, not for users.\n\n" printf "If you only want to use the Stable Diffusion UI, you've downloaded the wrong file.\n" -printf "Please download and follow the instructions at https://github.com/cmdr2/stable-diffusion-ui#installation\n\n" +printf "Please download and follow the instructions at https://github.com/easydiffusion/easydiffusion#installation \n\n" printf "If you are actually a developer of this project, please type Y and press enter\n\n" read -p "Are you a developer of this project (Y/N) " yn diff --git a/scripts/bootstrap.bat b/scripts/bootstrap.bat index d3cdd19f..8c1069c8 100644 --- a/scripts/bootstrap.bat +++ b/scripts/bootstrap.bat @@ -11,7 +11,7 @@ setlocal enabledelayedexpansion set MAMBA_ROOT_PREFIX=%cd%\installer_files\mamba set INSTALL_ENV_DIR=%cd%\installer_files\env set LEGACY_INSTALL_ENV_DIR=%cd%\installer -set MICROMAMBA_DOWNLOAD_URL=https://github.com/cmdr2/stable-diffusion-ui/releases/download/v1.1/micromamba.exe +set MICROMAMBA_DOWNLOAD_URL=https://github.com/easydiffusion/easydiffusion/releases/download/v1.1/micromamba.exe set umamba_exists=F set OLD_APPDATA=%APPDATA% diff --git a/scripts/check_modules.py b/scripts/check_modules.py index 6275de45..5f1a9bb8 100644 --- a/scripts/check_modules.py +++ b/scripts/check_modules.py @@ -148,9 +148,9 @@ def fail(module_name): print( f"""Error installing {module_name}. Sorry about that, please try to: 1. Run this installer again. -2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting +2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB -4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues +4. If that doesn't solve the problem, please file an issue at https://github.com/easydiffusion/easydiffusion/issues Thanks!""" ) exit(1) diff --git a/scripts/functions.sh b/scripts/functions.sh index 495e9950..477b7743 100644 --- a/scripts/functions.sh +++ b/scripts/functions.sh @@ -15,9 +15,9 @@ fail() { Error downloading Stable Diffusion UI. Sorry about that, please try to: 1. Run this installer again. - 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting + 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB - 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues + 4. If that doesn't solve the problem, please file an issue at https://github.com/easydiffusion/easydiffusion/issues Thanks! diff --git a/scripts/on_env_start.bat b/scripts/on_env_start.bat index bc92d0e9..0871973f 100644 --- a/scripts/on_env_start.bat +++ b/scripts/on_env_start.bat @@ -55,10 +55,10 @@ if "%update_branch%"=="" ( @echo. & echo "Downloading Easy Diffusion..." & echo. @echo "Using the %update_branch% channel" & echo. - @call git clone -b "%update_branch%" https://github.com/cmdr2/stable-diffusion-ui.git sd-ui-files && ( + @call git clone -b "%update_branch%" https://github.com/easydiffusion/easydiffusion.git sd-ui-files && ( @echo sd_ui_git_cloned >> scripts\install_status.txt ) || ( - @echo "Error downloading Easy Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" + @echo "Error downloading Easy Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/easydiffusion/easydiffusion/issues" & echo "Thanks!" pause @exit /b ) diff --git a/scripts/on_env_start.sh b/scripts/on_env_start.sh index 366b5dd1..d936924e 100755 --- a/scripts/on_env_start.sh +++ b/scripts/on_env_start.sh @@ -38,7 +38,7 @@ else printf "\n\nDownloading Easy Diffusion..\n\n" printf "Using the $update_branch channel\n\n" - if git clone -b "$update_branch" https://github.com/cmdr2/stable-diffusion-ui.git sd-ui-files ; then + if git clone -b "$update_branch" https://github.com/easydiffusion/easydiffusion.git sd-ui-files ; then echo sd_ui_git_cloned >> scripts/install_status.txt else fail "git clone failed" diff --git a/scripts/on_sd_start.bat b/scripts/on_sd_start.bat index f92b9f6f..860361d4 100644 --- a/scripts/on_sd_start.bat +++ b/scripts/on_sd_start.bat @@ -26,7 +26,7 @@ if exist "%cd%\stable-diffusion\env" ( @rem activate the installer env call conda activate @if "%ERRORLEVEL%" NEQ "0" ( - @echo. & echo "Error activating conda for Easy Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo. + @echo. & echo "Error activating conda for Easy Diffusion. Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/easydiffusion/easydiffusion/issues" & echo "Thanks!" & echo. pause exit /b ) @@ -68,7 +68,7 @@ if "%ERRORLEVEL%" NEQ "0" ( call WHERE uvicorn > .tmp @>nul findstr /m "uvicorn" .tmp @if "%ERRORLEVEL%" NEQ "0" ( - @echo. & echo "UI packages not found! Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/cmdr2/stable-diffusion-ui/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues" & echo "Thanks!" & echo. + @echo. & echo "UI packages not found! Sorry about that, please try to:" & echo " 1. Run this installer again." & echo " 2. If that doesn't fix it, please try the common troubleshooting steps at https://github.com/easydiffusion/easydiffusion/wiki/Troubleshooting" & echo " 3. If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB" & echo " 4. If that doesn't solve the problem, please file an issue at https://github.com/easydiffusion/easydiffusion/issues" & echo "Thanks!" & echo. pause exit /b ) diff --git a/ui/easydiffusion/app.py b/ui/easydiffusion/app.py index 38e3392c..99810e75 100644 --- a/ui/easydiffusion/app.py +++ b/ui/easydiffusion/app.py @@ -237,7 +237,7 @@ def fail_and_die(fail_type: str, data: str): suggestions = [ "Run this installer again.", "If those steps don't help, please copy *all* the error messages in this window, and ask the community at https://discord.com/invite/u9yhsFmEkB", - "If that doesn't solve the problem, please file an issue at https://github.com/cmdr2/stable-diffusion-ui/issues", + "If that doesn't solve the problem, please file an issue at https://github.com/easydiffusion/easydiffusion/issues", ] if fail_type == "model_download": diff --git a/ui/index.html b/ui/index.html index 0c4386de..2afdfd84 100644 --- a/ui/index.html +++ b/ui/index.html @@ -60,7 +60,7 @@
    @@ -133,18 +133,18 @@ - Click to learn more about custom models + Click to learn more about custom models - Click to learn more about Clip Skip + Click to learn more about Clip Skip - Click to learn more about VAEs + Click to learn more about VAEs - Click to learn more about samplers + Click to learn more about samplers - Click to learn more about Seamless Tiling + Click to learn more about Seamless Tiling
    +
    +
    +
    +

    Image Modifiers

    + (drawing style, camera, etc.) +
    +
    + + + Add Custom Modifiers + + + + +
    +
    +
    +
    + + + Expand Categories + +
    +
    +
    +
    @@ -102,7 +132,7 @@
    - +
    @@ -293,29 +323,6 @@
    - -
    -

    - Image Modifiers (art styles, tags etc) - - - Add Custom Modifiers - - -

    -
    -
    - - -   - - -
    -
    -
    @@ -475,6 +482,16 @@

    Set your custom modifiers (one per line)

    Tip: You can include special characters like {} () [] and |. You can also put multiple comma-separated phrases in a single line, to make a single modifier that combines all of those.

    +
    + + +   + + +
    diff --git a/ui/media/css/main.css b/ui/media/css/main.css index 9df38f9a..af4c152e 100644 --- a/ui/media/css/main.css +++ b/ui/media/css/main.css @@ -211,10 +211,6 @@ code { #makeImage { border-radius: 6px; } -#editor-modifiers h5 { - padding: 5pt 0; - margin: 0; -} #makeImage { flex: 0 0 70px; background: var(--accent-color); @@ -284,14 +280,193 @@ button#resume { .collapsible:not(.active) ~ .collapsible-content { display: none !important; } +#image-modifier-dropdown { + margin-left: 1em; + position: relative; + cursor: pointer; +} +#image-modifier-dropdown[data-active="true"]::before { + content: "➖"; +} +#image-modifier-dropdown[data-active="false"]::before { + content: "➕"; +} #editor-modifiers { - overflow-y: auto; + max-width: 75vw; + min-width: 50vw; + max-height: fit-content; + overflow-y: hidden; overflow-x: hidden; + display: none; + background: var(--background-color1); + border: solid 1px var(--background-color3); + z-index: 999; + border-radius: 6px; + box-shadow: 0px 0px 30px black; + border: 2px solid rgb(255 255 255 / 10%); +} +#editor-modifiers.active { + display: flex; + flex-direction: column; + position: absolute; + left: 5vw; +} +.modifiers-maximized { + position: fixed !important; + top: 0 !important; + bottom: 0px !important; + left: 0px !important; + right: 0px !important; + max-width: unset !important; + max-height: unset !important; + border: 0px !important; + border-radius: 0px !important; +} +.modifiers-maximized #editor-modifiers-entries { + max-height: 100%; + flex: 1; +} +#editor-modifiers-header { + background-color: var(--background-color4); + padding: 0.5em; + border-bottom: 1px solid rgb(255 255 255 / 10%); + display: flex; + justify-content: space-between; + align-items: center; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +#editor-modifiers-subheader { + background-color: var(--background-color4); + padding: 0.5em; + border-bottom: 1px solid rgb(255 255 255 / 10%); + display: flex; + align-items: center; + grid-gap: 0.8em; + flex-direction: row; + position: relative; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + transition: all 0.1s ease; +} +#editor-modifiers-subheader::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(255, 255, 255, 0.02); + opacity: 1; + pointer-events: none; +} +#modifiers-header-left { + display: flex; + flex-direction: column; + grid-gap: 0.1em; +} +#modifiers-header-left span { + font-size: 0.8em; + color: rgb(127 127 127); + font-weight: 200; +} +#modifiers-header-right { + display: flex; + align-items: center; + align-content: center; + justify-content: center; + grid-gap: 0.8em; + margin-right: 0.3em; +} + +#editor-modifiers-subheader i, +#modifiers-header-right i { + cursor: pointer; + margin: 0; + padding: 0; +} +#modifiers-header-right .section-button, +#editor-modifiers-subheader .section-button { + margin-top: 0.3em; +} +#modifiers-action-collapsibles-btn { + display: flex; + grid-gap: 0.5em; + cursor: pointer; +} +.modifiers-action-text { + font-size: 0.8em; + color: rgb(192 192 192); +} +#modifiers-expand-btn { + z-index: 2; +} +#modifiers-expand-btn .simple-tooltip { + background-color: var(--background-color3); + border-radius: 50px; +} +.modifier-category .collapsible { + position: relative; +} +.modifier-category .collapsible::after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(255, 255, 255, 0.1); + opacity: 0; + transition: opacity 0.1s ease; + pointer-events: none; +} +.modifier-category:hover .collapsible::after { + opacity: 1; + pointer-events: none; +} +#editor-modifiers-entries { + overflow: auto scroll; + max-height: 50vh; + height: fit-content; + margin-bottom: 0.1em; + padding-left: 0px; +} +#editor-modifiers-entries .collapsible { + transition: opacity 0.1s ease; + padding-left: 0.5em; +} +#editor-modifiers-entries .modifier-category:nth-child(odd) .collapsible::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(255, 255, 255, 0.02); + opacity: 1; + pointer-events: none; } #editor-modifiers .editor-modifiers-leaf { padding-top: 10pt; padding-bottom: 10pt; } +#editor-modifiers h5 { + padding: 5pt 0; + margin: 0; + position: sticky; + top: -2px; + z-index: 10; + background-color: var(--background-color3); + border-bottom: 1px solid rgb(255 255 255 / 4%); + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} img { box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.15), 0 6px 20px 0 rgba(0, 0, 0, 0.15); } @@ -310,6 +485,9 @@ div.img-preview img { margin-top: 5pt; display: none; } +#editor-inputs-tags-list { + max-height: 30em; +} #server-status { position: absolute; right: 16px; @@ -779,7 +957,6 @@ input::file-selector-button { height: 19px; } - .input-toggle { display: inline-block; position: relative; @@ -1083,6 +1260,7 @@ input::file-selector-button { /* POPUPS */ .popup:not(.active) { visibility: hidden; + overflow-x: hidden; /* fix overflow from body */ opacity: 0; } diff --git a/ui/media/css/modifier-thumbnails.css b/ui/media/css/modifier-thumbnails.css index c6fb8107..02b91fce 100644 --- a/ui/media/css/modifier-thumbnails.css +++ b/ui/media/css/modifier-thumbnails.css @@ -1,14 +1,16 @@ .modifier-card { + position: relative; + box-sizing: content-box; /* fixes border misalignment */ box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); transition: 0.1s; border-radius: 7px; margin: 3pt 3pt; float: left; - width: 8em; - height: 11.5em; + width: 6em; + height: 9.5em; display: grid; grid-template-columns: 1fr; - grid-template-rows: 8em 3.5em; + grid-template-rows: 6em 3.5em; gap: 0px 0px; grid-auto-flow: row; grid-template-areas: @@ -16,82 +18,71 @@ "modifier-card-container"; border: 2px solid rgba(255, 255, 255, .05); cursor: pointer; -} -.modifier-card-size_5 { - width: 18em; - grid-template-rows: 18em 3.5em; - height: 21.5em; -} -.modifier-card-size_5 .modifier-card-image-overlay { - font-size: 8em; -} -.modifier-card-size_4 { - width: 14em; - grid-template-rows: 14em 3.5em; - height: 17.5em; -} -.modifier-card-size_4 .modifier-card-image-overlay { - font-size: 7em; + z-index: 2; } .modifier-card-size_3 { - width: 11em; - grid-template-rows: 11em 3.5em; - height: 14.5em; -} -.modifier-card-size_3 .modifier-card-image-overlay { - font-size: 6em; -} -.modifier-card-size_2 { width: 10em; grid-template-rows: 10em 3.5em; height: 13.5em; } -.modifier-card-size_2 .modifier-card-image-overlay { +.modifier-card-size_3 .modifier-card-image-overlay { font-size: 6em; } -.modifier-card-size_1 { +.modifier-card-size_3 .modifier-card-label { + font-size: 1.2em; +} +.modifier-card-size_2 { width: 9em; grid-template-rows: 9em 3.5em; height: 12.5em; } -.modifier-card-size_1 .modifier-card-image-overlay { +.modifier-card-size_2 .modifier-card-image-overlay { font-size: 5em; } -.modifier-card-size_-1 { +.modifier-card-size_2 .modifier-card-label { + font-size: 1.1em; +} +.modifier-card-size_1 { width: 7em; grid-template-rows: 7em 3.5em; height: 10.5em; } -.modifier-card-size_-1 .modifier-card-image-overlay { +.modifier-card-size_1 .modifier-card-image-overlay { font-size: 4em; } -.modifier-card-size_-2 { - width: 6em; - grid-template-rows: 6em 3.5em; - height: 9.5em; -} -.modifier-card-size_-2 .modifier-card-image-overlay { - font-size: 3em; -} -.modifier-card-size_-3 { +.modifier-card-size_-1 { width: 5em; grid-template-rows: 5em 3.5em; height: 8.5em; } -.modifier-card-size_-3 .modifier-card-image-overlay { +.modifier-card-size_-1 .modifier-card-image-overlay { font-size: 3em; } -.modifier-card-size_-3 .modifier-card-label { - font-size: 0.8em; +.modifier-card-size_-1 .modifier-card-label { + font-size: 0.9em; +} +.modifier-card-size_-2 { + width: 4em; + grid-template-rows: 3.5em 3em; + height: 6.5em; +} +.modifier-card-size_-2 .modifier-card-image-overlay { + font-size: 2em; +} +.modifier-card-size_-2 .modifier-card-label { + font-size: 0.7em; } .modifier-card-tiny { - width: 6em; - height: 9.5em; - grid-template-rows: 6em 3.5em; + width: 5em; + grid-template-rows: 5em 3.5em; + height: 8.5em; } .modifier-card-tiny .modifier-card-image-overlay { font-size: 4em; } +.modifier-card-tiny .modifier-card-label { + font-size: 0.9em; +} .modifier-card:hover { transform: scale(1.05); box-shadow: 0 5px 16px 5px rgba(0, 0, 0, 0.25); @@ -115,6 +106,7 @@ } .modifier-card-image-container * { position: absolute; + text-align: center; } .modifier-card-container { text-align: center; @@ -131,6 +123,7 @@ .modifier-card-label { padding: 4px; word-break: break-word; + text-transform: capitalize; } .modifier-card-image-overlay { width: inherit; @@ -140,7 +133,7 @@ position: absolute; border-radius: 5px 5px 0 0; opacity: 0; - font-size: 5em; + font-size: 4em; font-weight: 900; color: rgb(255 255 255 / 50%); display: flex; @@ -153,9 +146,8 @@ position: absolute; z-index: 3; } -.modifier-card-overlay:hover ~ .modifier-card-container .modifier-card-label.tooltip .tooltip-text { - visibility: visible; - opacity: 1; +.modifier-card-active .modifier-card-overlay { + background-color: rgb(169 78 241 / 40%); } .modifier-card:hover > .modifier-card-image-container .modifier-card-image-overlay { opacity: 1; @@ -175,53 +167,24 @@ border: 2px solid rgb(179 82 255 / 94%); box-shadow: 0 0px 10px 0 rgb(170 0 229 / 58%); } -.tooltip { - position: relative; - display: inline-block; -} -.tooltip .tooltip-text { - visibility: hidden; - width: 120px; - background: rgb(101,97,181); - background: linear-gradient(180deg, rgba(101,97,181,1) 0%, rgba(47,45,85,1) 100%); - color: #fff; - text-align: center; - border-radius: 6px; - padding: 5px; - position: absolute; - z-index: 1; - top: 105%; - left: 39%; - margin-left: -60px; - opacity: 0; - transition: opacity 0.3s; - border: 2px solid rgb(90 100 177 / 94%); - box-shadow: 0px 10px 20px 5px rgb(11 0 58 / 55%); - width: 10em; -} -.tooltip .tooltip-text::after { - content: ""; - position: absolute; - top: -0.9em; - left: 50%; - margin-left: -5px; - border-width: 5px; - border-style: solid; - border-color: transparent transparent rgb(90 100 177 / 94%) transparent; -} -.tooltip:hover .tooltip-text { - visibility: visible; - opacity: 1; -} #modifier-card-size-slider { width: 6em; margin-bottom: 0.5em; vertical-align: middle; } -#modifier-settings-btn { - float: right; -} #modifier-settings-config textarea { width: 90%; height: 150px; } +.modifier-card .hidden { + display: none; +} +.support-long-label .modifier-card-overlay:hover ~ .modifier-card-container .modifier-card-label { + font-size: 0.7em; +} +.support-long-label .modifier-card-overlay:hover ~ .modifier-card-container .long-label { + display: block; +} +.support-long-label .modifier-card-overlay:hover ~ .modifier-card-container .regular-label { + display: none; +} \ No newline at end of file diff --git a/ui/media/js/image-modifiers.js b/ui/media/js/image-modifiers.js index 69f31ab1..5f3a9014 100644 --- a/ui/media/js/image-modifiers.js +++ b/ui/media/js/image-modifiers.js @@ -1,14 +1,21 @@ let activeTags = [] let modifiers = [] let customModifiersGroupElement = undefined -let customModifiersInitialContent +let customModifiersInitialContent = "" +let modifierPanelFreezed = false +let modifiersMainContainer = document.querySelector("#editor-modifiers") +let modifierDropdown = document.querySelector("#image-modifier-dropdown") +let editorModifiersContainer = document.querySelector("#editor-modifiers") let editorModifierEntries = document.querySelector("#editor-modifiers-entries") let editorModifierTagsList = document.querySelector("#editor-inputs-tags-list") let editorTagsContainer = document.querySelector("#editor-inputs-tags-container") let modifierCardSizeSlider = document.querySelector("#modifier-card-size-slider") let previewImageField = document.querySelector("#preview-image") let modifierSettingsBtn = document.querySelector("#modifier-settings-btn") +let modifiersContainerSizeBtn = document.querySelector("#modifiers-container-size-btn") +let modifiersCloseBtn = document.querySelector("#modifiers-close-button") +let modifiersCollapsiblesBtn = document.querySelector("#modifiers-action-collapsibles-btn") let modifierSettingsOverlay = document.querySelector("#modifier-settings-config") let customModifiersTextBox = document.querySelector("#custom-modifiers-input") let customModifierEntriesToolbar = document.querySelector("#editor-modifiers-entries-toolbar") @@ -18,31 +25,31 @@ const activeCardClass = "modifier-card-active" const CUSTOM_MODIFIERS_KEY = "customModifiers" function createModifierCard(name, previews, removeBy) { - const modifierCard = document.createElement("div") - let style = previewImageField.value - let styleIndex = style == "portrait" ? 0 : 1 + let cardPreviewImageType = previewImageField.value + const modifierCard = document.createElement("div") modifierCard.className = "modifier-card" modifierCard.innerHTML = `
    +
    -

    +

    No Image

    Modifier Image
    -

    +
    + +

    +
    ` const image = modifierCard.querySelector(".modifier-card-image") - const errorText = modifierCard.querySelector(".modifier-card-error-label") - const label = modifierCard.querySelector(".modifier-card-label") - - errorText.innerText = "No Image" + const longLabel = modifierCard.querySelector(".modifier-card-label span.long-label") + const regularLabel = modifierCard.querySelector(".modifier-card-label p.regular-label") if (typeof previews == "object") { - image.src = previews[styleIndex] // portrait - image.setAttribute("preview-type", style) + image.src = previews[cardPreviewImageType == "portrait" ? 0 : 1] // 0 index is portrait, 1 landscape + image.setAttribute("preview-type", cardPreviewImageType) } else { image.remove() } @@ -50,24 +57,32 @@ function createModifierCard(name, previews, removeBy) { const maxLabelLength = 30 const cardLabel = removeBy ? name.replace("by ", "") : name - if (cardLabel.length <= maxLabelLength) { - label.querySelector("p").innerText = cardLabel - } else { - const tooltipText = document.createElement("span") - tooltipText.className = "tooltip-text" - tooltipText.innerText = name - - label.classList.add("tooltip") - label.appendChild(tooltipText) - - label.querySelector("p").innerText = cardLabel.substring(0, maxLabelLength) + "..." + function getFormattedLabel(length) { + if (cardLabel?.length <= length) { + return cardLabel + } else { + return cardLabel.substring(0, length) + "..." + } } - label.querySelector("p").dataset.fullName = name // preserve the full name + modifierCard.dataset.fullName = name // preserve the full name + regularLabel.dataset.fullName = name // preserve the full name, legacy support for older plugins + + longLabel.innerText = getFormattedLabel(maxLabelLength * 2) + regularLabel.innerText = getFormattedLabel(maxLabelLength) + + if (cardLabel.length > maxLabelLength) { + modifierCard.classList.add("support-long-label") + + if (cardLabel.length > maxLabelLength * 2) { + modifierCard.title = `"${name}"` + } + } + return modifierCard } -function createModifierGroup(modifierGroup, initiallyExpanded, removeBy) { +function createModifierGroup(modifierGroup, isInitiallyOpen, removeBy) { const title = modifierGroup.category const modifiers = modifierGroup.modifiers @@ -78,8 +93,8 @@ function createModifierGroup(modifierGroup, initiallyExpanded, removeBy) { const modifiersEl = document.createElement("div") modifiersEl.classList.add("collapsible-content", "editor-modifiers-leaf") - if (initiallyExpanded === true) { - titleEl.className += " active" + if (isInitiallyOpen === true) { + titleEl.classList.add("active") } modifiers.forEach((modObj) => { @@ -126,7 +141,7 @@ function createModifierGroup(modifierGroup, initiallyExpanded, removeBy) { e.appendChild(titleEl) e.appendChild(modifiersEl) - editorModifierEntries.insertBefore(e, customModifierEntriesToolbar.nextSibling) + editorModifierEntries.prepend(e) return e } @@ -149,7 +164,10 @@ async function loadModifiers() { res.reverse() res.forEach((modifierGroup, idx) => { - createModifierGroup(modifierGroup, idx === res.length - 1, modifierGroup === "Artist" ? true : false) // only remove "By " for artists + const isInitiallyOpen = false // idx === res.length - 1 + const removeBy = modifierGroup === "Artist" ? true : false // only remove "By " for artists + + createModifierGroup(modifierGroup, isInitiallyOpen, removeBy) }) createCollapsibles(editorModifierEntries) @@ -169,7 +187,7 @@ function refreshModifiersState(newTags, inactiveTags) { .querySelector("#editor-modifiers") .querySelectorAll(".modifier-card") .forEach((modifierCard) => { - const modifierName = modifierCard.querySelector(".modifier-card-label p").dataset.fullName // pick the full modifier name + const modifierName = modifierCard.dataset.fullName // pick the full modifier name if (activeTags.map((x) => x.name).includes(modifierName)) { modifierCard.classList.remove(activeCardClass) modifierCard.querySelector(".modifier-card-image-overlay").innerText = "+" @@ -184,8 +202,9 @@ function refreshModifiersState(newTags, inactiveTags) { .querySelector("#editor-modifiers") .querySelectorAll(".modifier-card") .forEach((modifierCard) => { - const modifierName = modifierCard.querySelector(".modifier-card-label p").dataset.fullName + const modifierName = modifierCard.dataset.fullName const shortModifierName = modifierCard.querySelector(".modifier-card-label p").innerText + if (trimModifiers(tag) == trimModifiers(modifierName)) { // add modifier to active array if (!activeTags.map((x) => x.name).includes(tag)) { @@ -242,10 +261,10 @@ function refreshInactiveTags(inactiveTags) { } // update cards - let overlays = document.querySelector("#editor-inputs-tags-list").querySelectorAll(".modifier-card-overlay") + let overlays = editorModifierTagsList.querySelectorAll(".modifier-card-overlay") overlays.forEach((i) => { - let modifierName = i.parentElement.getElementsByClassName("modifier-card-label")[0].getElementsByTagName("p")[0] - .dataset.fullName + let modifierName = i.parentElement.dataset.fullName + if (inactiveTags?.find((element) => trimModifiers(element) === modifierName) !== undefined) { i.parentElement.classList.add("modifier-toggle-inactive") } @@ -262,6 +281,12 @@ function refreshTagsList(inactiveTags) { editorTagsContainer.style.display = "block" } + if(activeTags.length > 15) { + editorModifierTagsList.style["overflow-y"] = "auto" + } else { + editorModifierTagsList.style["overflow-y"] = "unset" + } + activeTags.forEach((tag, index) => { tag.element.querySelector(".modifier-card-image-overlay").innerText = "-" tag.element.classList.add("modifier-card-tiny") @@ -285,48 +310,42 @@ function refreshTagsList(inactiveTags) { let brk = document.createElement("br") brk.style.clear = "both" + editorModifierTagsList.appendChild(brk) + refreshInactiveTags(inactiveTags) + document.dispatchEvent(new Event("refreshImageModifiers")) // notify plugins that the image tags have been refreshed } function toggleCardState(modifierName, makeActive) { - document - .querySelector("#editor-modifiers") - .querySelectorAll(".modifier-card") - .forEach((card) => { - const name = card.querySelector(".modifier-card-label").innerText - if ( - trimModifiers(modifierName) == trimModifiers(name) || - trimModifiers(modifierName) == "by " + trimModifiers(name) - ) { - if (makeActive) { - card.classList.add(activeCardClass) - card.querySelector(".modifier-card-image-overlay").innerText = "-" - } else { - card.classList.remove(activeCardClass) - card.querySelector(".modifier-card-image-overlay").innerText = "+" - } - } - }) + const cards = [...document.querySelectorAll("#editor-modifiers .modifier-card")] + .filter(cardElem => trimModifiers(cardElem.dataset.fullName) == trimModifiers(modifierName)) + + const cardExists = typeof cards == "object" && cards?.length > 0 + + if (cardExists) { + const card = cards[0] + + if (makeActive) { + card.classList.add(activeCardClass) + card.querySelector(".modifier-card-image-overlay").innerText = "-" + } else { + card.classList.remove(activeCardClass) + card.querySelector(".modifier-card-image-overlay").innerText = "+" + } + } } function changePreviewImages(val) { const previewImages = document.querySelectorAll(".modifier-card-image-container img") - let previewArr = [] - - modifiers.map((x) => x.modifiers).forEach((x) => previewArr.push(...x.map((m) => m.previews))) - - previewArr = previewArr.map((x) => { - let obj = {} - - x.forEach((preview) => { + const previewArr = modifiers.flatMap((x) => x.modifiers.map((m) => m.previews)) + .map((x) => x.reduce((obj, preview) => { obj[preview.name] = preview.path - }) - return obj - }) + return obj + }, {})) previewImages.forEach((previewImage) => { const currentPreviewType = previewImage.getAttribute("preview-type") @@ -369,17 +388,70 @@ function resizeModifierCards(val) { }) } +function saveCustomModifiers() { + localStorage.setItem(CUSTOM_MODIFIERS_KEY, customModifiersTextBox.value.trim()) + + loadCustomModifiers() +} + +function loadCustomModifiers() { + PLUGINS["MODIFIERS_LOAD"].forEach((fn) => fn.loader.call()) +} + +function showModifierContainer() { + document.addEventListener("click", checkIfClickedOutsideDropdownElem) + + modifierDropdown.dataset.active = true + editorModifiersContainer.classList.add("active") +} + +function hideModifierContainer() { + document.removeEventListener("click", checkIfClickedOutsideDropdownElem) + + modifierDropdown.dataset.active = false + editorModifiersContainer.classList.remove("active") +} + +function checkIfClickedOutsideDropdownElem(e) { + const clickedElement = e.target + + const clickedInsideSpecificElems = [modifierDropdown, editorModifiersContainer, modifierSettingsOverlay].some((div) => + div && (div.contains(clickedElement) || div === clickedElement)) + + if (!clickedInsideSpecificElems && !modifierPanelFreezed) { + hideModifierContainer() + } +} + +function collapseAllModifierCategory() { + const collapsibleElems = editorModifierEntries.querySelectorAll(".modifier-category .collapsible"); // needs to have ";" + + [...collapsibleElems].forEach((elem) => { + const isActive = elem.classList.contains("active") + + if(isActive) { + elem?.click() + } + }) +} + +function expandAllModifierCategory() { + const collapsibleElems = editorModifierEntries.querySelectorAll(".modifier-category .collapsible"); // needs to have ";" + + [...collapsibleElems].forEach((elem) => { + const isActive = elem.classList.contains("active") + + if (!isActive) { + elem?.click() + } + }) +} + +customModifiersTextBox.addEventListener("change", saveCustomModifiers) + modifierCardSizeSlider.onchange = () => resizeModifierCards(modifierCardSizeSlider.value) previewImageField.onchange = () => changePreviewImages(previewImageField.value) -modifierSettingsBtn.addEventListener("click", function(e) { - modifierSettingsOverlay.classList.add("active") - customModifiersTextBox.setSelectionRange(0, 0) - customModifiersTextBox.focus() - customModifiersInitialContent = customModifiersTextBox.value // preserve the initial content - e.stopPropagation() -}) - modifierSettingsOverlay.addEventListener("keydown", function(e) { switch (e.key) { case "Escape": // Escape to cancel @@ -397,14 +469,93 @@ modifierSettingsOverlay.addEventListener("keydown", function(e) { } }) -function saveCustomModifiers() { - localStorage.setItem(CUSTOM_MODIFIERS_KEY, customModifiersTextBox.value.trim()) +modifierDropdown.addEventListener("click", e => { + const targetElem = e.target + const isDropdownActive = targetElem.dataset.active == "true" ? true : false - loadCustomModifiers() -} + if (!isDropdownActive) + showModifierContainer() + else + hideModifierContainer() +}) -function loadCustomModifiers() { - PLUGINS["MODIFIERS_LOAD"].forEach((fn) => fn.loader.call()) -} +let collapsiblesBtnState = false -customModifiersTextBox.addEventListener("change", saveCustomModifiers) +modifiersCollapsiblesBtn.addEventListener("click", (e) => { + const btnElem = modifiersCollapsiblesBtn + + const collapseText = "Collapse Categories" + const expandText = "Expand Categories" + + const collapseIconClasses = ["fa-solid", "fa-square-minus"] + const expandIconClasses = ["fa-solid", "fa-square-plus"] + + const iconElem = btnElem.querySelector(".modifiers-action-icon") + const textElem = btnElem.querySelector(".modifiers-action-text") + + if (collapsiblesBtnState) { + collapseAllModifierCategory() + + collapsiblesBtnState = false + + collapseIconClasses.forEach((c) => iconElem.classList.remove(c)) + expandIconClasses.forEach((c) => iconElem.classList.add(c)) + + textElem.innerText = expandText + } else { + expandAllModifierCategory() + + collapsiblesBtnState = true + + expandIconClasses.forEach((c) => iconElem.classList.remove(c)) + collapseIconClasses.forEach((c) => iconElem.classList.add(c)) + + textElem.innerText = collapseText + } +}) + +let containerSizeBtnState = false + +modifiersContainerSizeBtn.addEventListener("click", (e) => { + const btnElem = modifiersContainerSizeBtn + + const maximizeIconClasses = ["fa-solid", "fa-expand"] + const revertIconClasses = ["fa-solid", "fa-compress"] + + modifiersMainContainer.classList.toggle("modifiers-maximized") + + if(containerSizeBtnState) { + revertIconClasses.forEach((c) => btnElem.classList.remove(c)) + maximizeIconClasses.forEach((c) => btnElem.classList.add(c)) + + containerSizeBtnState = false + } else { + maximizeIconClasses.forEach((c) => btnElem.classList.remove(c)) + revertIconClasses.forEach((c) => btnElem.classList.add(c)) + + containerSizeBtnState = true + } +}) + +modifierSettingsBtn.addEventListener("click", (e) => { + modifierSettingsOverlay.classList.add("active") + customModifiersTextBox.setSelectionRange(0, 0) + customModifiersTextBox.focus() + customModifiersInitialContent = customModifiersTextBox.value // preserve the initial content + e.stopPropagation() +}) + +modifiersCloseBtn.addEventListener("click", (e) => { + hideModifierContainer() +}) + +// prevents the modifier panel closing at the same time as the settings overlay +new MutationObserver(() => { + const isActive = modifierSettingsOverlay.classList.contains("active") + + if (!isActive) { + modifierPanelFreezed = true + + setTimeout(() => modifierPanelFreezed = false, 25) + } +}).observe(modifierSettingsOverlay, { attributes: true }) \ No newline at end of file From 2a5b3040e2e999d1a2254e0a0e9997db8254c924 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 19 Jun 2023 19:58:17 +0530 Subject: [PATCH 106/123] sdkit 1.0.108 - potential fix for multi-gpu bug while rendering - the sampler instances weren't thread-local --- scripts/check_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index c754ec32..e8140839 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.107", + "sdkit": "1.0.108", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", From 4bf78521cee48664c4b08a6aefdf47e2b5311f25 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 19 Jun 2023 19:58:59 +0530 Subject: [PATCH 107/123] changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index b53ac141..49f056c7 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.41 - 19 Jun 2023 - Another fix for multi-gpu rendering (in all VRAM usage modes). * 2.5.41 - 13 Jun 2023 - Fix multi-gpu bug with "low" VRAM usage mode while generating images. * 2.5.41 - 12 Jun 2023 - Fix multi-gpu bug with CodeFormer. * 2.5.41 - 6 Jun 2023 - Allow changing the strength of CodeFormer, and slightly improved styling of the CodeFormer options. From 5b35c47360e18bfa6e4bfc5fc158f72c97e4182d Mon Sep 17 00:00:00 2001 From: JeLuF Date: Mon, 19 Jun 2023 21:50:56 +0200 Subject: [PATCH 108/123] Fix saving of network settings --- ui/media/js/parameters.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/media/js/parameters.js b/ui/media/js/parameters.js index 2f915eeb..27cfe6fc 100644 --- a/ui/media/js/parameters.js +++ b/ui/media/js/parameters.js @@ -649,6 +649,7 @@ async function getSystemInfo() { } saveSettingsBtn.addEventListener("click", function() { + console.log("listenPortField.value", listenPortField.value) if (listenPortField.value == "") { alert("The network port field must not be empty.") return @@ -664,7 +665,8 @@ saveSettingsBtn.addEventListener("click", function() { update_branch: updateBranch, } - Array.from(parametersTable.children).forEach((parameterRow) => { + //Array.from(parametersTable.children).forEach((parameterRow) => { + document.querySelectorAll('#system-settings [data-setting-id]').forEach((parameterRow) => { if (parameterRow.dataset.saveInAppConfig === "true") { const parameterElement = document.getElementById(parameterRow.dataset.settingId) || From 65bb01892f6286eb5b47dd58511f3f9ca0b9ecd5 Mon Sep 17 00:00:00 2001 From: JeLuF Date: Mon, 19 Jun 2023 21:58:58 +0200 Subject: [PATCH 109/123] remove old code --- ui/media/js/parameters.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/media/js/parameters.js b/ui/media/js/parameters.js index 27cfe6fc..50c6682b 100644 --- a/ui/media/js/parameters.js +++ b/ui/media/js/parameters.js @@ -665,7 +665,6 @@ saveSettingsBtn.addEventListener("click", function() { update_branch: updateBranch, } - //Array.from(parametersTable.children).forEach((parameterRow) => { document.querySelectorAll('#system-settings [data-setting-id]').forEach((parameterRow) => { if (parameterRow.dataset.saveInAppConfig === "true") { const parameterElement = From aac9acf068b384bf39b059898be3a563b0c6b4d0 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 20 Jun 2023 10:49:34 +0530 Subject: [PATCH 110/123] sdkit 1.0.109 - auto-set fp32 attention precision in diffusers if required --- scripts/check_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index e8140839..fe7521b3 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.108", + "sdkit": "1.0.109", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", From a43bd2fd3b496c4c38c22e09f69b7035baf38722 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Tue, 20 Jun 2023 10:50:28 +0530 Subject: [PATCH 111/123] changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 49f056c7..90f21ae2 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.41 - 20 Jun 2023 - Automatically fix black images if fp32 attention precision is required in diffusers. * 2.5.41 - 19 Jun 2023 - Another fix for multi-gpu rendering (in all VRAM usage modes). * 2.5.41 - 13 Jun 2023 - Fix multi-gpu bug with "low" VRAM usage mode while generating images. * 2.5.41 - 12 Jun 2023 - Fix multi-gpu bug with CodeFormer. From 7811929b5bf7d5b4860607b309b91630aa427681 Mon Sep 17 00:00:00 2001 From: JeLuF Date: Thu, 22 Jun 2023 01:15:07 +0200 Subject: [PATCH 112/123] Run dev console in ED directory --- scripts/Developer Console.cmd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/Developer Console.cmd b/scripts/Developer Console.cmd index 921a9dca..256cd682 100644 --- a/scripts/Developer Console.cmd +++ b/scripts/Developer Console.cmd @@ -2,6 +2,8 @@ echo "Opening Stable Diffusion UI - Developer Console.." & echo. +cd %cd% + set PATH=C:\Windows\System32;%PATH% @rem set legacy and new installer's PATH, if they exist From a5898aaf3b57170ac8c88b327ecf10673d7c9f22 Mon Sep 17 00:00:00 2001 From: JeLuF Date: Thu, 22 Jun 2023 23:54:45 +0200 Subject: [PATCH 113/123] Show COMSPEC variable in logs --- scripts/Developer Console.cmd | 2 ++ scripts/Start Stable Diffusion UI.cmd | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/Developer Console.cmd b/scripts/Developer Console.cmd index 921a9dca..232cb6a1 100644 --- a/scripts/Developer Console.cmd +++ b/scripts/Developer Console.cmd @@ -21,6 +21,8 @@ call git --version call where conda call conda --version +echo. +echo COMSPEC=%COMSPEC% echo. @rem activate the legacy environment (if present) and set PYTHONPATH diff --git a/scripts/Start Stable Diffusion UI.cmd b/scripts/Start Stable Diffusion UI.cmd index 4f8555ea..9a4a6303 100644 --- a/scripts/Start Stable Diffusion UI.cmd +++ b/scripts/Start Stable Diffusion UI.cmd @@ -36,8 +36,9 @@ call git --version call where conda call conda --version +echo . +echo COMSPEC=%COMSPEC% @rem Download the rest of the installer and UI call scripts\on_env_start.bat - @pause From d9bddffc426c850e4c10d836717c2baa5830c82a Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Fri, 23 Jun 2023 21:42:11 +0530 Subject: [PATCH 114/123] sdkit 1.0.110 - don't offload latent upscaler to the CPU if not running on a GPU --- scripts/check_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index fe7521b3..c1c1febb 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.109", + "sdkit": "1.0.110", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", From eb301a67d4ce2673d0c1095512be1a8dcf5e6715 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Fri, 23 Jun 2023 21:43:36 +0530 Subject: [PATCH 115/123] changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 90f21ae2..0d9640bb 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.41 - 23 Jun 2023 - Fix a regression where latent upscaler stopped working on PCs without a graphics card. * 2.5.41 - 20 Jun 2023 - Automatically fix black images if fp32 attention precision is required in diffusers. * 2.5.41 - 19 Jun 2023 - Another fix for multi-gpu rendering (in all VRAM usage modes). * 2.5.41 - 13 Jun 2023 - Fix multi-gpu bug with "low" VRAM usage mode while generating images. From 4dd1a46efa55533646f16c3f1d989b88defab810 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Sat, 24 Jun 2023 15:21:13 +0530 Subject: [PATCH 116/123] sdkit 1.0.111 - don't apply a negative lora when testing a newly loaded SD model --- scripts/check_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_modules.py b/scripts/check_modules.py index c1c1febb..a339ed46 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.110", + "sdkit": "1.0.111", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", From 887d871d26eb93155ffb3f173e10acd671cf4ee4 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Sat, 24 Jun 2023 15:22:09 +0530 Subject: [PATCH 117/123] changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 0d9640bb..f147ad0c 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.41 - 24 Jun 2023 - (beta-only) Fix a recent regression where the LoRA would not get applied when changing SD models. * 2.5.41 - 23 Jun 2023 - Fix a regression where latent upscaler stopped working on PCs without a graphics card. * 2.5.41 - 20 Jun 2023 - Automatically fix black images if fp32 attention precision is required in diffusers. * 2.5.41 - 19 Jun 2023 - Another fix for multi-gpu rendering (in all VRAM usage modes). From c74be07c33a883be9532cb5ff0e5f1e33d161ace Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Sat, 24 Jun 2023 15:46:03 +0530 Subject: [PATCH 118/123] sdkit 1.0.112 - fix broken inpainting in low vram mode --- CHANGES.md | 1 + scripts/check_modules.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index f147ad0c..66fae99b 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.41 - 24 Jun 2023 - (beta-only) Fix broken inpainting in low VRAM usage mode. * 2.5.41 - 24 Jun 2023 - (beta-only) Fix a recent regression where the LoRA would not get applied when changing SD models. * 2.5.41 - 23 Jun 2023 - Fix a regression where latent upscaler stopped working on PCs without a graphics card. * 2.5.41 - 20 Jun 2023 - Automatically fix black images if fp32 attention precision is required in diffusers. diff --git a/scripts/check_modules.py b/scripts/check_modules.py index a339ed46..4cbf261f 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.111", + "sdkit": "1.0.112", "stable-diffusion-sdkit": "2.1.4", "rich": "12.6.0", "uvicorn": "0.19.0", From 881fdc58ec7646d0a1ee76a3f64d002859db3aa0 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 26 Jun 2023 15:34:25 +0530 Subject: [PATCH 119/123] debug logging --- ui/media/js/parameters.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/media/js/parameters.js b/ui/media/js/parameters.js index 50c6682b..cd86be63 100644 --- a/ui/media/js/parameters.js +++ b/ui/media/js/parameters.js @@ -649,7 +649,6 @@ async function getSystemInfo() { } saveSettingsBtn.addEventListener("click", function() { - console.log("listenPortField.value", listenPortField.value) if (listenPortField.value == "") { alert("The network port field must not be empty.") return From c9a5ad9c3a25bc1578f3e920475cef4c053d3bfc Mon Sep 17 00:00:00 2001 From: JeLuF Date: Mon, 26 Jun 2023 12:20:34 +0200 Subject: [PATCH 120/123] Update Developer Console.cmd --- scripts/Developer Console.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Developer Console.cmd b/scripts/Developer Console.cmd index 256cd682..3a91725a 100644 --- a/scripts/Developer Console.cmd +++ b/scripts/Developer Console.cmd @@ -2,7 +2,7 @@ echo "Opening Stable Diffusion UI - Developer Console.." & echo. -cd %cd% +cd /d %~dp0 set PATH=C:\Windows\System32;%PATH% From e1e2a2a249ed414d5e83c4db019b48e2e507204c Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 26 Jun 2023 16:00:55 +0530 Subject: [PATCH 121/123] Update index.html --- ui/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/index.html b/ui/index.html index a78a6f06..6f771e62 100644 --- a/ui/index.html +++ b/ui/index.html @@ -450,7 +450,6 @@
  • Some custom inpainting models don't work
  • These samplers don't work yet: Unipc SNR, Unipc TQ, Unipc SNR2, DPM++ 2s Ancestral, DPM++ SDE, DPM Fast, DPM Adaptive, DPM2
  • Hypernetwork doesn't work
  • -
  • Multi GPU - cuda:1 and cuda:0 conflict
  • The time remaining in browser differs from the one in the console
  • From 848ff35e85736466200b5119baead5f05685cbd3 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 26 Jun 2023 16:04:18 +0530 Subject: [PATCH 122/123] Update index.html --- ui/index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/index.html b/ui/index.html index 15b44daf..ffe91f37 100644 --- a/ui/index.html +++ b/ui/index.html @@ -461,7 +461,8 @@
  • More choices for img2img samplers
  • -
  • Support for inpainting models
  • +
  • Support for official inpainting models
  • +
  • Generate images that tile seamlessly
  • Clip Skip support allows to skip the last CLIP layer (recommended by some LORA models)
  • New samplers: DDPM and DEIS
  • Memory optimizations that allow the use of 2GB GPUs
  • From df416a6a177044450d28e1e0941dd7087583bc23 Mon Sep 17 00:00:00 2001 From: cmdr2 Date: Mon, 26 Jun 2023 16:11:10 +0530 Subject: [PATCH 123/123] link --- ui/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/index.html b/ui/index.html index ffe91f37..555cb691 100644 --- a/ui/index.html +++ b/ui/index.html @@ -438,7 +438,7 @@

    Diffusers Tech Preview

    The Diffusers Tech Preview allows early access to the new features based on Diffusers.

    -

    The Preview is under active development. It is experimental! It does still have bugs and missing features!

    +

    This is under active development, and is missing a few features. It is experimental! Please report any bugs to the #beta channel in our Discord server!

    New upcoming features in our new engine

    • LORA support - Place LORA files in the models/lora folder.