From 40ff6db5325fc34ad4fa35e80cb1e7768d9f7e75 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 21 Jan 2023 08:36:07 +0300 Subject: [PATCH] extra networks UI rework of hypernets: rather than via settings, hypernets are added directly to prompt as --- html/card-no-preview.png | Bin 0 -> 84440 bytes html/extra-networks-card.html | 11 + html/extra-networks-no-cards.html | 8 + javascript/extraNetworks.js | 60 ++++++ javascript/hints.js | 2 + javascript/ui.js | 9 +- modules/api/api.py | 7 +- modules/extra_networks.py | 147 +++++++++++++ modules/extra_networks_hypernet.py | 21 ++ modules/generation_parameters_copypaste.py | 12 +- modules/hypernetworks/hypernetwork.py | 107 +++++++--- modules/hypernetworks/ui.py | 5 +- modules/processing.py | 24 ++- modules/sd_hijack_optimizations.py | 10 +- modules/shared.py | 21 +- .../textual_inversion/textual_inversion.py | 2 + modules/ui.py | 50 +++-- modules/ui_components.py | 10 + modules/ui_extra_networks.py | 149 ++++++++++++++ modules/ui_extra_networks_hypernets.py | 34 +++ .../ui_extra_networks_textual_inversion.py | 32 +++ script.js | 13 +- scripts/xy_grid.py | 29 --- style.css | 194 ++++++++++-------- webui.py | 26 ++- 25 files changed, 767 insertions(+), 216 deletions(-) create mode 100644 html/card-no-preview.png create mode 100644 html/extra-networks-card.html create mode 100644 html/extra-networks-no-cards.html create mode 100644 javascript/extraNetworks.js create mode 100644 modules/extra_networks.py create mode 100644 modules/extra_networks_hypernet.py create mode 100644 modules/ui_extra_networks.py create mode 100644 modules/ui_extra_networks_hypernets.py create mode 100644 modules/ui_extra_networks_textual_inversion.py diff --git a/html/card-no-preview.png b/html/card-no-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..e2beb2692067db56ac5f7bd5bfc3d895d9063371 GIT binary patch literal 84440 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 roT@D7znJ|p0Ht>&Lqv%5#_s +
+
+ +
+ {name} +
+ + diff --git a/html/extra-networks-no-cards.html b/html/extra-networks-no-cards.html new file mode 100644 index 000000000..389358d6c --- /dev/null +++ b/html/extra-networks-no-cards.html @@ -0,0 +1,8 @@ +
+

Nothing here. Add some content to the following directories:

+ +
    +{dirs} +
