From 4845db4e324dd5194ea82cc5f772237242a89a92 Mon Sep 17 00:00:00 2001 From: Ftps <63702646+Tps-F@users.noreply.github.com> Date: Wed, 15 Mar 2023 20:29:50 +0900 Subject: Update ui_extensions.py Add git submodule and Fix WinError --- modules/ui_extensions.py | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'modules') diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index df75a925..b24b67fc 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -141,22 +141,11 @@ def install_extension_from_url(dirname, url): try: shutil.rmtree(tmpdir, True) - - repo = git.Repo.clone_from(url, tmpdir) - repo.remote().fetch() - - try: - os.rename(tmpdir, target_dir) - except OSError as err: - # TODO what does this do on windows? I think it'll be a different error code but I don't have a system to check it - # Shouldn't cause any new issues at least but we probably want to handle it there too. - if err.errno == errno.EXDEV: - # Cross device link, typical in docker or when tmp/ and extensions/ are on different file systems - # Since we can't use a rename, do the slower but more versitile shutil.move() - shutil.move(tmpdir, target_dir) - else: - # Something else, not enough free space, permissions, etc. rethrow it so that it gets handled. - raise(err) + with git.Repo.clone_from(url, tmpdir) as repo: + repo.remote().fetch() + for submodule in repo.submodules: + submodule.update() + os.rename(tmpdir, target_dir) import launch launch.run_extension_installer(target_dir) -- cgit v1.2.1 From 79ed567b12c73231b712eb97106a565330968e34 Mon Sep 17 00:00:00 2001 From: Ftps <63702646+Tps-F@users.noreply.github.com> Date: Wed, 15 Mar 2023 22:42:53 +0900 Subject: remove unused library I'm sorry I forgot. --- modules/ui_extensions.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'modules') diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index b24b67fc..3d9c4261 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -1,6 +1,5 @@ import json import os.path -import shutil import sys import time import traceback @@ -10,7 +9,6 @@ import git import gradio as gr import html import shutil -import errno from modules import extensions, shared, paths from modules.call_queue import wrap_gradio_gpu_call -- cgit v1.2.1 From 147d2922ff573f757b8940446b925c2e658e40ac Mon Sep 17 00:00:00 2001 From: Ftps <63702646+Tps-F@users.noreply.github.com> Date: Thu, 16 Mar 2023 12:35:48 +0900 Subject: Cross device link --- modules/ui_extensions.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index 3d9c4261..d9def96e 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -9,6 +9,7 @@ import git import gradio as gr import html import shutil +import errno from modules import extensions, shared, paths from modules.call_queue import wrap_gradio_gpu_call @@ -143,7 +144,16 @@ def install_extension_from_url(dirname, url): repo.remote().fetch() for submodule in repo.submodules: submodule.update() - os.rename(tmpdir, target_dir) + try: + os.rename(tmpdir, target_dir) + except OSError as err: + if err.errno == errno.EXDEV: + # Cross device link, typical in docker or when tmp/ and extensions/ are on different file systems + # Since we can't use a rename, do the slower but more versitile shutil.move() + shutil.move(tmpdir, target_dir) + else: + # Something else, not enough free space, permissions, etc. rethrow it so that it gets handled. + raise err import launch launch.run_extension_installer(target_dir) -- cgit v1.2.1 From 4cbbb881ee530d9b9ba18027e2b0057e6a2c4ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=A6=CF=86?= <42910943+Brawlence@users.noreply.github.com> Date: Thu, 9 Mar 2023 07:56:19 +0300 Subject: Unload checkpoints on Request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …to free VRAM. New Action buttons in the settings to manually free and reload checkpoints, essentially juggling models between RAM and VRAM. --- modules/api/api.py | 14 +++++++++++++- modules/sd_models.py | 22 +++++++++++++++++++++- modules/ui.py | 22 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/api/api.py b/modules/api/api.py index 35e17afc..f52f7fef 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -18,7 +18,7 @@ from modules.textual_inversion.textual_inversion import create_embedding, train_ from modules.textual_inversion.preprocess import preprocess from modules.hypernetworks.hypernetwork import create_hypernetwork, train_hypernetwork from PIL import PngImagePlugin,Image -from modules.sd_models import checkpoints_list +from modules.sd_models import checkpoints_list, unload_model_weights, reload_model_weights from modules.sd_models_config import find_checkpoint_config_near_filename from modules.realesrgan_model import get_realesrgan_models from modules import devices @@ -150,6 +150,8 @@ class Api: self.add_api_route("/sdapi/v1/train/embedding", self.train_embedding, methods=["POST"], response_model=TrainResponse) self.add_api_route("/sdapi/v1/train/hypernetwork", self.train_hypernetwork, methods=["POST"], response_model=TrainResponse) self.add_api_route("/sdapi/v1/memory", self.get_memory, methods=["GET"], response_model=MemoryResponse) + self.add_api_route("/sdapi/v1/unload-checkpoint", self.unloadapi, methods=["POST"]) + self.add_api_route("/sdapi/v1/reload-checkpoint", self.reloadapi, methods=["POST"]) self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=ScriptsList) def add_api_route(self, path: str, endpoint, **kwargs): @@ -412,6 +414,16 @@ class Api: return {} + def unloadapi(self): + unload_model_weights() + + return {} + + def reloadapi(self): + reload_model_weights() + + return {} + def skip(self): shared.state.skip() diff --git a/modules/sd_models.py b/modules/sd_models.py index f0cb1240..f9dd0521 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -494,7 +494,7 @@ def reload_model_weights(sd_model=None, info=None): if sd_model is None or checkpoint_config != sd_model.used_config: del sd_model checkpoints_loaded.clear() - load_model(checkpoint_info, already_loaded_state_dict=state_dict, time_taken_to_load_state_dict=timer.records["load weights from disk"]) + load_model(checkpoint_info, already_loaded_state_dict=state_dict) return shared.sd_model try: @@ -517,3 +517,23 @@ def reload_model_weights(sd_model=None, info=None): print(f"Weights loaded in {timer.summary()}.") return sd_model + +def unload_model_weights(sd_model=None, info=None): + from modules import lowvram, devices, sd_hijack + timer = Timer() + + if shared.sd_model: + + # shared.sd_model.cond_stage_model.to(devices.cpu) + # shared.sd_model.first_stage_model.to(devices.cpu) + shared.sd_model.to(devices.cpu) + sd_hijack.model_hijack.undo_hijack(shared.sd_model) + shared.sd_model = None + sd_model = None + gc.collect() + devices.torch_gc() + torch.cuda.empty_cache() + + print(f"Unloaded weights {timer.summary()}.") + + return sd_model \ No newline at end of file diff --git a/modules/ui.py b/modules/ui.py index 7e603332..d93ef134 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1491,11 +1491,33 @@ def create_ui(): request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications") download_localization = gr.Button(value='Download localization template', elem_id="download_localization") reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary', elem_id="settings_reload_script_bodies") + with gr.Row(): + unload_sd_model = gr.Button(value='Unload SD checkpoint to free VRAM', elem_id="sett_unload_sd_model") + reload_sd_model = gr.Button(value='Reload the last SD checkpoint back into VRAM', elem_id="sett_reload_sd_model") with gr.TabItem("Licenses"): gr.HTML(shared.html("licenses.html"), elem_id="licenses") gr.Button(value="Show all pages", elem_id="settings_show_all_pages") + + + def unload_sd_weights(): + modules.sd_models.unload_model_weights() + + def reload_sd_weights(): + modules.sd_models.reload_model_weights() + + unload_sd_model.click( + fn=unload_sd_weights, + inputs=[], + outputs=[] + ) + + reload_sd_model.click( + fn=reload_sd_weights, + inputs=[], + outputs=[] + ) request_notifications.click( fn=lambda: None, -- cgit v1.2.1 From 254d9946439be9b6266b671db68086eb68ef1e63 Mon Sep 17 00:00:00 2001 From: FNSpd <125805478+FNSpd@users.noreply.github.com> Date: Tue, 21 Mar 2023 14:45:39 +0400 Subject: Update devices.py --- modules/devices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/devices.py b/modules/devices.py index 52c3e7cd..6c6c7233 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -110,7 +110,7 @@ def autocast(disable=False): if disable: return contextlib.nullcontext() - if dtype == torch.float32 or shared.cmd_opts.precision == "full": + if dtype == torch.float32 or shared.cmd_opts.precision == "full" or shared.cmd_opts.upcast_sampling: return contextlib.nullcontext() return torch.autocast("cuda") -- cgit v1.2.1 From 91cfa9718cead1c9834d5fe46a3af54abeacc8e2 Mon Sep 17 00:00:00 2001 From: FNSpd <125805478+FNSpd@users.noreply.github.com> Date: Tue, 21 Mar 2023 14:47:43 +0400 Subject: Update sd_hijack_unet.py --- modules/sd_hijack_unet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/sd_hijack_unet.py b/modules/sd_hijack_unet.py index 843ab66c..d37ec316 100644 --- a/modules/sd_hijack_unet.py +++ b/modules/sd_hijack_unet.py @@ -67,7 +67,7 @@ def hijack_ddpm_edit(): unet_needs_upcast = lambda *args, **kwargs: devices.unet_needs_upcast CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.apply_model', apply_model, unet_needs_upcast) CondFunc('ldm.modules.diffusionmodules.openaimodel.timestep_embedding', lambda orig_func, timesteps, *args, **kwargs: orig_func(timesteps, *args, **kwargs).to(torch.float32 if timesteps.dtype == torch.int64 else devices.dtype_unet), unet_needs_upcast) -if version.parse(torch.__version__) <= version.parse("1.13.1"): +if version.parse(torch.__version__) <= version.parse("1.13.2"): CondFunc('ldm.modules.diffusionmodules.util.GroupNorm32.forward', lambda orig_func, self, *args, **kwargs: orig_func(self.float(), *args, **kwargs), unet_needs_upcast) CondFunc('ldm.modules.attention.GEGLU.forward', lambda orig_func, self, x: orig_func(self.float(), x.float()).to(devices.dtype_unet), unet_needs_upcast) CondFunc('open_clip.transformer.ResidualAttentionBlock.__init__', lambda orig_func, *args, **kwargs: kwargs.update({'act_layer': GELUHijack}) and False or orig_func(*args, **kwargs), lambda _, *args, **kwargs: kwargs.get('act_layer') is None or kwargs['act_layer'] == torch.nn.GELU) -- cgit v1.2.1 From c84c9df73799e173fcfafdc9548dbd043ba28682 Mon Sep 17 00:00:00 2001 From: FNSpd <125805478+FNSpd@users.noreply.github.com> Date: Tue, 21 Mar 2023 14:50:22 +0400 Subject: Update sd_hijack_optimizations.py --- modules/sd_hijack_optimizations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 2e307b5d..eaff12f0 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -337,7 +337,7 @@ def xformers_attention_forward(self, x, context=None, mask=None): dtype = q.dtype if shared.opts.upcast_attn: - q, k = q.float(), k.float() + q, k, v = q.float(), k.float(), v.float() out = xformers.ops.memory_efficient_attention(q, k, v, attn_bias=None, op=get_xformers_flash_attention_op(q, k, v)) -- cgit v1.2.1 From 00bd271faffbdfd2988b6cfc9117c67681ee14b7 Mon Sep 17 00:00:00 2001 From: ArrowM Date: Tue, 21 Mar 2023 21:13:30 -0500 Subject: Move `load_file_from_url` Why? one of the internal calls of `load_file_from_url` import cv2, which locks the cv2 site-package, which extensions may (and in our case, is) breaking the installation of some libraries. The base project should be limiting its import of unnecessary libraries when possible during the installation phase. --- modules/modelloader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/modelloader.py b/modules/modelloader.py index e351d808..522affc6 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -4,7 +4,6 @@ import shutil import importlib from urllib.parse import urlparse -from basicsr.utils.download_util import load_file_from_url from modules import shared from modules.upscaler import Upscaler, UpscalerLanczos, UpscalerNearest, UpscalerNone from modules.paths import script_path, models_path @@ -59,6 +58,7 @@ def load_models(model_path: str, model_url: str = None, command_path: str = None if model_url is not None and len(output) == 0: if download_name is not None: + from basicsr.utils.download_util import load_file_from_url dl = load_file_from_url(model_url, model_path, True, download_name) output.append(dl) else: -- cgit v1.2.1 From 64b7e8382377bb578d9740c061979776b214cfd9 Mon Sep 17 00:00:00 2001 From: sumof2primes Date: Wed, 22 Mar 2023 18:24:11 +0900 Subject: Fix scripts load order - 1st webui, 2nd extensions-builtin, 3rd extensions - to load scripts independent of --data-dir - change load order key [x.basedir, x.filename, x.path] to [orderby(x.basedir), x.filename, x.path] e.g., scripts/xyz_grid.py dependent extentions should loaded later extensions\sd-webui-controlnet\scripts\xyz_grid_support.py extensions\sd-webui-additional-networks\scripts\xyz_grid_support.py --- modules/scripts.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/scripts.py b/modules/scripts.py index 8de19884..935c693c 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -239,7 +239,15 @@ def load_scripts(): elif issubclass(script_class, scripts_postprocessing.ScriptPostprocessing): postprocessing_scripts_data.append(ScriptClassData(script_class, scriptfile.path, scriptfile.basedir, module)) - for scriptfile in sorted(scripts_list): + def orderby(basedir): + # 1st webui, 2nd extensions-builtin, 3rd extensions + priority = {os.path.join(paths.script_path, "extensions-builtin"):1, paths.script_path:0} + for key in priority: + if basedir.startswith(key): + return priority[key] + return 9999 + + for scriptfile in sorted(scripts_list, key=lambda x: [orderby(x.basedir), x.filename, x.path]): try: if scriptfile.basedir != paths.script_path: sys.path = [scriptfile.basedir] + sys.path -- cgit v1.2.1 From cd3cd0fca0f109662e783a55d12c26837254f11f Mon Sep 17 00:00:00 2001 From: sumof2primes Date: Thu, 23 Mar 2023 01:28:09 +0900 Subject: Fix scripts load order - 1st webui, 2nd extensions-builtin, 3rd extensions - to load scripts independent of --data-dir - change load order key [x.basedir, x.filename, x.path] to [orderby(x.basedir), x.filename, x.path] e.g., scripts/xyz_grid.py dependent extentions should loaded later extensions\sd-webui-controlnet\scripts\xyz_grid_support.py extensions\sd-webui-additional-networks\scripts\xyz_grid_support.py --- modules/scripts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/scripts.py b/modules/scripts.py index 935c693c..a8d525bf 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -247,7 +247,7 @@ def load_scripts(): return priority[key] return 9999 - for scriptfile in sorted(scripts_list, key=lambda x: [orderby(x.basedir), x.filename, x.path]): + for scriptfile in sorted(scripts_list, key=lambda x: [orderby(x.basedir), x]): try: if scriptfile.basedir != paths.script_path: sys.path = [scriptfile.basedir] + sys.path -- cgit v1.2.1 From caf84e8233236cd36fcd42e39e4199262dc3f4e7 Mon Sep 17 00:00:00 2001 From: catboxanon <122327233+catboxanon@users.noreply.github.com> Date: Wed, 22 Mar 2023 17:51:40 +0000 Subject: Expose inpainting mask and composite For inpainting, this exposes the mask and masked composite and gives the user the ability to display these in the web UI, save to disk, or both. --- modules/processing.py | 16 ++++++++++++++++ modules/shared.py | 4 ++++ 2 files changed, 20 insertions(+) (limited to 'modules') diff --git a/modules/processing.py b/modules/processing.py index 59717b4c..2e5a363f 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -689,6 +689,22 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: image.info["parameters"] = text output_images.append(image) + if hasattr(p, 'mask_for_overlay') and p.mask_for_overlay: + image_mask = p.mask_for_overlay.convert('RGB') + image_mask_composite = Image.composite(image.convert('RGBA').convert('RGBa'), Image.new('RGBa', image.size), p.mask_for_overlay.convert('L')).convert('RGBA') + + if opts.save_mask: + images.save_image(image_mask, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-mask") + + if opts.save_mask_composite: + images.save_image(image_mask_composite, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-mask-composite") + + if opts.return_mask: + output_images.append(image_mask) + + if opts.return_mask_composite: + output_images.append(image_mask_composite) + del x_samples_ddim devices.torch_gc() diff --git a/modules/shared.py b/modules/shared.py index f28a12cc..d26e9111 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -332,6 +332,8 @@ options_templates.update(options_section(('saving-images', "Saving images/grids" "save_images_before_face_restoration": OptionInfo(False, "Save a copy of image before doing face restoration."), "save_images_before_highres_fix": OptionInfo(False, "Save a copy of image before applying highres fix."), "save_images_before_color_correction": OptionInfo(False, "Save a copy of image before applying color correction to img2img results"), + "save_mask": OptionInfo(False, "For inpainting, save a copy of the greyscale mask"), + "save_mask_composite": OptionInfo(False, "For inpainting, save a masked composite"), "jpeg_quality": OptionInfo(80, "Quality for saved jpeg images", gr.Slider, {"minimum": 1, "maximum": 100, "step": 1}), "webp_lossless": OptionInfo(False, "Use lossless compression for webp images"), "export_for_4chan": OptionInfo(True, "If the saved image file size is above the limit, or its either width or height are above the limit, save a downscaled copy as JPG"), @@ -454,6 +456,8 @@ options_templates.update(options_section(('extra_networks', "Extra Networks"), { options_templates.update(options_section(('ui', "User interface"), { "return_grid": OptionInfo(True, "Show grid in results for web"), + "return_mask": OptionInfo(False, "For inpainting, include the greyscale mask in results for web"), + "return_mask_composite": OptionInfo(False, "For inpainting, include masked composite in results for web"), "do_not_show_images": OptionInfo(False, "Do not show any images in results for web"), "add_model_hash_to_info": OptionInfo(True, "Add model hash to generation information"), "add_model_name_to_info": OptionInfo(True, "Add model name to generation information"), -- cgit v1.2.1 From 92e173d414e5441ff34e5a6b12d5a766e86b0c36 Mon Sep 17 00:00:00 2001 From: carat-johyun Date: Thu, 23 Mar 2023 14:28:08 +0900 Subject: fix variable typo --- modules/sd_models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/sd_models.py b/modules/sd_models.py index f0cb1240..6410b09a 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -178,7 +178,7 @@ def select_checkpoint(): return checkpoint_info -chckpoint_dict_replacements = { +checkpoint_dict_replacements = { 'cond_stage_model.transformer.embeddings.': 'cond_stage_model.transformer.text_model.embeddings.', 'cond_stage_model.transformer.encoder.': 'cond_stage_model.transformer.text_model.encoder.', 'cond_stage_model.transformer.final_layer_norm.': 'cond_stage_model.transformer.text_model.final_layer_norm.', @@ -186,7 +186,7 @@ chckpoint_dict_replacements = { def transform_checkpoint_dict_key(k): - for text, replacement in chckpoint_dict_replacements.items(): + for text, replacement in checkpoint_dict_replacements.items(): if k.startswith(text): k = replacement + k[len(text):] -- cgit v1.2.1 From c5142e2fbecb50531a55aa804ea132c5d870858c Mon Sep 17 00:00:00 2001 From: brkirch Date: Fri, 24 Mar 2023 02:58:18 -0400 Subject: Add workaround for broken nn.Linear on macOS 13.2 Credit to danieldk (https://github.com/explosion/curated-transformers/pull/124) for the workaround this is based on. --- modules/mac_specific.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'modules') diff --git a/modules/mac_specific.py b/modules/mac_specific.py index 18e6ff72..3a170f60 100644 --- a/modules/mac_specific.py +++ b/modules/mac_specific.py @@ -1,4 +1,5 @@ import torch +import platform from modules import paths from modules.sd_hijack_utils import CondFunc from packaging import version @@ -32,6 +33,10 @@ if has_mps: # MPS fix for randn in torchsde CondFunc('torchsde._brownian.brownian_interval._randn', lambda _, size, dtype, device, seed: torch.randn(size, dtype=dtype, device=torch.device("cpu"), generator=torch.Generator(torch.device("cpu")).manual_seed(int(seed))).to(device), lambda _, size, dtype, device, seed: device.type == 'mps') + if platform.mac_ver()[0].startswith("13.2."): + # MPS workaround for https://github.com/pytorch/pytorch/issues/95188, thanks to danieldk (https://github.com/explosion/curated-transformers/pull/124) + CondFunc('torch.nn.functional.linear', lambda _, input, weight, bias: (torch.matmul(input, weight.t()) + bias) if bias is not None else torch.matmul(input, weight.t()), lambda _, input, weight, bias: input.numel() > 10485760) + if version.parse(torch.__version__) < version.parse("1.13"): # PyTorch 1.13 doesn't need these fixes but unfortunately is slower and has regressions that prevent training from working -- cgit v1.2.1 From 27fe3eb6a9d8f866af8b90dff18f4445124702da Mon Sep 17 00:00:00 2001 From: brkirch Date: Fri, 24 Mar 2023 03:04:47 -0400 Subject: Add workaround for MPS layer_norm on PyTorch 2.0 On PyTorch 2.0, with MPS layer_norm only accepts float32 inputs. This was fixed shortly after 2.0 was finalized so the workaround can be applied with an exact version match. --- modules/mac_specific.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/mac_specific.py b/modules/mac_specific.py index 3a170f60..6fe8dea0 100644 --- a/modules/mac_specific.py +++ b/modules/mac_specific.py @@ -54,4 +54,6 @@ if has_mps: CondFunc('torch.cumsum', cumsum_fix_func, None) CondFunc('torch.Tensor.cumsum', cumsum_fix_func, None) CondFunc('torch.narrow', lambda orig_func, *args, **kwargs: orig_func(*args, **kwargs).clone(), None) - + if version.parse(torch.__version__) == version.parse("2.0"): + # MPS workaround for https://github.com/pytorch/pytorch/issues/96113 + CondFunc('torch.nn.functional.layer_norm', lambda orig_func, x, normalized_shape, weight, bias, eps, **kwargs: orig_func(x.float(), normalized_shape, weight.float() if weight is not None else None, bias.float() if bias is not None else bias, eps).to(x.dtype), lambda *args, **kwargs: len(args) == 6) -- cgit v1.2.1 From beb7dda5d6d5baa1570721fd7ca18e236fa02521 Mon Sep 17 00:00:00 2001 From: FNSpd <125805478+FNSpd@users.noreply.github.com> Date: Fri, 24 Mar 2023 16:25:42 +0400 Subject: Update sd_hijack_unet.py --- modules/sd_hijack_unet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/sd_hijack_unet.py b/modules/sd_hijack_unet.py index d37ec316..15858263 100644 --- a/modules/sd_hijack_unet.py +++ b/modules/sd_hijack_unet.py @@ -67,7 +67,7 @@ def hijack_ddpm_edit(): unet_needs_upcast = lambda *args, **kwargs: devices.unet_needs_upcast CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.apply_model', apply_model, unet_needs_upcast) CondFunc('ldm.modules.diffusionmodules.openaimodel.timestep_embedding', lambda orig_func, timesteps, *args, **kwargs: orig_func(timesteps, *args, **kwargs).to(torch.float32 if timesteps.dtype == torch.int64 else devices.dtype_unet), unet_needs_upcast) -if version.parse(torch.__version__) <= version.parse("1.13.2"): +if version.parse(torch.__version__) <= version.parse("1.13.2") or torch.cuda.is_available(): CondFunc('ldm.modules.diffusionmodules.util.GroupNorm32.forward', lambda orig_func, self, *args, **kwargs: orig_func(self.float(), *args, **kwargs), unet_needs_upcast) CondFunc('ldm.modules.attention.GEGLU.forward', lambda orig_func, self, x: orig_func(self.float(), x.float()).to(devices.dtype_unet), unet_needs_upcast) CondFunc('open_clip.transformer.ResidualAttentionBlock.__init__', lambda orig_func, *args, **kwargs: kwargs.update({'act_layer': GELUHijack}) and False or orig_func(*args, **kwargs), lambda _, *args, **kwargs: kwargs.get('act_layer') is None or kwargs['act_layer'] == torch.nn.GELU) -- cgit v1.2.1 From 280ed8f00fde0ece026339acdd42888ac4dc3167 Mon Sep 17 00:00:00 2001 From: FNSpd <125805478+FNSpd@users.noreply.github.com> Date: Fri, 24 Mar 2023 16:29:16 +0400 Subject: Update sd_hijack_optimizations.py --- modules/sd_hijack_optimizations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index eaff12f0..372555ff 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -372,7 +372,7 @@ def scaled_dot_product_attention_forward(self, x, context=None, mask=None): dtype = q.dtype if shared.opts.upcast_attn: - q, k = q.float(), k.float() + q, k, v = q.float(), k.float(), v.float() # the output of sdp = (batch, num_heads, seq_len, head_dim) hidden_states = torch.nn.functional.scaled_dot_product_attention( -- cgit v1.2.1 From 803d44c4740f3de6b35fb7b9e3981a5eaf18b070 Mon Sep 17 00:00:00 2001 From: butaixianran Date: Sat, 25 Mar 2023 02:05:00 +0800 Subject: Fix None type error for TI module When user using model_name.png as a preview image, textural_inversion.py still treat it as an embeding, and didn't handle its error, just let python throw out an None type error like following: ```bash File "D:\Work\Dev\AI\stable-diffusion-webui\modules\textual_inversion\textual_inversion.py", line 155, in load_from_file name = data.get('name', name) AttributeError: 'NoneType' object has no attribute 'get' ``` With just a simple `if data:` checking as following, there will be no error, breaks nothing, and now this module can works fine with user's preview images. Old code: ```python data = extract_image_data_embed(embed_image) name = data.get('name', name) ``` New code: ```python data = extract_image_data_embed(embed_image) if data: name = data.get('name', name) else: # if data is None, means this is not an embeding, just a preview image return ``` Also, since there is no more errors on textual inversion module, from now on, extra network can set "model_name.png" as preview image for embedings. --- modules/textual_inversion/textual_inversion.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index c63c7d1d..d2e62e58 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -152,7 +152,11 @@ class EmbeddingDatabase: name = data.get('name', name) else: data = extract_image_data_embed(embed_image) - name = data.get('name', name) + if data: + name = data.get('name', name) + else: + # if data is None, means this is not an embeding, just a preview image + return elif ext in ['.BIN', '.PT']: data = torch.load(path, map_location="cpu") elif ext in ['.SAFETENSORS']: -- cgit v1.2.1 From a9eab236d7e8afa4d6205127904a385b2c43bb24 Mon Sep 17 00:00:00 2001 From: FNSpd <125805478+FNSpd@users.noreply.github.com> Date: Fri, 24 Mar 2023 23:08:30 +0400 Subject: Update devices.py --- modules/devices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/devices.py b/modules/devices.py index 6c6c7233..52c3e7cd 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -110,7 +110,7 @@ def autocast(disable=False): if disable: return contextlib.nullcontext() - if dtype == torch.float32 or shared.cmd_opts.precision == "full" or shared.cmd_opts.upcast_sampling: + if dtype == torch.float32 or shared.cmd_opts.precision == "full": return contextlib.nullcontext() return torch.autocast("cuda") -- cgit v1.2.1 From 9f0da9f6edfb9be1d69ba3492a61d96db769307b Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 20 Mar 2023 16:09:36 +0300 Subject: initial gradio 3.22 support --- modules/scripts.py | 3 +++ modules/scripts_postprocessing.py | 2 +- modules/ui.py | 43 +++++++++++++++++++++------------------ modules/ui_common.py | 3 ++- modules/ui_components.py | 36 ++++++++++++++++++-------------- 5 files changed, 50 insertions(+), 37 deletions(-) (limited to 'modules') diff --git a/modules/scripts.py b/modules/scripts.py index 8de19884..40d8dcc6 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -521,6 +521,9 @@ def IOComponent_init(self, *args, **kwargs): res = original_IOComponent_init(self, *args, **kwargs) + # this adds gradio-* to every component for css styling (ie gradio-button to gr.Button) + self.elem_classes = ["gradio-" + self.get_block_name(), *(self.elem_classes or [])] + script_callbacks.after_component_callback(self, **kwargs) if scripts_current is not None: diff --git a/modules/scripts_postprocessing.py b/modules/scripts_postprocessing.py index ce0ebb61..b11568c0 100644 --- a/modules/scripts_postprocessing.py +++ b/modules/scripts_postprocessing.py @@ -109,7 +109,7 @@ class ScriptPostprocessingRunner: inputs = [] for script in self.scripts_in_preferred_order(): - with gr.Box() as group: + with gr.Row() as group: self.create_script_ui(script, inputs) script.group = group diff --git a/modules/ui.py b/modules/ui.py index 7e603332..80807ce3 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -20,7 +20,7 @@ from PIL import Image, PngImagePlugin from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call from modules import sd_hijack, sd_models, localization, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, postprocessing, ui_components, ui_common, ui_postprocessing -from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML +from modules.ui_components import FormRow, FormColumn, FormGroup, ToolButton, FormHTML from modules.paths import script_path, data_path from modules.shared import opts, cmd_opts, restricted_opts @@ -89,7 +89,7 @@ paste_symbol = '\u2199\ufe0f' # ↙ refresh_symbol = '\U0001f504' # πŸ”„ save_style_symbol = '\U0001f4be' # πŸ’Ύ apply_style_symbol = '\U0001f4cb' # πŸ“‹ -clear_prompt_symbol = '\U0001F5D1' # πŸ—‘οΈ +clear_prompt_symbol = '\U0001f5d1\ufe0f' # πŸ—‘οΈ extra_networks_symbol = '\U0001F3B4' # 🎴 switch_values_symbol = '\U000021C5' # β‡… @@ -179,14 +179,13 @@ def interrogate_deepbooru(image): def create_seed_inputs(target_interface): - with FormRow(elem_id=target_interface + '_seed_row'): + with FormRow(elem_id=target_interface + '_seed_row', variant="compact"): seed = (gr.Textbox if cmd_opts.use_textbox_seed else gr.Number)(label='Seed', value=-1, elem_id=target_interface + '_seed') seed.style(container=False) - random_seed = gr.Button(random_symbol, elem_id=target_interface + '_random_seed') - reuse_seed = gr.Button(reuse_symbol, elem_id=target_interface + '_reuse_seed') + random_seed = ToolButton(random_symbol, elem_id=target_interface + '_random_seed') + reuse_seed = ToolButton(reuse_symbol, elem_id=target_interface + '_reuse_seed') - with gr.Group(elem_id=target_interface + '_subseed_show_box'): - seed_checkbox = gr.Checkbox(label='Extra', elem_id=target_interface + '_subseed_show', value=False) + seed_checkbox = gr.Checkbox(label='Extra', elem_id=target_interface + '_subseed_show', value=False) # Components to show/hide based on the 'Extra' checkbox seed_extras = [] @@ -195,8 +194,8 @@ def create_seed_inputs(target_interface): seed_extras.append(seed_extra_row_1) subseed = gr.Number(label='Variation seed', value=-1, elem_id=target_interface + '_subseed') subseed.style(container=False) - random_subseed = gr.Button(random_symbol, elem_id=target_interface + '_random_subseed') - reuse_subseed = gr.Button(reuse_symbol, elem_id=target_interface + '_reuse_subseed') + random_subseed = ToolButton(random_symbol, elem_id=target_interface + '_random_subseed') + reuse_subseed = ToolButton(reuse_symbol, elem_id=target_interface + '_reuse_subseed') subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01, elem_id=target_interface + '_subseed_strength') with FormRow(visible=False) as seed_extra_row_2: @@ -291,19 +290,19 @@ def create_toprow(is_img2img): with gr.Row(): with gr.Column(scale=80): with gr.Row(): - negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=2, placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)") + negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=3, placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)") button_interrogate = None button_deepbooru = None if is_img2img: - with gr.Column(scale=1, elem_id="interrogate_col"): + with gr.Column(scale=1, elem_classes="interrogate-col"): button_interrogate = gr.Button('Interrogate\nCLIP', elem_id="interrogate") button_deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru") with gr.Column(scale=1, elem_id=f"{id_part}_actions_column"): - with gr.Row(elem_id=f"{id_part}_generate_box"): - interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt") - skip = gr.Button('Skip', elem_id=f"{id_part}_skip") + with gr.Row(elem_id=f"{id_part}_generate_box", elem_classes="generate-box"): + interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt", elem_classes="generate-box-interrupt") + skip = gr.Button('Skip', elem_id=f"{id_part}_skip", elem_classes="generate-box-skip") submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary') skip.click( @@ -325,9 +324,9 @@ def create_toprow(is_img2img): prompt_style_apply = ToolButton(value=apply_style_symbol, elem_id=f"{id_part}_style_apply") save_style = ToolButton(value=save_style_symbol, elem_id=f"{id_part}_style_create") - token_counter = gr.HTML(value="", elem_id=f"{id_part}_token_counter") + token_counter = gr.HTML(value="0/75", elem_id=f"{id_part}_token_counter", elem_classes=["token-counter"]) token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button") - negative_token_counter = gr.HTML(value="", elem_id=f"{id_part}_negative_token_counter") + negative_token_counter = gr.HTML(value="0/75", elem_id=f"{id_part}_negative_token_counter", elem_classes=["token-counter"]) negative_token_button = gr.Button(visible=False, elem_id=f"{id_part}_negative_token_button") clear_prompt_button.click( @@ -479,7 +478,9 @@ def create_ui(): width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="txt2img_width") height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="txt2img_height") - res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn") + with gr.Column(elem_id="txt2img_dimensions_row", scale=1): + res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn") + if opts.dimensions_and_batch_together: with gr.Column(elem_id="txt2img_column_batch"): batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count") @@ -492,7 +493,7 @@ def create_ui(): seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs('txt2img') elif category == "checkboxes": - with FormRow(elem_id="txt2img_checkboxes", variant="compact"): + with FormRow(elem_classes="checkboxes-row", variant="compact"): restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1, elem_id="txt2img_restore_faces") tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling") enable_hr = gr.Checkbox(label='Hires. fix', value=False, elem_id="txt2img_enable_hr") @@ -757,7 +758,9 @@ def create_ui(): width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="img2img_width") height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="img2img_height") - res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn") + with gr.Column(elem_id="img2img_dimensions_row", scale=1): + res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn") + if opts.dimensions_and_batch_together: with gr.Column(elem_id="img2img_column_batch"): batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count") @@ -774,7 +777,7 @@ def create_ui(): seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs('img2img') elif category == "checkboxes": - with FormRow(elem_id="img2img_checkboxes", variant="compact"): + with FormRow(elem_classes="checkboxes-row", variant="compact"): restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1, elem_id="img2img_restore_faces") tiling = gr.Checkbox(label='Tiling', value=False, elem_id="img2img_tiling") diff --git a/modules/ui_common.py b/modules/ui_common.py index a12433d2..d4e00829 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -130,7 +130,7 @@ Requested path was: {f} generation_info = None with gr.Column(): with gr.Row(elem_id=f"image_buttons_{tabname}"): - open_folder_button = gr.Button(folder_symbol, elem_id="hidden_element" if shared.cmd_opts.hide_ui_dir_config else f'open_folder_{tabname}') + open_folder_button = gr.Button(folder_symbol, visible=not shared.cmd_opts.hide_ui_dir_config) if tabname != "extras": save = gr.Button('Save', elem_id=f'save_{tabname}') @@ -160,6 +160,7 @@ Requested path was: {f} _js="function(x, y, z){ return [x, y, selected_gallery_index()] }", inputs=[generation_info, html_info, html_info], outputs=[html_info, html_info], + show_progress=False, ) save.click( diff --git a/modules/ui_components.py b/modules/ui_components.py index 284ca0cf..2b1da2cb 100644 --- a/modules/ui_components.py +++ b/modules/ui_components.py @@ -1,55 +1,61 @@ import gradio as gr -class ToolButton(gr.Button, gr.components.FormComponent): - """Small button with single emoji as text, fits inside gradio forms""" +class FormComponent: + def get_expected_parent(self): + return gr.components.Form - def __init__(self, **kwargs): - super().__init__(variant="tool", **kwargs) - def get_block_name(self): - return "button" +gr.Dropdown.get_expected_parent = FormComponent.get_expected_parent -class ToolButtonTop(gr.Button, gr.components.FormComponent): - """Small button with single emoji as text, with extra margin at top, fits inside gradio forms""" +class ToolButton(FormComponent, gr.Button): + """Small button with single emoji as text, fits inside gradio forms""" - def __init__(self, **kwargs): - super().__init__(variant="tool-top", **kwargs) + def __init__(self, *args, **kwargs): + classes = kwargs.pop("elem_classes", []) + super().__init__(*args, elem_classes=["tool", *classes], **kwargs) def get_block_name(self): return "button" -class FormRow(gr.Row, gr.components.FormComponent): +class FormRow(FormComponent, gr.Row): """Same as gr.Row but fits inside gradio forms""" def get_block_name(self): return "row" -class FormGroup(gr.Group, gr.components.FormComponent): +class FormColumn(FormComponent, gr.Column): + """Same as gr.Column but fits inside gradio forms""" + + def get_block_name(self): + return "column" + + +class FormGroup(FormComponent, gr.Group): """Same as gr.Row but fits inside gradio forms""" def get_block_name(self): return "group" -class FormHTML(gr.HTML, gr.components.FormComponent): +class FormHTML(FormComponent, gr.HTML): """Same as gr.HTML but fits inside gradio forms""" def get_block_name(self): return "html" -class FormColorPicker(gr.ColorPicker, gr.components.FormComponent): +class FormColorPicker(FormComponent, gr.ColorPicker): """Same as gr.ColorPicker but fits inside gradio forms""" def get_block_name(self): return "colorpicker" -class DropdownMulti(gr.Dropdown): +class DropdownMulti(FormComponent, gr.Dropdown): """Same as gr.Dropdown but always multiselect""" def __init__(self, **kwargs): super().__init__(multiselect=True, **kwargs) -- cgit v1.2.1 From 9b2f20540004c47733ee47fb6bf58a41161ac0da Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 21 Mar 2023 06:49:19 +0300 Subject: fix ctrl+up/down attention edit fix dropdown obscured by live preview stylistic changes --- modules/ui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/ui.py b/modules/ui.py index 80807ce3..6e0ac89f 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -587,7 +587,7 @@ def create_ui(): txt2img_prompt.submit(**txt2img_args) submit.click(**txt2img_args) - res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height]) + res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False) txt_prompt_img.change( fn=modules.images.image_data, @@ -907,7 +907,7 @@ def create_ui(): img2img_prompt.submit(**img2img_args) submit.click(**img2img_args) - res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height]) + res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False) img2img_interrogate.click( fn=lambda *args: process_interrogate(interrogate, *args), -- cgit v1.2.1 From 43a0912a07376fd045095de0fea54de098b113ef Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 21 Mar 2023 08:18:14 +0300 Subject: hide delete button for single-item dropdown more stylistic changes --- modules/scripts.py | 15 +++++++++++++-- modules/ui.py | 2 ++ modules/ui_common.py | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'modules') diff --git a/modules/scripts.py b/modules/scripts.py index 40d8dcc6..8f55cf24 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -513,6 +513,18 @@ def reload_scripts(): scripts_postproc = scripts_postprocessing.ScriptPostprocessingRunner() +def add_classes_to_gradio_component(comp): + """ + this adds gradio-* to the component for css styling (ie gradio-button to gr.Button), as well as some others + """ + + comp.elem_classes = ["gradio-" + comp.get_block_name(), *(comp.elem_classes or [])] + + if getattr(comp, 'multiselect', False): + comp.elem_classes.append('multiselect') + + + def IOComponent_init(self, *args, **kwargs): if scripts_current is not None: scripts_current.before_component(self, **kwargs) @@ -521,8 +533,7 @@ def IOComponent_init(self, *args, **kwargs): res = original_IOComponent_init(self, *args, **kwargs) - # this adds gradio-* to every component for css styling (ie gradio-button to gr.Button) - self.elem_classes = ["gradio-" + self.get_block_name(), *(self.elem_classes or [])] + add_classes_to_gradio_component(self) script_callbacks.after_component_callback(self, **kwargs) diff --git a/modules/ui.py b/modules/ui.py index 6e0ac89f..c5b0e876 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1601,11 +1601,13 @@ def create_ui(): for i, k, item in quicksettings_list: component = component_dict[k] + info = opts.data_labels[k] component.change( fn=lambda value, k=k: run_settings_single(value, key=k), inputs=[component], outputs=[component, text_settings], + show_progress=info.refresh is not None, ) text_settings.change( diff --git a/modules/ui_common.py b/modules/ui_common.py index d4e00829..7b752b45 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -129,7 +129,7 @@ Requested path was: {f} generation_info = None with gr.Column(): - with gr.Row(elem_id=f"image_buttons_{tabname}"): + with gr.Row(elem_id=f"image_buttons_{tabname}", elem_classes="image-buttons"): open_folder_button = gr.Button(folder_symbol, visible=not shared.cmd_opts.hide_ui_dir_config) if tabname != "extras": -- cgit v1.2.1 From af2db25c84c9a226ab34959e868fc18740418b4b Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 21 Mar 2023 08:49:08 +0300 Subject: enable queue by default more stylistic changes --- modules/shared.py | 3 ++- modules/ui.py | 4 ++-- modules/ui_extensions.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'modules') diff --git a/modules/shared.py b/modules/shared.py index f28a12cc..0b70d104 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -107,7 +107,8 @@ parser.add_argument("--cors-allow-origins-regex", type=str, help="Allowed CORS o parser.add_argument("--tls-keyfile", type=str, help="Partially enables TLS, requires --tls-certfile to fully function", default=None) parser.add_argument("--tls-certfile", type=str, help="Partially enables TLS, requires --tls-keyfile to fully function", default=None) parser.add_argument("--server-name", type=str, help="Sets hostname of server", default=None) -parser.add_argument("--gradio-queue", action='store_true', help="Uses gradio queue; experimental option; breaks restart UI button") +parser.add_argument("--gradio-queue", action='store_true', help="does not do anything", default=True) +parser.add_argument("--no-gradio-queue", action='store_true', help="Disables gradio queue; causes the webpage to use http requests instead of websockets; was the defaul in earlier versions") parser.add_argument("--skip-version-check", action='store_true', help="Do not check versions of torch and xformers") parser.add_argument("--no-hashing", action='store_true', help="disable sha256 hashing of checkpoints to help loading performance", default=False) parser.add_argument("--no-download-sd-model", action='store_true', help="don't download SD1.5 model even if no model is found in --ckpt-dir", default=False) diff --git a/modules/ui.py b/modules/ui.py index c5b0e876..9b9bfa8b 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -478,7 +478,7 @@ def create_ui(): width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="txt2img_width") height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="txt2img_height") - with gr.Column(elem_id="txt2img_dimensions_row", scale=1): + with gr.Column(elem_id="txt2img_dimensions_row", scale=1, elem_classes="dimensions-tools"): res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn") if opts.dimensions_and_batch_together: @@ -758,7 +758,7 @@ def create_ui(): width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="img2img_width") height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="img2img_height") - with gr.Column(elem_id="img2img_dimensions_row", scale=1): + with gr.Column(elem_id="img2img_dimensions_row", scale=1, elem_classes="dimensions-tools"): res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn") if opts.dimensions_and_batch_together: diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index df75a925..50173e68 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -244,7 +244,7 @@ def refresh_available_extensions_from_data(hide_tags, sort_column): hidden += 1 continue - install_code = f"""""" + install_code = f"""""" tags_text = ", ".join([f"{x}" for x in extension_tags]) -- cgit v1.2.1 From ff216820fd680b5d04ce6cea7bf21e1bbec356b4 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 21 Mar 2023 09:24:19 +0300 Subject: fix extra networks ui --- modules/ui_extra_networks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index cdfd6f2a..8cd6d8cf 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -86,7 +86,7 @@ class ExtraNetworksPage: subdirs = {"": 1, **subdirs} subdirs_html = "".join([f""" - """ for subdir in subdirs]) -- cgit v1.2.1 From 4697def23516ee05fbbb01f8cf6d38e9f3b19dd5 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 25 Mar 2023 07:29:51 +0300 Subject: bump gradio to 3.23 fix broken image dragging --- modules/generation_parameters_copypaste.py | 7 ++++++- modules/images.py | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index 7c0b5b4e..6df76858 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -401,9 +401,14 @@ def connect_paste(button, paste_fields, input_comp, override_settings_component, button.click( fn=paste_func, - _js=f"recalculate_prompts_{tabname}", inputs=[input_comp], outputs=[x[0] for x in paste_fields], ) + button.click( + fn=None, + _js=f"recalculate_prompts_{tabname}", + inputs=[], + outputs=[], + ) diff --git a/modules/images.py b/modules/images.py index 2da988ee..7030aaaa 100644 --- a/modules/images.py +++ b/modules/images.py @@ -645,6 +645,8 @@ Steps: {json_info["steps"]}, Sampler: {sampler}, CFG scale: {json_info["scale"]} def image_data(data): + import gradio as gr + try: image = Image.open(io.BytesIO(data)) textinfo, _ = read_info_from_image(image) @@ -660,7 +662,7 @@ def image_data(data): except Exception: pass - return '', None + return gr.update(), None def flatten(img, bgcolor): -- cgit v1.2.1 From 9ed04e759d8b4a84db1f0e37abee59178fe1f586 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 25 Mar 2023 10:11:04 +0300 Subject: use HTTP request to fetch metadata for Lora cards instead of including it into the main page --- modules/ui_extra_networks.py | 47 +++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 12 deletions(-) (limited to 'modules') diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 8cd6d8cf..3cf8fcb6 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -22,21 +22,37 @@ def register_page(page): allowed_dirs.update(set(sum([x.allowed_directories_for_previews() for x in extra_pages], []))) -def add_pages_to_demo(app): - def fetch_file(filename: str = ""): - from starlette.responses import FileResponse +def fetch_file(filename: str = ""): + from starlette.responses import FileResponse + + if not any([Path(x).absolute() in Path(filename).absolute().parents for x in allowed_dirs]): + raise ValueError(f"File cannot be fetched: {filename}. Must be in one of directories registered by extra pages.") + + ext = os.path.splitext(filename)[1].lower() + if ext not in (".png", ".jpg", ".webp"): + raise ValueError(f"File cannot be fetched: {filename}. Only png and jpg and webp.") + + # would profit from returning 304 + return FileResponse(filename, headers={"Accept-Ranges": "bytes"}) + + +def get_metadata(page: str = "", item: str = ""): + from starlette.responses import JSONResponse - if not any([Path(x).absolute() in Path(filename).absolute().parents for x in allowed_dirs]): - raise ValueError(f"File cannot be fetched: {filename}. Must be in one of directories registered by extra pages.") + page = next(iter([x for x in extra_pages if x.name == page]), None) + if page is None: + return JSONResponse({}) - ext = os.path.splitext(filename)[1].lower() - if ext not in (".png", ".jpg", ".webp"): - raise ValueError(f"File cannot be fetched: {filename}. Only png and jpg and webp.") + metadata = page.metadata.get(item) + if metadata is None: + return JSONResponse({}) - # would profit from returning 304 - return FileResponse(filename, headers={"Accept-Ranges": "bytes"}) + return JSONResponse({"metadata": metadata}) + +def add_pages_to_demo(app): app.add_api_route("/sd_extra_networks/thumb", fetch_file, methods=["GET"]) + app.add_api_route("/sd_extra_networks/metadata", get_metadata, methods=["GET"]) class ExtraNetworksPage: @@ -45,6 +61,7 @@ class ExtraNetworksPage: self.name = title.lower() self.card_page = shared.html("extra-networks-card.html") self.allow_negative_prompt = False + self.metadata = {} def refresh(self): pass @@ -66,6 +83,8 @@ class ExtraNetworksPage: view = shared.opts.extra_networks_default_view items_html = '' + self.metadata = {} + subdirs = {} for parentdir in [os.path.abspath(x) for x in self.allowed_directories_for_previews()]: for x in glob.glob(os.path.join(parentdir, '**/*'), recursive=True): @@ -92,6 +111,10 @@ class ExtraNetworksPage: """ for subdir in subdirs]) for item in self.list_items(): + metadata = item.get("metadata") + if metadata: + self.metadata[item["name"]] = metadata + items_html += self.create_html_for_item(item, tabname) if items_html == '': @@ -127,8 +150,7 @@ class ExtraNetworksPage: metadata_button = "" metadata = item.get("metadata") if metadata: - metadata_onclick = '"' + html.escape(f"""extraNetworksShowMetadata({json.dumps(metadata)}); return false;""") + '"' - metadata_button = f"" + metadata_button = f"" args = { "preview_html": "style='background-image: url(\"" + html.escape(preview) + "\")'" if preview else '', @@ -215,6 +237,7 @@ def create_ui(container, button, tabname): with gr.Tabs(elem_id=tabname+"_extra_tabs") as tabs: for page in ui.stored_extra_pages: with gr.Tab(page.title): + page_elem = gr.HTML(page.create_html(ui.tabname)) ui.pages.append(page_elem) -- cgit v1.2.1