+
+ diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js new file mode 100644 index 000000000..71e522d16 --- /dev/null +++ b/javascript/extraNetworks.js @@ -0,0 +1,60 @@ + +function setupExtraNetworksForTab(tabname){ + gradioApp().querySelector('#'+tabname+'_extra_tabs').classList.add('extra-networks') + + gradioApp().querySelector('#'+tabname+'_extra_tabs > div').appendChild(gradioApp().getElementById(tabname+'_extra_refresh')) + gradioApp().querySelector('#'+tabname+'_extra_tabs > div').appendChild(gradioApp().getElementById(tabname+'_extra_close')) +} + +var activePromptTextarea = null; +var activePositivePromptTextarea = null; + +function setupExtraNetworks(){ + setupExtraNetworksForTab('txt2img') + setupExtraNetworksForTab('img2img') + + function registerPrompt(id, isNegative){ + var textarea = gradioApp().querySelector("#" + id + " > label > textarea"); + + if (activePromptTextarea == null){ + activePromptTextarea = textarea + } + if (activePositivePromptTextarea == null && ! isNegative){ + activePositivePromptTextarea = textarea + } + + textarea.addEventListener("focus", function(){ + activePromptTextarea = textarea; + if(! isNegative) activePositivePromptTextarea = textarea; + }); + } + + registerPrompt('txt2img_prompt') + registerPrompt('txt2img_neg_prompt', true) + registerPrompt('img2img_prompt') + registerPrompt('img2img_neg_prompt', true) +} + +onUiLoaded(setupExtraNetworks) + +function cardClicked(textToAdd, allowNegativePrompt){ + textarea = allowNegativePrompt ? activePromptTextarea : activePositivePromptTextarea + + textarea.value = textarea.value + " " + textToAdd + updateInput(textarea) + + return false +} + +function saveCardPreview(event, tabname, filename){ + textarea = gradioApp().querySelector("#" + tabname + '_preview_filename > label > textarea') + button = gradioApp().getElementById(tabname + '_save_preview') + + textarea.value = filename + updateInput(textarea) + + button.click() + + event.stopPropagation() + event.preventDefault() +} diff --git a/javascript/hints.js b/javascript/hints.js index e746e20d5..f4079f961 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -21,6 +21,8 @@ titles = { "\U0001F5D1": "Clear prompt", "\u{1f4cb}": "Apply selected styles to current prompt", "\u{1f4d2}": "Paste available values into the field", + "\u{1f3b4}": "Show extra networks", + "Inpaint a part of image": "Draw a mask over an image, and the script will regenerate the masked area with content according to prompt", "SD upscale": "Upscale image normally, split result into tiles, improve each tile using img2img, merge whole image back", diff --git a/javascript/ui.js b/javascript/ui.js index 3ba90ca88..a7e754394 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -196,8 +196,6 @@ function confirm_clear_prompt(prompt, negative_prompt) { return [prompt, negative_prompt] } - - opts = {} onUiUpdate(function(){ if(Object.keys(opts).length != 0) return; @@ -239,11 +237,14 @@ onUiUpdate(function(){ return } + prompt.parentElement.insertBefore(counter, prompt) counter.classList.add("token-counter") prompt.parentElement.style.position = "relative" - textarea.addEventListener("input", () => update_token_counter(id_button)); + textarea.addEventListener("input", function(){ + update_token_counter(id_button); + }); } registerTextarea('txt2img_prompt', 'txt2img_token_counter', 'txt2img_token_button') @@ -261,10 +262,8 @@ onUiUpdate(function(){ }) } } - }) - onOptionsChanged(function(){ elem = gradioApp().getElementById('sd_checkpoint_hash') sd_checkpoint_hash = opts.sd_checkpoint_hash || "" diff --git a/modules/api/api.py b/modules/api/api.py index 9814bbc28..2c371e6e7 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -480,7 +480,7 @@ class Api: def train_hypernetwork(self, args: dict): try: shared.state.begin() - initial_hypernetwork = shared.loaded_hypernetwork + shared.loaded_hypernetworks = [] apply_optimizations = shared.opts.training_xattention_optimizations error = None filename = '' @@ -491,16 +491,15 @@ class Api: except Exception as e: error = e finally: - shared.loaded_hypernetwork = initial_hypernetwork shared.sd_model.cond_stage_model.to(devices.device) shared.sd_model.first_stage_model.to(devices.device) if not apply_optimizations: sd_hijack.apply_optimizations() shared.state.end() - return TrainResponse(info = "train embedding complete: filename: {filename} error: {error}".format(filename = filename, error = error)) + return TrainResponse(info="train embedding complete: filename: {filename} error: {error}".format(filename=filename, error=error)) except AssertionError as msg: shared.state.end() - return TrainResponse(info = "train embedding error: {error}".format(error = error)) + return TrainResponse(info="train embedding error: {error}".format(error=error)) def get_memory(self): try: diff --git a/modules/extra_networks.py b/modules/extra_networks.py new file mode 100644 index 000000000..1978673d7 --- /dev/null +++ b/modules/extra_networks.py @@ -0,0 +1,147 @@ +import re +from collections import defaultdict + +from modules import errors + +extra_network_registry = {} + + +def initialize(): + extra_network_registry.clear() + + +def register_extra_network(extra_network): + extra_network_registry[extra_network.name] = extra_network + + +class ExtraNetworkParams: + def __init__(self, items=None): + self.items = items or [] + + +class ExtraNetwork: + def __init__(self, name): + self.name = name + + def activate(self, p, params_list): + """ + Called by processing on every run. Whatever the extra network is meant to do should be activated here. + Passes arguments related to this extra network in params_list. + User passes arguments by specifying this in his prompt: + + + + Where name matches the name of this ExtraNetwork object, and arg1:arg2:arg3 are any natural number of text arguments + separated by colon. + + Even if the user does not mention this ExtraNetwork in his prompt, the call will stil be made, with empty params_list - + in this case, all effects of this extra networks should be disabled. + + Can be called multiple times before deactivate() - each new call should override the previous call completely. + + For example, if this ExtraNetwork's name is 'hypernet' and user's prompt is: + + > "1girl, " + + params_list will be: + + [ + ExtraNetworkParams(items=["agm", "1.1"]), + ExtraNetworkParams(items=["ray"]) + ] + + """ + raise NotImplementedError + + def deactivate(self, p): + """ + Called at the end of processing for housekeeping. No need to do anything here. + """ + + raise NotImplementedError + + +def activate(p, extra_network_data): + """call activate for extra networks in extra_network_data in specified order, then call + activate for all remaining registered networks with an empty argument list""" + + for extra_network_name, extra_network_args in extra_network_data.items(): + extra_network = extra_network_registry.get(extra_network_name, None) + if extra_network is None: + print(f"Skipping unknown extra network: {extra_network_name}") + continue + + try: + extra_network.activate(p, extra_network_args) + except Exception as e: + errors.display(e, f"activating extra network {extra_network_name} with arguments {extra_network_args}") + + for extra_network_name, extra_network in extra_network_registry.items(): + args = extra_network_data.get(extra_network_name, None) + if args is not None: + continue + + try: + extra_network.activate(p, []) + except Exception as e: + errors.display(e, f"activating extra network {extra_network_name}") + + +def deactivate(p, extra_network_data): + """call deactivate for extra networks in extra_network_data in specified order, then call + deactivate for all remaining registered networks""" + + for extra_network_name, extra_network_args in extra_network_data.items(): + extra_network = extra_network_registry.get(extra_network_name, None) + if extra_network is None: + continue + + try: + extra_network.deactivate(p) + except Exception as e: + errors.display(e, f"deactivating extra network {extra_network_name}") + + for extra_network_name, extra_network in extra_network_registry.items(): + args = extra_network_data.get(extra_network_name, None) + if args is not None: + continue + + try: + extra_network.deactivate(p) + except Exception as e: + errors.display(e, f"deactivating unmentioned extra network {extra_network_name}") + + +re_extra_net = re.compile(r"<(\w+):([^>]+)>") + + +def parse_prompt(prompt): + res = defaultdict(list) + + def found(m): + name = m.group(1) + args = m.group(2) + + res[name].append(ExtraNetworkParams(items=args.split(":"))) + + return "" + + prompt = re.sub(re_extra_net, found, prompt) + + return prompt, res + + +def parse_prompts(prompts): + res = [] + extra_data = None + + for prompt in prompts: + updated_prompt, parsed_extra_data = parse_prompt(prompt) + + if extra_data is None: + extra_data = parsed_extra_data + + res.append(updated_prompt) + + return res, extra_data + diff --git a/modules/extra_networks_hypernet.py b/modules/extra_networks_hypernet.py new file mode 100644 index 000000000..6a0c4ba87 --- /dev/null +++ b/modules/extra_networks_hypernet.py @@ -0,0 +1,21 @@ +from modules import extra_networks +from modules.hypernetworks import hypernetwork + + +class ExtraNetworkHypernet(extra_networks.ExtraNetwork): + def __init__(self): + super().__init__('hypernet') + + def activate(self, p, params_list): + names = [] + multipliers = [] + for params in params_list: + assert len(params.items) > 0 + + names.append(params.items[0]) + multipliers.append(float(params.items[1]) if len(params.items) > 1 else 1.0) + + hypernetwork.load_hypernetworks(names, multipliers) + + def deactivate(p, self): + pass diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index a381ff599..46e12dc6c 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -79,8 +79,6 @@ def integrate_settings_paste_fields(component_dict): from modules import ui settings_map = { - 'sd_hypernetwork': 'Hypernet', - 'sd_hypernetwork_strength': 'Hypernet strength', 'CLIP_stop_at_last_layers': 'Clip skip', 'inpainting_mask_weight': 'Conditional mask weight', 'sd_model_checkpoint': 'Model hash', @@ -275,13 +273,9 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model if "Clip skip" not in res: res["Clip skip"] = "1" - if "Hypernet strength" not in res: - res["Hypernet strength"] = "1" - - if "Hypernet" in res: - hypernet_name = res["Hypernet"] - hypernet_hash = res.get("Hypernet hash", None) - res["Hypernet"] = find_hypernetwork_key(hypernet_name, hypernet_hash) + hypernet = res.get("Hypernet", None) + if hypernet is not None: + res["Prompt"] += f"""""" if "Hires resize-1" not in res: res["Hires resize-1"] = 0 diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 74e785824..80a47c791 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -25,7 +25,6 @@ from statistics import stdev, mean optimizer_dict = {optim_name : cls_obj for optim_name, cls_obj in inspect.getmembers(torch.optim, inspect.isclass) if optim_name != "Optimizer"} class HypernetworkModule(torch.nn.Module): - multiplier = 1.0 activation_dict = { "linear": torch.nn.Identity, "relu": torch.nn.ReLU, @@ -41,6 +40,8 @@ class HypernetworkModule(torch.nn.Module): add_layer_norm=False, activate_output=False, dropout_structure=None): super().__init__() + self.multiplier = 1.0 + assert layer_structure is not None, "layer_structure must not be None" assert layer_structure[0] == 1, "Multiplier Sequence should start with size 1!" assert layer_structure[-1] == 1, "Multiplier Sequence should end with size 1!" @@ -115,7 +116,7 @@ class HypernetworkModule(torch.nn.Module): state_dict[to] = x def forward(self, x): - return x + self.linear(x) * (HypernetworkModule.multiplier if not self.training else 1) + return x + self.linear(x) * (self.multiplier if not self.training else 1) def trainables(self): layer_structure = [] @@ -125,9 +126,6 @@ class HypernetworkModule(torch.nn.Module): return layer_structure -def apply_strength(value=None): - HypernetworkModule.multiplier = value if value is not None else shared.opts.sd_hypernetwork_strength - #param layer_structure : sequence used for length, use_dropout : controlling boolean, last_layer_dropout : for compatibility check. def parse_dropout_structure(layer_structure, use_dropout, last_layer_dropout): if layer_structure is None: @@ -192,6 +190,20 @@ class Hypernetwork: for param in layer.parameters(): param.requires_grad = mode + def to(self, device): + for k, layers in self.layers.items(): + for layer in layers: + layer.to(device) + + return self + + def set_multiplier(self, multiplier): + for k, layers in self.layers.items(): + for layer in layers: + layer.multiplier = multiplier + + return self + def eval(self): for k, layers in self.layers.items(): for layer in layers: @@ -269,11 +281,13 @@ class Hypernetwork: self.optimizer_state_dict = None if self.optimizer_state_dict: self.optimizer_name = optimizer_saved_dict.get('optimizer_name', 'AdamW') - print("Loaded existing optimizer from checkpoint") - print(f"Optimizer name is {self.optimizer_name}") + if shared.opts.print_hypernet_extra: + print("Loaded existing optimizer from checkpoint") + print(f"Optimizer name is {self.optimizer_name}") else: self.optimizer_name = "AdamW" - print("No saved optimizer exists in checkpoint") + if shared.opts.print_hypernet_extra: + print("No saved optimizer exists in checkpoint") for size, sd in state_dict.items(): if type(size) == int: @@ -306,23 +320,43 @@ def list_hypernetworks(path): return res -def load_hypernetwork(filename): - path = shared.hypernetworks.get(filename, None) - # Prevent any file named "None.pt" from being loaded. - if path is not None and filename != "None": - print(f"Loading hypernetwork {filename}") - try: - shared.loaded_hypernetwork = Hypernetwork() - shared.loaded_hypernetwork.load(path) +def load_hypernetwork(name): + path = shared.hypernetworks.get(name, None) - except Exception: - print(f"Error loading hypernetwork {path}", file=sys.stderr) - print(traceback.format_exc(), file=sys.stderr) - else: - if shared.loaded_hypernetwork is not None: - print("Unloading hypernetwork") + if path is None: + return None - shared.loaded_hypernetwork = None + hypernetwork = Hypernetwork() + + try: + hypernetwork.load(path) + except Exception: + print(f"Error loading hypernetwork {path}", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + return None + + return hypernetwork + + +def load_hypernetworks(names, multipliers=None): + already_loaded = {} + + for hypernetwork in shared.loaded_hypernetworks: + if hypernetwork.name in names: + already_loaded[hypernetwork.name] = hypernetwork + + shared.loaded_hypernetworks.clear() + + for i, name in enumerate(names): + hypernetwork = already_loaded.get(name, None) + if hypernetwork is None: + hypernetwork = load_hypernetwork(name) + + if hypernetwork is None: + continue + + hypernetwork.set_multiplier(multipliers[i] if multipliers else 1.0) + shared.loaded_hypernetworks.append(hypernetwork) def find_closest_hypernetwork_name(search: str): @@ -336,18 +370,27 @@ def find_closest_hypernetwork_name(search: str): return applicable[0] -def apply_hypernetwork(hypernetwork, context, layer=None): - hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) +def apply_single_hypernetwork(hypernetwork, context_k, context_v, layer=None): + hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context_k.shape[2], None) if hypernetwork_layers is None: - return context, context + return context_k, context_v if layer is not None: layer.hyper_k = hypernetwork_layers[0] layer.hyper_v = hypernetwork_layers[1] - context_k = hypernetwork_layers[0](context) - context_v = hypernetwork_layers[1](context) + context_k = hypernetwork_layers[0](context_k) + context_v = hypernetwork_layers[1](context_v) + return context_k, context_v + + +def apply_hypernetworks(hypernetworks, context, layer=None): + context_k = context + context_v = context + for hypernetwork in hypernetworks: + context_k, context_v = apply_single_hypernetwork(hypernetwork, context_k, context_v, layer) + return context_k, context_v @@ -357,7 +400,7 @@ def attention_CrossAttention_forward(self, x, context=None, mask=None): q = self.to_q(x) context = default(context, x) - context_k, context_v = apply_hypernetwork(shared.loaded_hypernetwork, context, self) + context_k, context_v = apply_hypernetworks(shared.loaded_hypernetworks, context, self) k = self.to_k(context_k) v = self.to_v(context_v) @@ -464,8 +507,9 @@ def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradi template_file = template_file.path path = shared.hypernetworks.get(hypernetwork_name, None) - shared.loaded_hypernetwork = Hypernetwork() - shared.loaded_hypernetwork.load(path) + hypernetwork = Hypernetwork() + hypernetwork.load(path) + shared.loaded_hypernetworks = [hypernetwork] shared.state.job = "train-hypernetwork" shared.state.textinfo = "Initializing hypernetwork training..." @@ -489,7 +533,6 @@ def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradi else: images_dir = None - hypernetwork = shared.loaded_hypernetwork checkpoint = sd_models.select_checkpoint() initial_step = hypernetwork.step or 0 diff --git a/modules/hypernetworks/ui.py b/modules/hypernetworks/ui.py index 81e3f519b..76599f5ad 100644 --- a/modules/hypernetworks/ui.py +++ b/modules/hypernetworks/ui.py @@ -9,6 +9,7 @@ from modules import devices, sd_hijack, shared not_available = ["hardswish", "multiheadattention"] keys = list(x for x in modules.hypernetworks.hypernetwork.HypernetworkModule.activation_dict.keys() if x not in not_available) + def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None, activation_func=None, weight_init=None, add_layer_norm=False, use_dropout=False, dropout_structure=None): filename = modules.hypernetworks.hypernetwork.create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure, activation_func, weight_init, add_layer_norm, use_dropout, dropout_structure) @@ -16,8 +17,7 @@ def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None, def train_hypernetwork(*args): - - initial_hypernetwork = shared.loaded_hypernetwork + shared.loaded_hypernetworks = [] assert not shared.cmd_opts.lowvram, 'Training models with lowvram is not possible' @@ -34,7 +34,6 @@ Hypernetwork saved to {html.escape(filename)} except Exception: raise finally: - shared.loaded_hypernetwork = initial_hypernetwork shared.sd_model.cond_stage_model.to(devices.device) shared.sd_model.first_stage_model.to(devices.device) sd_hijack.apply_optimizations() diff --git a/modules/processing.py b/modules/processing.py index a3e9f7095..b5deeacf5 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -13,7 +13,7 @@ from skimage import exposure from typing import Any, Dict, List, Optional import modules.sd_hijack -from modules import devices, prompt_parser, masking, sd_samplers, lowvram, generation_parameters_copypaste, script_callbacks +from modules import devices, prompt_parser, masking, sd_samplers, lowvram, generation_parameters_copypaste, script_callbacks, extra_networks from modules.sd_hijack import model_hijack from modules.shared import opts, cmd_opts, state import modules.shared as shared @@ -438,9 +438,6 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iter "Size": f"{p.width}x{p.height}", "Model hash": getattr(p, 'sd_model_hash', None if not opts.add_model_hash_to_info or not shared.sd_model.sd_model_hash else shared.sd_model.sd_model_hash), "Model": (None if not opts.add_model_name_to_info or not shared.sd_model.sd_checkpoint_info.model_name else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', '')), - "Hypernet": (None if shared.loaded_hypernetwork is None else shared.loaded_hypernetwork.name), - "Hypernet hash": (None if shared.loaded_hypernetwork is None else shared.loaded_hypernetwork.shorthash()), - "Hypernet strength": (None if shared.loaded_hypernetwork is None or shared.opts.sd_hypernetwork_strength >= 1 else shared.opts.sd_hypernetwork_strength), "Batch size": (None if p.batch_size < 2 else p.batch_size), "Batch pos": (None if p.batch_size < 2 else position_in_batch), "Variation seed": (None if p.subseed_strength == 0 else all_subseeds[index]), @@ -468,14 +465,12 @@ def process_images(p: StableDiffusionProcessing) -> Processed: try: for k, v in p.override_settings.items(): setattr(opts, k, v) - if k == 'sd_hypernetwork': - shared.reload_hypernetworks() # make onchange call for changing hypernet if k == 'sd_model_checkpoint': - sd_models.reload_model_weights() # make onchange call for changing SD model + sd_models.reload_model_weights() if k == 'sd_vae': - sd_vae.reload_vae_weights() # make onchange call for changing VAE + sd_vae.reload_vae_weights() res = process_images_inner(p) @@ -484,9 +479,11 @@ def process_images(p: StableDiffusionProcessing) -> Processed: if p.override_settings_restore_afterwards: for k, v in stored_opts.items(): setattr(opts, k, v) - if k == 'sd_hypernetwork': shared.reload_hypernetworks() - if k == 'sd_model_checkpoint': sd_models.reload_model_weights() - if k == 'sd_vae': sd_vae.reload_vae_weights() + if k == 'sd_model_checkpoint': + sd_models.reload_model_weights() + + if k == 'sd_vae': + sd_vae.reload_vae_weights() return res @@ -564,10 +561,14 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: cache[0] = (required_prompts, steps) return cache[1] + p.all_prompts, extra_network_data = extra_networks.parse_prompts(p.all_prompts) + with torch.no_grad(), p.sd_model.ema_scope(): with devices.autocast(): p.init(p.all_prompts, p.all_seeds, p.all_subseeds) + extra_networks.activate(p, extra_network_data) + with open(os.path.join(shared.script_path, "params.txt"), "w", encoding="utf8") as file: processed = Processed(p, [], p.seed, "") file.write(processed.infotext(p, 0)) @@ -681,6 +682,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: if opts.grid_save: images.save_image(grid, p.outpath_grids, "grid", p.all_seeds[0], p.all_prompts[0], opts.grid_format, info=infotext(), short_filename=not opts.grid_extended_filename, p=p, grid=True) + extra_networks.deactivate(p, extra_network_data) devices.torch_gc() res = Processed(p, output_images, p.all_seeds[0], infotext(), comments="".join(["\n\n" + x for x in comments]), subseed=p.all_subseeds[0], index_of_first_image=index_of_first_image, infotexts=infotexts) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index cdc63ed74..4fa54329d 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -44,7 +44,7 @@ def split_cross_attention_forward_v1(self, x, context=None, mask=None): q_in = self.to_q(x) context = default(context, x) - context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + context_k, context_v = hypernetwork.apply_hypernetworks(shared.loaded_hypernetworks, context) k_in = self.to_k(context_k) v_in = self.to_v(context_v) del context, context_k, context_v, x @@ -78,7 +78,7 @@ def split_cross_attention_forward(self, x, context=None, mask=None): q_in = self.to_q(x) context = default(context, x) - context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + context_k, context_v = hypernetwork.apply_hypernetworks(shared.loaded_hypernetworks, context) k_in = self.to_k(context_k) v_in = self.to_v(context_v) @@ -203,7 +203,7 @@ def split_cross_attention_forward_invokeAI(self, x, context=None, mask=None): q = self.to_q(x) context = default(context, x) - context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + context_k, context_v = hypernetwork.apply_hypernetworks(shared.loaded_hypernetworks, context) k = self.to_k(context_k) * self.scale v = self.to_v(context_v) del context, context_k, context_v, x @@ -225,7 +225,7 @@ def sub_quad_attention_forward(self, x, context=None, mask=None): q = self.to_q(x) context = default(context, x) - context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + context_k, context_v = hypernetwork.apply_hypernetworks(shared.loaded_hypernetworks, context) k = self.to_k(context_k) v = self.to_v(context_v) del context, context_k, context_v, x @@ -284,7 +284,7 @@ def xformers_attention_forward(self, x, context=None, mask=None): q_in = self.to_q(x) context = default(context, x) - context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + context_k, context_v = hypernetwork.apply_hypernetworks(shared.loaded_hypernetworks, context) k_in = self.to_k(context_k) v_in = self.to_v(context_v) diff --git a/modules/shared.py b/modules/shared.py index 2f3664542..c0e11f184 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -23,6 +23,7 @@ demo = None sd_default_config = os.path.join(script_path, "configs/v1-inference.yaml") sd_model_file = os.path.join(script_path, 'model.ckpt') default_sd_model_file = sd_model_file + parser = argparse.ArgumentParser() parser.add_argument("--config", type=str, default=sd_default_config, help="path to config which constructs model",) parser.add_argument("--ckpt", type=str, default=sd_model_file, help="path to checkpoint of stable diffusion model; if specified, this checkpoint will be added to the list of checkpoints and loaded",) @@ -145,7 +146,7 @@ config_filename = cmd_opts.ui_settings_file os.makedirs(cmd_opts.hypernetwork_dir, exist_ok=True) hypernetworks = {} -loaded_hypernetwork = None +loaded_hypernetworks = [] def reload_hypernetworks(): @@ -153,8 +154,6 @@ def reload_hypernetworks(): global hypernetworks hypernetworks = hypernetwork.list_hypernetworks(cmd_opts.hypernetwork_dir) - hypernetwork.load_hypernetwork(opts.sd_hypernetwork) - class State: @@ -399,8 +398,6 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "sd_vae_checkpoint_cache": OptionInfo(0, "VAE Checkpoints to cache in RAM", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}), "sd_vae": OptionInfo("Automatic", "SD VAE", gr.Dropdown, lambda: {"choices": ["Automatic", "None"] + list(sd_vae.vae_dict)}, refresh=sd_vae.refresh_vae_list), "sd_vae_as_default": OptionInfo(True, "Ignore selected VAE for stable diffusion checkpoints that have their own .vae.pt next to them"), - "sd_hypernetwork": OptionInfo("None", "Hypernetwork", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}, refresh=reload_hypernetworks), - "sd_hypernetwork_strength": OptionInfo(1.0, "Hypernetwork strength", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.001}), "inpainting_mask_weight": OptionInfo(1.0, "Inpainting conditioning mask strength", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), "initial_noise_multiplier": OptionInfo(1.0, "Noise multiplier for img2img", gr.Slider, {"minimum": 0.5, "maximum": 1.5, "step": 0.01 }), "img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors."), @@ -661,3 +658,17 @@ mem_mon.start() def listfiles(dirname): filenames = [os.path.join(dirname, x) for x in sorted(os.listdir(dirname)) if not x.startswith(".")] return [file for file in filenames if os.path.isfile(file)] + + +def html_path(filename): + return os.path.join(script_path, "html", filename) + + +def html(filename): + path = html_path(filename) + + if os.path.exists(path): + with open(path, encoding="utf8") as file: + return file.read() + + return "" diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 5a7be4228..4e90f690f 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -50,6 +50,7 @@ class Embedding: self.sd_checkpoint = None self.sd_checkpoint_name = None self.optimizer_state_dict = None + self.filename = None def save(self, filename): embedding_data = { @@ -182,6 +183,7 @@ class EmbeddingDatabase: embedding.sd_checkpoint_name = data.get('sd_checkpoint_name', None) embedding.vectors = vec.shape[0] embedding.shape = vec.shape[-1] + embedding.filename = path if self.expected_shape == -1 or self.expected_shape == embedding.shape: self.register_embedding(embedding, shared.sd_model) diff --git a/modules/ui.py b/modules/ui.py index 06c11848a..d23b2b8e9 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -20,7 +20,7 @@ import numpy as np 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 +from modules import sd_hijack, sd_models, localization, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML from modules.paths import script_path @@ -90,6 +90,7 @@ refresh_symbol = '\U0001f504' # 🔄 save_style_symbol = '\U0001f4be' # 💾 apply_style_symbol = '\U0001f4cb' # 📋 clear_prompt_symbol = '\U0001F5D1' # 🗑️ +extra_networks_symbol = '\U0001F3B4' # 🎴 def plaintext_to_html(text): @@ -324,6 +325,8 @@ def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: def update_token_counter(text, steps): try: + text, _ = extra_networks.parse_prompt(text) + _, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text]) prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps) @@ -354,10 +357,10 @@ def create_toprow(is_img2img): 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)") with gr.Column(scale=1, elem_id="roll_col"): - paste = gr.Button(value=paste_symbol, elem_id="paste") - save_style = gr.Button(value=save_style_symbol, elem_id="style_create") - prompt_style_apply = gr.Button(value=apply_style_symbol, elem_id="style_apply") - clear_prompt_button = gr.Button(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt") + paste = ToolButton(value=paste_symbol, elem_id="paste") + clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt") + extra_networks_button = ToolButton(value=extra_networks_symbol, elem_id=f"{id_part}_extra_networks") + token_counter = gr.HTML(value="", elem_id=f"{id_part}_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") @@ -395,11 +398,14 @@ def create_toprow(is_img2img): outputs=[], ) - with gr.Row(): + with gr.Row(elem_id=f"{id_part}_styles_row"): prompt_styles = gr.Dropdown(label="Styles", elem_id=f"{id_part}_styles", choices=[k for k, v in shared.prompt_styles.styles.items()], value=[], multiselect=True) create_refresh_button(prompt_styles, shared.prompt_styles.reload, lambda: {"choices": [k for k, v in shared.prompt_styles.styles.items()]}, f"refresh_{id_part}_styles") - return prompt, prompt_styles, negative_prompt, submit, button_interrogate, button_deepbooru, prompt_style_apply, save_style, paste, token_counter, token_button, negative_token_counter, negative_token_button + prompt_style_apply = ToolButton(value=apply_style_symbol, elem_id="style_apply") + save_style = ToolButton(value=save_style_symbol, elem_id="style_create") + + return prompt, prompt_styles, negative_prompt, submit, button_interrogate, button_deepbooru, prompt_style_apply, save_style, paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button def setup_progressbar(*args, **kwargs): @@ -616,11 +622,15 @@ def create_ui(): modules.scripts.scripts_txt2img.initialize_scripts(is_img2img=False) with gr.Blocks(analytics_enabled=False) as txt2img_interface: - txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=False) + txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=False) dummy_component = gr.Label(visible=False) txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="binary", visible=False) + with FormRow(variant='compact', elem_id="txt2img_extra_networks", visible=False) as extra_networks: + from modules import ui_extra_networks + extra_networks_ui = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'txt2img') + with gr.Row().style(equal_height=False): with gr.Column(variant='compact', elem_id="txt2img_settings"): for category in ordered_ui_categories(): @@ -794,14 +804,20 @@ def create_ui(): token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_prompt, steps], outputs=[token_counter]) negative_token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_negative_prompt, steps], outputs=[negative_token_counter]) + ui_extra_networks.setup_ui(extra_networks_ui, txt2img_gallery) + modules.scripts.scripts_current = modules.scripts.scripts_img2img modules.scripts.scripts_img2img.initialize_scripts(is_img2img=True) with gr.Blocks(analytics_enabled=False) as img2img_interface: - img2img_prompt, img2img_prompt_styles, img2img_negative_prompt, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, img2img_paste, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=True) + img2img_prompt, img2img_prompt_styles, img2img_negative_prompt, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, img2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=True) img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="binary", visible=False) + with FormRow(variant='compact', elem_id="img2img_extra_networks", visible=False) as extra_networks: + from modules import ui_extra_networks + extra_networks_ui_img2img = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'img2img') + with FormRow().style(equal_height=False): with gr.Column(variant='compact', elem_id="img2img_settings"): copy_image_buttons = [] @@ -1064,6 +1080,8 @@ def create_ui(): token_button.click(fn=update_token_counter, inputs=[img2img_prompt, steps], outputs=[token_counter]) negative_token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_negative_prompt, steps], outputs=[negative_token_counter]) + ui_extra_networks.setup_ui(extra_networks_ui_img2img, img2img_gallery) + img2img_paste_fields = [ (img2img_prompt, "Prompt"), (img2img_negative_prompt, "Negative prompt"), @@ -1666,10 +1684,8 @@ def create_ui(): 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") - if os.path.exists("html/licenses.html"): - with open("html/licenses.html", encoding="utf8") as file: - with gr.TabItem("Licenses"): - gr.HTML(file.read(), elem_id="licenses") + 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") @@ -1756,11 +1772,9 @@ def create_ui(): if os.path.exists(os.path.join(script_path, "notification.mp3")): audio_notification = gr.Audio(interactive=False, value=os.path.join(script_path, "notification.mp3"), elem_id="audio_notification", visible=False) - if os.path.exists("html/footer.html"): - with open("html/footer.html", encoding="utf8") as file: - footer = file.read() - footer = footer.format(versions=versions_html()) - gr.HTML(footer, elem_id="footer") + footer = shared.html("footer.html") + footer = footer.format(versions=versions_html()) + gr.HTML(footer, elem_id="footer") text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False) settings_submit.click( diff --git a/modules/ui_components.py b/modules/ui_components.py index 97acff062..463244256 100644 --- a/modules/ui_components.py +++ b/modules/ui_components.py @@ -11,6 +11,16 @@ class ToolButton(gr.Button, gr.components.FormComponent): return "button" +class ToolButtonTop(gr.Button, gr.components.FormComponent): + """Small button with single emoji as text, with extra margin at top, fits inside gradio forms""" + + def __init__(self, **kwargs): + super().__init__(variant="tool-top", **kwargs) + + def get_block_name(self): + return "button" + + class FormRow(gr.Row, gr.components.FormComponent): """Same as gr.Row but fits inside gradio forms""" diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py new file mode 100644 index 000000000..253e90f7b --- /dev/null +++ b/modules/ui_extra_networks.py @@ -0,0 +1,149 @@ +import os.path + +from modules import shared +import gradio as gr +import json + +from modules.generation_parameters_copypaste import image_from_url_text + +extra_pages = [] + + +def register_page(page): + """registers extra networks page for the UI; recommend doing it in on_app_started() callback for extensions""" + + extra_pages.append(page) + + +class ExtraNetworksPage: + def __init__(self, title): + self.title = title + self.card_page = shared.html("extra-networks-card.html") + self.allow_negative_prompt = False + + def refresh(self): + pass + + def create_html(self, tabname): + items_html = '' + + for item in self.list_items(): + items_html += self.create_html_for_item(item, tabname) + + if items_html == '': + dirs = "".join([f"
  • {x}
  • " for x in self.allowed_directories_for_previews()]) + items_html = shared.html("extra-networks-no-cards.html").format(dirs=dirs) + + res = "
    " + items_html + "
    " + + return res + + def list_items(self): + raise NotImplementedError() + + def allowed_directories_for_previews(self): + return [] + + def create_html_for_item(self, item, tabname): + preview = item.get("preview", None) + + args = { + "preview_html": "style='background-image: url(" + json.dumps(preview) + ")'" if preview else '', + "prompt": json.dumps(item["prompt"]), + "tabname": json.dumps(tabname), + "local_preview": json.dumps(item["local_preview"]), + "name": item["name"], + "allow_negative_prompt": "true" if self.allow_negative_prompt else "false", + } + + return self.card_page.format(**args) + + +def intialize(): + extra_pages.clear() + + +class ExtraNetworksUi: + def __init__(self): + self.pages = None + self.stored_extra_pages = None + + self.button_save_preview = None + self.preview_target_filename = None + + self.tabname = None + + +def create_ui(container, button, tabname): + ui = ExtraNetworksUi() + ui.pages = [] + ui.stored_extra_pages = extra_pages.copy() + ui.tabname = tabname + + with gr.Tabs(elem_id=tabname+"_extra_tabs") as tabs: + button_refresh = gr.Button('Refresh', elem_id=tabname+"_extra_refresh") + button_close = gr.Button('Close', elem_id=tabname+"_extra_close") + + 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) + + ui.button_save_preview = gr.Button('Save preview', elem_id=tabname+"_save_preview", visible=False) + ui.preview_target_filename = gr.Textbox('Preview save filename', elem_id=tabname+"_preview_filename", visible=False) + + button.click(fn=lambda: gr.update(visible=True), inputs=[], outputs=[container]) + button_close.click(fn=lambda: gr.update(visible=False), inputs=[], outputs=[container]) + + def refresh(): + res = [] + + for pg in ui.stored_extra_pages: + pg.refresh() + res.append(pg.create_html(ui.tabname)) + + return res + + button_refresh.click(fn=refresh, inputs=[], outputs=ui.pages) + + return ui + + +def path_is_parent(parent_path, child_path): + parent_path = os.path.abspath(parent_path) + child_path = os.path.abspath(child_path) + + return os.path.commonpath([parent_path]) == os.path.commonpath([parent_path, child_path]) + + +def setup_ui(ui, gallery): + def save_preview(index, images, filename): + if len(images) == 0: + print("There is no image in gallery to save as a preview.") + return [page.create_html(ui.tabname) for page in ui.stored_extra_pages] + + index = int(index) + index = 0 if index < 0 else index + index = len(images) - 1 if index >= len(images) else index + + img_info = images[index if index >= 0 else 0] + image = image_from_url_text(img_info) + + is_allowed = False + for extra_page in ui.stored_extra_pages: + if any([path_is_parent(x, filename) for x in extra_page.allowed_directories_for_previews()]): + is_allowed = True + break + + assert is_allowed, f'writing to {filename} is not allowed' + + image.save(filename) + + return [page.create_html(ui.tabname) for page in ui.stored_extra_pages] + + ui.button_save_preview.click( + fn=save_preview, + _js="function(x, y, z){console.log(x, y, z); return [selected_gallery_index(), y, z]}", + inputs=[ui.preview_target_filename, gallery, ui.preview_target_filename], + outputs=[*ui.pages] + ) diff --git a/modules/ui_extra_networks_hypernets.py b/modules/ui_extra_networks_hypernets.py new file mode 100644 index 000000000..312dbaf04 --- /dev/null +++ b/modules/ui_extra_networks_hypernets.py @@ -0,0 +1,34 @@ +import os + +from modules import shared, ui_extra_networks + + +class ExtraNetworksPageHypernetworks(ui_extra_networks.ExtraNetworksPage): + def __init__(self): + super().__init__('Hypernetworks') + + def refresh(self): + shared.reload_hypernetworks() + + def list_items(self): + for name, path in shared.hypernetworks.items(): + path, ext = os.path.splitext(path) + previews = [path + ".png", path + ".preview.png"] + + preview = None + for file in previews: + if os.path.isfile(file): + preview = "./file=" + file.replace('\\', '/') + "?mtime=" + str(os.path.getmtime(file)) + break + + yield { + "name": name, + "filename": path, + "preview": preview, + "prompt": f"", + "local_preview": path + ".png", + } + + def allowed_directories_for_previews(self): + return [shared.cmd_opts.hypernetwork_dir] + diff --git a/modules/ui_extra_networks_textual_inversion.py b/modules/ui_extra_networks_textual_inversion.py new file mode 100644 index 000000000..e4a6e3bfb --- /dev/null +++ b/modules/ui_extra_networks_textual_inversion.py @@ -0,0 +1,32 @@ +import os + +from modules import ui_extra_networks, sd_hijack + + +class ExtraNetworksPageTextualInversion(ui_extra_networks.ExtraNetworksPage): + def __init__(self): + super().__init__('Textual Inversion') + self.allow_negative_prompt = True + + def refresh(self): + sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings(force_reload=True) + + def list_items(self): + for embedding in sd_hijack.model_hijack.embedding_db.word_embeddings.values(): + path, ext = os.path.splitext(embedding.filename) + preview_file = path + ".preview.png" + + preview = None + if os.path.isfile(preview_file): + preview = "./file=" + preview_file.replace('\\', '/') + "?mtime=" + str(os.path.getmtime(preview_file)) + + yield { + "name": embedding.name, + "filename": embedding.filename, + "preview": preview, + "prompt": embedding.name, + "local_preview": path + ".preview.png", + } + + def allowed_directories_for_previews(self): + return list(sd_hijack.model_hijack.embedding_db.embedding_dirs) diff --git a/script.js b/script.js index 3345e32b4..97e0bfcf9 100644 --- a/script.js +++ b/script.js @@ -13,6 +13,7 @@ function get_uiCurrentTabContent() { } uiUpdateCallbacks = [] +uiLoadedCallbacks = [] uiTabChangeCallbacks = [] optionsChangedCallbacks = [] let uiCurrentTab = null @@ -20,6 +21,9 @@ let uiCurrentTab = null function onUiUpdate(callback){ uiUpdateCallbacks.push(callback) } +function onUiLoaded(callback){ + uiLoadedCallbacks.push(callback) +} function onUiTabChange(callback){ uiTabChangeCallbacks.push(callback) } @@ -38,8 +42,15 @@ function executeCallbacks(queue, m) { queue.forEach(function(x){runCallback(x, m)}) } +var executedOnLoaded = false; + document.addEventListener("DOMContentLoaded", function() { var mutationObserver = new MutationObserver(function(m){ + if(!executedOnLoaded && gradioApp().querySelector('#txt2img_prompt')){ + executedOnLoaded = true; + executeCallbacks(uiLoadedCallbacks); + } + executeCallbacks(uiUpdateCallbacks, m); const newTab = get_uiCurrentTab(); if ( newTab && ( newTab !== uiCurrentTab ) ) { @@ -53,7 +64,7 @@ document.addEventListener("DOMContentLoaded", function() { /** * Add a ctrl+enter as a shortcut to start a generation */ - document.addEventListener('keydown', function(e) { +document.addEventListener('keydown', function(e) { var handled = false; if (e.key !== undefined) { if((e.key == "Enter" && (e.metaKey || e.ctrlKey || e.altKey))) handled = true; diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 6629f5d5f..b1badec90 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -11,7 +11,6 @@ import modules.scripts as scripts import gradio as gr from modules import images, paths, sd_samplers, processing, sd_models, sd_vae -from modules.hypernetworks import hypernetwork from modules.processing import process_images, Processed, StableDiffusionProcessingTxt2Img from modules.shared import opts, cmd_opts, state import modules.shared as shared @@ -94,28 +93,6 @@ def confirm_checkpoints(p, xs): raise RuntimeError(f"Unknown checkpoint: {x}") -def apply_hypernetwork(p, x, xs): - if x.lower() in ["", "none"]: - name = None - else: - name = hypernetwork.find_closest_hypernetwork_name(x) - if not name: - raise RuntimeError(f"Unknown hypernetwork: {x}") - hypernetwork.load_hypernetwork(name) - - -def apply_hypernetwork_strength(p, x, xs): - hypernetwork.apply_strength(x) - - -def confirm_hypernetworks(p, xs): - for x in xs: - if x.lower() in ["", "none"]: - continue - if not hypernetwork.find_closest_hypernetwork_name(x): - raise RuntimeError(f"Unknown hypernetwork: {x}") - - def apply_clip_skip(p, x, xs): opts.data["CLIP_stop_at_last_layers"] = x @@ -208,8 +185,6 @@ axis_options = [ AxisOption("Prompt order", str_permutations, apply_order, format_value=format_value_join_list), AxisOption("Sampler", str, apply_sampler, format_value=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]), AxisOption("Checkpoint name", str, apply_checkpoint, format_value=format_value, confirm=confirm_checkpoints, cost=1.0, choices=lambda: list(sd_models.checkpoints_list)), - AxisOption("Hypernetwork", str, apply_hypernetwork, format_value=format_value, confirm=confirm_hypernetworks, cost=0.2, choices=lambda: list(shared.hypernetworks)), - AxisOption("Hypernet str.", float, apply_hypernetwork_strength), AxisOption("Sigma Churn", float, apply_field("s_churn")), AxisOption("Sigma min", float, apply_field("s_tmin")), AxisOption("Sigma max", float, apply_field("s_tmax")), @@ -291,7 +266,6 @@ def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend, include_lone_ class SharedSettingsStackHelper(object): def __enter__(self): self.CLIP_stop_at_last_layers = opts.CLIP_stop_at_last_layers - self.hypernetwork = opts.sd_hypernetwork self.vae = opts.sd_vae def __exit__(self, exc_type, exc_value, tb): @@ -299,9 +273,6 @@ class SharedSettingsStackHelper(object): modules.sd_models.reload_model_weights() modules.sd_vae.reload_vae_weights() - hypernetwork.load_hypernetwork(self.hypernetwork) - hypernetwork.apply_strength() - opts.data["CLIP_stop_at_last_layers"] = self.CLIP_stop_at_last_layers diff --git a/style.css b/style.css index 3a515ebdc..5e8bc2ca2 100644 --- a/style.css +++ b/style.css @@ -132,13 +132,6 @@ } #roll_col > button { - min-width: 2em; - min-height: 2em; - max-width: 2em; - max-height: 2em; - flex-grow: 0; - padding-left: 0.25em; - padding-right: 0.25em; margin: 0.1em 0; } @@ -146,9 +139,10 @@ min-width: 0 !important; max-width: 8em !important; margin-right: 1em; + gap: 0; } #interrogate, #deepbooru{ - margin: 0em 0.25em 0.9em 0.25em; + margin: 0em 0.25em 0.5em 0.25em; min-width: 8em; max-width: 8em; } @@ -157,8 +151,17 @@ min-width: 8em !important; } +#txt2img_styles_row, #img2img_styles_row{ + gap: 0.25em; + margin-top: 0.5em; +} + +#txt2img_styles_row > button, #img2img_styles_row > button{ + margin: 0; +} + #txt2img_styles, #img2img_styles{ - margin-top: 1em; + padding: 0; } #txt2img_styles ul, #img2img_styles ul{ @@ -635,16 +638,20 @@ canvas[key="mask"] { background-color: rgb(31 41 55 / var(--tw-bg-opacity)); } -.gr-button-tool{ +.gr-button-tool, .gr-button-tool-top{ max-width: 2.5em; min-width: 2.5em !important; height: 2.4em; +} + +.gr-button-tool{ + margin: 0.6em 0em 0.55em 0; +} + +.gr-button-tool-top, #settings .gr-button-tool{ margin: 1.6em 0.7em 0.55em 0; } -#tab_modelmerger .gr-button-tool{ - margin: 0.6em 0em 0.55em 0; -} #modelmerger_results_container{ margin-top: 1em; @@ -763,81 +770,88 @@ footer { line-height: 2.4em; } -/* The following handles localization for right-to-left (RTL) languages like Arabic. -The rtl media type will only be activated by the logic in javascript/localization.js. -If you change anything above, you need to make sure it is RTL compliant by just running -your changes through converters like https://cssjanus.github.io/ or https://rtlcss.com/. -Then, you will need to add the RTL counterpart only if needed in the rtl section below.*/ -@media rtl { - /* this part was added manually */ - :host { - direction: rtl; - } - select, .file-preview, .gr-text-input, .output-html:has(.performance), #ti_progress { - direction: ltr; - } - #script_list > label > select, - #x_type > label > select, - #y_type > label > select { - direction: rtl; - } - .gr-radio, .gr-checkbox{ - margin-left: 0.25em; - } - - /* automatically generated with few manual modifications */ - .performance .time { - margin-right: unset; - margin-left: 0; - } - .justify-center.overflow-x-scroll { - justify-content: right; - } - .justify-center.overflow-x-scroll button:first-of-type { - margin-left: unset; - margin-right: auto; - } - .justify-center.overflow-x-scroll button:last-of-type { - margin-right: unset; - margin-left: auto; - } - #settings fieldset span.text-gray-500, #settings .gr-block.gr-box span.text-gray-500, #settings label.block span{ - margin-right: unset; - margin-left: 8em; - } - #txt2img_progressbar, #img2img_progressbar, #ti_progressbar{ - right: unset; - left: 0; - } - .progressDiv .progress{ - padding: 0 0 0 8px; - text-align: left; - } - #lightboxModal{ - left: unset; - right: 0; - } - .modalPrev, .modalNext{ - border-radius: 3px 0 0 3px; - } - .modalNext { - right: unset; - left: 0; - border-radius: 0 3px 3px 0; - } - #imageARPreview{ - left:unset; - right:0px; - } - #txt2img_skip, #img2img_skip{ - right: unset; - left: 0px; - } - #context-menu{ - box-shadow:-1px 1px 2px #CE6400; - } - .gr-box > div > div > input.gr-text-input{ - right: unset; - left: 0.5em; - } +#txt2img_extra_networks, #img2img_extra_networks{ + margin-top: -1em; } + +.extra-networks > div > [id *= '_extra_']{ + margin: 0.3em; +} + +.extra-network-cards .nocards{ + margin: 1.25em 0.5em 0.5em 0.5em; +} + +.extra-network-cards .nocards h1{ + font-size: 1.5em; + margin-bottom: 1em; +} + +.extra-network-cards .nocards li{ + margin-left: 0.5em; +} + +.extra-network-cards .card{ + display: inline-block; + margin: 0.5em; + width: 16em; + height: 24em; + box-shadow: 0 0 5px rgba(128, 128, 128, 0.5); + border-radius: 0.2em; + position: relative; + + background-size: auto 100%; + background-position: center; + overflow: hidden; + cursor: pointer; + + background-image: url('./file=html/card-no-preview.png') +} + +.extra-network-cards .card:hover{ + box-shadow: 0 0 2px 0.3em rgba(0, 128, 255, 0.35); +} + +.extra-network-cards .card .actions .additional{ + display: none; +} + +.extra-network-cards .card .actions{ + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 0.5em; + color: white; + background: rgba(0,0,0,0.5); + box-shadow: 0 0 0.25em 0.25em rgba(0,0,0,0.5); + text-shadow: 0 0 0.2em black; +} + +.extra-network-cards .card .actions:hover{ + box-shadow: 0 0 0.75em 0.75em rgba(0,0,0,0.5) !important; +} + +.extra-network-cards .card .actions .name{ + font-size: 1.7em; + font-weight: bold; + line-break: anywhere; +} + +.extra-network-cards .card .actions:hover .additional{ + display: block; +} + +.extra-network-cards .card ul{ + margin: 0.25em 0 0.75em 0.25em; + cursor: unset; +} + +.extra-network-cards .card ul a{ + cursor: pointer; +} + +.extra-network-cards .card ul a:hover{ + color: red; +} + diff --git a/webui.py b/webui.py index 865a73006..e8dd822a6 100644 --- a/webui.py +++ b/webui.py @@ -9,16 +9,18 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.gzip import GZipMiddleware -from modules import import_hook, errors +from modules import import_hook, errors, extra_networks +from modules import extra_networks_hypernet, ui_extra_networks_hypernets, ui_extra_networks_textual_inversion from modules.call_queue import wrap_queued_call, queue_lock, wrap_gradio_gpu_call from modules.paths import script_path import torch + # Truncate version number of nightly/local build of PyTorch to not cause exceptions with CodeFormer or Safetensors if ".dev" in torch.__version__ or "+git" in torch.__version__: torch.__version__ = re.search(r'[\d.]+[\d]', torch.__version__).group(0) -from modules import shared, devices, sd_samplers, upscaler, extensions, localization, ui_tempdir +from modules import shared, devices, sd_samplers, upscaler, extensions, localization, ui_tempdir, ui_extra_networks import modules.codeformer_model as codeformer import modules.extras import modules.face_restoration @@ -84,10 +86,17 @@ def initialize(): shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights())) shared.opts.onchange("sd_vae", wrap_queued_call(lambda: modules.sd_vae.reload_vae_weights()), call=False) shared.opts.onchange("sd_vae_as_default", wrap_queued_call(lambda: modules.sd_vae.reload_vae_weights()), call=False) - shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: shared.reload_hypernetworks())) - shared.opts.onchange("sd_hypernetwork_strength", modules.hypernetworks.hypernetwork.apply_strength) shared.opts.onchange("temp_dir", ui_tempdir.on_tmpdir_changed) + shared.reload_hypernetworks() + + ui_extra_networks.intialize() + ui_extra_networks.register_page(ui_extra_networks_textual_inversion.ExtraNetworksPageTextualInversion()) + ui_extra_networks.register_page(ui_extra_networks_hypernets.ExtraNetworksPageHypernetworks()) + + extra_networks.initialize() + extra_networks.register_extra_network(extra_networks_hypernet.ExtraNetworkHypernet()) + if cmd_opts.tls_keyfile is not None and cmd_opts.tls_keyfile is not None: try: @@ -209,6 +218,15 @@ def webui(): modules.sd_models.list_models() + shared.reload_hypernetworks() + + ui_extra_networks.intialize() + ui_extra_networks.register_page(ui_extra_networks_textual_inversion.ExtraNetworksPageTextualInversion()) + ui_extra_networks.register_page(ui_extra_networks_hypernets.ExtraNetworksPageHypernetworks()) + + extra_networks.initialize() + extra_networks.register_extra_network(extra_networks_hypernet.ExtraNetworkHypernet()) + if __name__ == "__main__": if cmd_opts.nowebui: