diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e5a6a52f..28723f82e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ highly recommended for simple prompts - general: - `rembg` remove backgrounds support for **is-net** model + - **settings** now show markers for all items set to non-default values - pre-create all system folders on startup ## Update for 2023-08-30 diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index 42bb1b1a6..664ac74ca 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit 42bb1b1a62181bf9ef5224015b1189a201ae103c +Subproject commit 664ac74cae218cb4dea4b51bdf6ed2f0c81ebca9 diff --git a/html/locale_en.json b/html/locale_en.json index c7b5c77f3..499af7083 100644 --- a/html/locale_en.json +++ b/html/locale_en.json @@ -2,11 +2,11 @@ {"id":"","label":"📘","localized":"","hint":"Read generation parameters from prompt or last generation if prompt is empty into user interface"}, {"id":"","label":"🚮","localized":"","hint":"Clear prompt"}, {"id":"","label":"🌐","localized":"","hint":"Show/hide extra networks"}, - {"id":"","label":"🧳","localized":"","hint":"Apply selected styles to current prompt"}, - {"id":"","label":"🛅","localized":"","hint":"Save current prompt as style template"}, + {"id":"","label":"⏩","localized":"","hint":"Apply selected styles to current prompt"}, + {"id":"","label":"⬇️","localized":"","hint":"Save current prompt as style template"}, {"id":"","label":"🔄","localized":"","hint":"Refresh"}, - {"id":"","label":"❌","localized":"","hint":"Close"}, - {"id":"","label":"📒","localized":"","hint":"Fill"}, + {"id":"","label":"🛗","localized":"","hint":"Close"}, + {"id":"","label":"⏫","localized":"","hint":"Fill"}, {"id":"","label":"🎲️","localized":"","hint":"Use random seed"}, {"id":"","label":"♻️","localized":"","hint":"Reuse previous seed"}, {"id":"","label":"⇅","localized":"","hint":"Swap values"} diff --git a/javascript/amethyst-nightfall.css b/javascript/amethyst-nightfall.css index 260d05423..fe66d2bf3 100644 --- a/javascript/amethyst-nightfall.css +++ b/javascript/amethyst-nightfall.css @@ -120,7 +120,7 @@ svg.feather.feather-image, .feather .feather-image { display: none } #pnginfo_html2_info { margin-top: -18px; background-color: var(--input-background-fill); padding: var(--input-padding) } #txt2img_tools > div > button, #img2img_tools > div > button { filter: hue-rotate(180deg) saturate(0.5); } #txt2img_tools, #img2img_tools { margin-top: -4px; margin-bottom: -4px; } -#txt2img_styles_row { margin-top: -6px; } +#txt2img_styles_row, #img2img_styles_row { margin-top: -6px; } /* custom elements overrides */ #steps-animation, #controlnet { border-width: 0; } diff --git a/javascript/black-orange.css b/javascript/black-orange.css index 36504c288..b1dd6f66a 100644 --- a/javascript/black-orange.css +++ b/javascript/black-orange.css @@ -115,7 +115,7 @@ svg.feather.feather-image, .feather .feather-image { display: none } #pnginfo_html2_info { margin-top: -18px; background-color: var(--input-background-fill); padding: var(--input-padding) } #txt2img_tools > div > button, #img2img_tools > div > button { filter: hue-rotate(180deg) saturate(0.5); } #txt2img_tools, #img2img_tools { margin-top: -4px; margin-bottom: -4px; } -#txt2img_styles_row { margin-top: -6px; } +#txt2img_styles_row, #img2img_styles_row { margin-top: -6px; } /* custom elements overrides */ #steps-animation, #controlnet { border-width: 0; } diff --git a/javascript/black-teal.css b/javascript/black-teal.css index 346da3d4f..54be70897 100644 --- a/javascript/black-teal.css +++ b/javascript/black-teal.css @@ -18,15 +18,13 @@ --highlight-color: var(--primary-200); --inactive-color: var(--primary--800); --background-color: #000000; -} -.light, .dark { --input-padding: 4px; - --radius-lg: 2px; - --radius-sm: 1px; + --radius-lg: 4px; + --radius-sm: 2px; --spacing-md: 4px; - --spacing-xxl: 12px; - --line-sm: 1.3em; - --line-md: 1.3em; + --spacing-xxl: 8px; + --line-sm: 1.2em; + --line-md: 1.4em; } html { font-size: var(--font-size); } @@ -35,10 +33,10 @@ button { font-size: 1.2rem; max-width: 400px; } img { background-color: var(--background-color); } input[type=checkbox] { background-color: transparent !important; } input[type=range] { height: var(--line-sm); appearance: none; margin-top: 0; min-width: 160px; background-color: var(--background-color); width: 100%; background: transparent; } -input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 18px; cursor: pointer; box-shadow: 2px 2px 3px #111111; background: var(--input-background-fill); border-radius: var(--radius-lg); border: 0px solid #222222; } -input[type=range]::-moz-range-track { width: 100%; height: 18px; cursor: pointer; box-shadow: 2px 2px 3px #111111; background: var(--input-background-fill); border-radius: var(--radius-lg); border: 0px solid #222222; } -input[type=range]::-webkit-slider-thumb { box-shadow: 2px 2px 3px #111111; border: 0px solid #000000; height: 18px; width: 40px; border-radius: var(--radius-lg); background: var(--highlight-color); cursor: pointer; appearance: none; margin-top: 0px; } -input[type=range]::-moz-range-thumb { box-shadow: 2px 2px 3px #111111; border: 0px solid #000000; height: 18px; width: 40px; border-radius: var(--radius-lg); background: var(--highlight-color); cursor: pointer; appearance: none; margin-top: 0px; } +input[type=range]::-webkit-slider-runnable-track { width: 100%; height: var(--line-sm); cursor: pointer; box-shadow: 2px 2px 3px #111111; background: var(--input-background-fill); border-radius: var(--radius-lg); border: 0px solid #222222; } +input[type=range]::-moz-range-track { width: 100%; height: var(--line-sm); cursor: pointer; box-shadow: 2px 2px 3px #111111; background: var(--input-background-fill); border-radius: var(--radius-lg); border: 0px solid #222222; } +input[type=range]::-webkit-slider-thumb { box-shadow: 2px 2px 3px #111111; border: 0px solid #000000; height: var(--line-sm); width: var(--line-sm); border-radius: var(--radius-lg); background: var(--highlight-color); cursor: pointer; appearance: none; margin-top: 0px; } +input[type=range]::-moz-range-thumb { box-shadow: 2px 2px 3px #111111; border: 0px solid #000000; height: var(--line-sm); width: var(--line-sm); border-radius: var(--radius-lg); background: var(--highlight-color); cursor: pointer; appearance: none; margin-top: 0px; } ::-webkit-scrollbar { width: 12px; } ::-webkit-scrollbar-track { background: #333333; } ::-webkit-scrollbar-thumb { background-color: var(--highlight-color); border-radius: var(--radius-lg); border-width: 0; box-shadow: 2px 2px 3px #111111; } @@ -74,7 +72,7 @@ svg.feather.feather-image, .feather .feather-image { display: none } .tab-nav { zoom: 120%; margin-bottom: 10px; border-bottom: 2px solid var(--highlight-color) !important; padding-bottom: 2px; } .label-wrap { margin: 16px 0px 8px 0px; } .gradio-slider input[type="number"] { width: 4.5em; font-size: 0.8rem; height: 20px; } -.gradio-button.tool { border: none; background: none; box-shadow: none; } +.gradio-button.tool { border: none; background: none; box-shadow: none; filter: hue-rotate(340deg) saturate(0.5); } #tab_extensions table td, #tab_extensions table th { border: none; padding: 0.5em; } #tab_extensions table { width: 96vw } #tab_extensions table thead { background-color: var(--neutral-700); } @@ -85,7 +83,9 @@ svg.feather.feather-image, .feather .feather-image { display: none } .gallery-item { box-shadow: none !important; } .performance { color: #888; } .extra-networks { border-left: 2px solid var(--highlight-color) !important; padding-left: 4px; } -.image-buttons { gap: 10px !important} +.image-buttons { gap: 10px !important; justify-content: center; } +.image-buttons > button { max-width: 160px; } +#system_row > button, #settings_row > button, #config_row > button { max-width: 190px; } /* gradio elements overrides */ #div.gradio-container { overflow-x: hidden; } @@ -113,7 +113,6 @@ svg.feather.feather-image, .feather .feather-image { display: none } #txt2img_results, #img2img_results, #extras_results { background-color: var(--background-color); padding: 0; } #txt2img_settings { min-width: var(--left-column); max-width: var(--left-column); background-color: #111111; padding-top: 16px; } #pnginfo_html2_info { margin-top: -18px; background-color: var(--input-background-fill); padding: var(--input-padding) } -#txt2img_tools > div > button, #img2img_tools > div > button { filter: hue-rotate(340deg) saturate(0.5); } #txt2img_tools, #img2img_tools { margin-top: -4px; margin-bottom: -4px; } #txt2img_styles_row, #img2img_styles_row { margin-top: -6px; } diff --git a/javascript/settings.js b/javascript/settings.js index d9e96dcf8..1b48491d3 100644 --- a/javascript/settings.js +++ b/javascript/settings.js @@ -45,6 +45,7 @@ function markIfModified(setting_name, value) { const changed_value = previous_value !== current_value; if (changed_value) elem.title = `click to revert to previous value: ${previous_value}`; const is_stored = opts_metadata[setting_name].is_stored; + if (is_stored) console.log('A', opts_metadata[setting_name]); if (is_stored) elem.title = 'custom value'; elem.disabled = !changed_value && !is_stored; elem.classList.toggle('changed', changed_value); diff --git a/javascript/style.css b/javascript/style.css index c5a72bfdf..866a1bb5a 100644 --- a/javascript/style.css +++ b/javascript/style.css @@ -239,7 +239,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt .extra-network-cards .card { height: fit-content; margin: 0.5em; position: relative; scroll-snap-align: start; scroll-margin-top: 0; } .extra-network-cards .card .overlay { position: absolute; bottom: 0; padding: 0.2em; z-index: 10; width: 100%; background: none; } .extra-network-cards .card:hover .overlay { background: rgba(0, 0, 0, 0.40); } -.extra-network-cards .card .overlay .name { font-size: 1.2em; font-weight: bold; line-break: anywhere; text-shadow: 1px 1px black; color: white; } +.extra-network-cards .card .overlay .name { font-size: 1.1em; font-weight: bold; text-shadow: 1px 1px black; color: white; } .extra-network-cards .card .overlay .tags { margin: 4px; display: none; overflow-wrap: break-word; } .extra-network-cards .card .overlay .tag { padding: 2px; margin: 2px; background: var(--neutral-700); cursor: pointer; display: inline-block; } .extra-network-cards .card .overlay .actions { font-size: 2.2em; display: none; text-align-last: center; cursor: pointer; font-variant: unicase; height: 0.8em } diff --git a/modules/loader.py b/modules/loader.py new file mode 100644 index 000000000..a578ca602 --- /dev/null +++ b/modules/loader.py @@ -0,0 +1,37 @@ +from __future__ import annotations +import re +import logging +import warnings +import urllib3 +from modules import timer, errors + +initialized = False +logging.getLogger("DeepSpeed").disabled = True +import torch # pylint: disable=C0411 +try: + import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import +except Exception: + pass +errors.log.debug(f'Loaded Torch=={torch.__version__}') +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) +import torchvision # pylint: disable=W0611,C0411 +import pytorch_lightning # pytorch_lightning should be imported after torch, but it re-enables warnings on import so import once to disable them # pylint: disable=W0611,C0411 +if ".dev" in torch.__version__ or "+git" in torch.__version__: + torch.__long_version__ = torch.__version__ + torch.__version__ = re.search(r'[\d.]+[\d]', torch.__version__).group(0) +logging.getLogger("xformers").addFilter(lambda record: 'A matching Triton is not available' not in record.getMessage()) +logging.getLogger("pytorch_lightning").disabled = True +warnings.filterwarnings(action="ignore", category=DeprecationWarning) +warnings.filterwarnings(action="ignore", category=FutureWarning) +warnings.filterwarnings(action="ignore", category=UserWarning, module="torchvision") +timer.startup.record("torch") + +from fastapi import FastAPI # pylint: disable=W0611,C0411 +import gradio # pylint: disable=W0611,C0411 +errors.log.debug(f'Loaded Gradio=={gradio.__version__}') +timer.startup.record("gradio") +errors.install([gradio]) + +import diffusers # pylint: disable=W0611,C0411 +errors.log.debug(f'Loaded Diffusers=={diffusers.__version__}') +timer.startup.record("diffusers") diff --git a/modules/modelloader.py b/modules/modelloader.py index 6468a9c70..fc456882a 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -244,12 +244,9 @@ def directory_has_changed(dir:str, *, recursive:bool=True) -> bool: # pylint: di def directory_directories(dir:str, *, recursive:bool=True) -> dict[str,tuple[float,list[str]]]: # pylint: disable=redefined-builtin dir = os.path.abspath(dir) if directory_has_changed(dir, recursive=recursive): - for _dir in modelloader_directories: - try: - if (os.path.exists(_dir) and os.path.isdir(_dir)): - continue - except Exception: - pass + for _dir in list(modelloader_directories): + if os.path.exists(_dir) or os.path.isdir(_dir): + continue del modelloader_directories[_dir] for _dir, _files in walk(dir, lambda e, path: shared.log.debug(f"FS walk error: {e} {path}")): try: diff --git a/modules/processing.py b/modules/processing.py index 0ab9a8c83..61fa941b1 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -27,6 +27,9 @@ import modules.sd_models as sd_models import modules.sd_vae as sd_vae +opt_C = 4 +opt_f = 8 + def setup_color_correction(image): shared.log.debug("Calibrating color correction.") correction_target = cv2.cvtColor(np.asarray(image.copy()), cv2.COLOR_RGB2LAB) @@ -933,8 +936,8 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): self.extra_generation_params["Hires steps"] = self.hr_second_pass_steps if self.hr_upscaler is not None: self.extra_generation_params["Hires upscaler"] = self.hr_upscaler + shared.log.debug(f'Init hires: upscaler={self.hr_upscaler} sampler={self.latent_sampler} resize={self.hr_resize_x}x{self.hr_resize_y} upscale={self.hr_upscale_to_x}x{self.hr_upscale_to_y}') self.extra_generation_params["Secondary sampler"] = self.latent_sampler - shared.log.debug(f'Init hires: upscaler={self.hr_upscaler} sampler={self.latent_sampler} resize={self.hr_resize_x}x{self.hr_resize_y} upscale={self.hr_upscale_to_x}x{self.hr_upscale_to_y}') def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength, prompts): diff --git a/modules/scripts.py b/modules/scripts.py index bfd04c30e..30136b561 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -4,7 +4,7 @@ import sys import time from collections import namedtuple import gradio as gr -from modules import paths, script_callbacks, extensions, script_loading, scripts_postprocessing, errors +from modules import paths, script_callbacks, extensions, script_loading, scripts_postprocessing, errors, timer from installer import log @@ -226,13 +226,14 @@ def list_files_with_name(filename): def load_scripts(): + t = timer.Timer() + t0 = time.time() global current_basedir # pylint: disable=global-statement scripts_data.clear() postprocessing_scripts_data.clear() script_callbacks.clear_callbacks() scripts_list = list_scripts("scripts", ".py") syspath = sys.path - time_load = {} def register_scripts_from_module(module, scriptfile): for script_class in module.__dict__.values(): @@ -245,7 +246,6 @@ def load_scripts(): postprocessing_scripts_data.append(ScriptClassData(script_class, scriptfile.path, scriptfile.basedir, module)) for scriptfile in scripts_list: - t0 = time.time() try: if scriptfile.basedir != paths.script_path: sys.path = [scriptfile.basedir] + sys.path @@ -256,7 +256,7 @@ def load_scripts(): errors.display(e, f'Loading script: {scriptfile.filename}') finally: current_basedir = paths.script_path - time_load[scriptfile.basedir] = time_load.get(scriptfile.basedir, 0) + (time.time()-t0) + t.record(os.path.basename(scriptfile.basedir)) sys.path = syspath global scripts_txt2img, scripts_img2img, scripts_postproc # pylint: disable=global-statement @@ -264,8 +264,7 @@ def load_scripts(): scripts_img2img = ScriptRunner() scripts_postproc = scripts_postprocessing.ScriptPostprocessingRunner() - time_summary = [f'{os.path.basename(k)}:{round(v,3)}s' for (k,v) in time_load.items() if v > 0.05] - log.debug(f'Scripts load: {time_summary}') + return t, time.time()-t0 def wrap_call(func, filename, funcname, *args, default=None, **kwargs): diff --git a/modules/sd_models.py b/modules/sd_models.py index 7c0d79413..597147d9e 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -403,7 +403,8 @@ def load_model_weights(model: torch.nn.Module, checkpoint_info: CheckpointInfo, try: model.load_state_dict(state_dict, strict=False) except Exception as e: - shared.log.error(f'Error loading model weights: {checkpoint_info.filename} {e}') + shared.log.error(f'Error loading model weights: {checkpoint_info.filename}') + shared.log.error(' '.join(str(e).splitlines()[:2])) return False del state_dict timer.record("apply") @@ -813,7 +814,8 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No shared.opts.diffusers_move_base=True shared.opts.diffusers_move_refiner=True shared.log.debug('Moving base model to CPU') - model_data.sd_model.to(devices.cpu) + if model_data.sd_model is not None: + model_data.sd_model.to(devices.cpu) devices.torch_gc(force=True) sd_model.to(devices.device) base_sent_to_cpu=True @@ -1007,7 +1009,10 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None, model_data.sd_model = sd_model current_checkpoint_info = None unload_model_weights(op=op) - shared.log.debug(f'Model weights unloaded: {memory_stats()}') + shared.log.debug(f'Model weights unloaded: {memory_stats()} op={op}') + if op == 'refiner': + # shared.opts.data['sd_model_refiner'] = 'None' + shared.opts.sd_model_refiner = 'None' return else: shared.log.debug(f'Model weights loaded: {memory_stats()}') @@ -1062,12 +1067,12 @@ def reload_model_weights(sd_model=None, info=None, reuse_dict=False, op='model') lowvram.send_everything_to_cpu() else: sd_model.to(devices.cpu) - if (reuse_dict or (shared.opts.model_reuse_dict and sd_model is not None)) and not sd_model.has_accelerate: - shared.log.info('Reusing previous model dictionary') - sd_hijack.model_hijack.undo_hijack(sd_model) - else: - unload_model_weights(op=op) - sd_model = None + if (reuse_dict or shared.opts.model_reuse_dict) and not sd_model.has_accelerate: + shared.log.info('Reusing previous model dictionary') + sd_hijack.model_hijack.undo_hijack(sd_model) + else: + unload_model_weights(op=op) + sd_model = None timer = Timer() state_dict = get_checkpoint_state_dict(checkpoint_info, timer) checkpoint_config = sd_models_config.find_checkpoint_config(state_dict, checkpoint_info) @@ -1095,7 +1100,7 @@ def reload_model_weights(sd_model=None, info=None, reuse_dict=False, op='model') timer.record("hijack") script_callbacks.model_loaded_callback(sd_model) timer.record("callbacks") - if not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram and not sd_model.has_accelerate: + if sd_model is not None and not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram and not sd_model.has_accelerate: sd_model.to(devices.device) timer.record("device") shared.log.info(f"Weights loaded in {timer.summary()}") diff --git a/modules/shared.py b/modules/shared.py index 7b5d44692..7eea2b708 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -635,7 +635,7 @@ options_templates.update(options_section(('extra_networks', "Extra Networks"), { "extra_networks_height": OptionInfo(53, "UI height (%)", gr.Slider, {"minimum": 10, "maximum": 100, "step": 1}), "extra_networks_sidebar_width": OptionInfo(35, "UI sidebar width (%)", gr.Slider, {"minimum": 10, "maximum": 80, "step": 1}), "extra_networks_card_lazy": OptionInfo(True, "UI card preview lazy loading"), - "extra_networks_card_size": OptionInfo(200, "UI card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}), + "extra_networks_card_size": OptionInfo(160, "UI card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}), "extra_networks_card_square": OptionInfo(True, "UI disable variable aspect ratio"), "extra_networks_card_fit": OptionInfo("cover", "UI image contain method", gr.Radio, lambda: {"choices": ["contain", "cover", "fill"]}), "extra_network_skip_indexing": OptionInfo(False, "Do not automatically build extra network pages", gr.Checkbox), @@ -767,7 +767,7 @@ class Options: d = {k: self.data.get(k, self.data_labels.get(k).default) for k in self.data_labels.keys()} metadata = { k: { - "is_stored": k in self.data, + "is_stored": k in self.data and self.data[k] != self.data_labels[k].default, "tab_name": v.section[0] } for k, v in self.data_labels.items() } diff --git a/modules/timer.py b/modules/timer.py index 17dfac4f0..55a5e29ec 100644 --- a/modules/timer.py +++ b/modules/timer.py @@ -21,18 +21,15 @@ class Timer: self.records[category] += e + extra_time self.total += e + extra_time - def summary(self): - res = f"{self.total:.1f}s" - - additions = [x for x in self.records.items() if x[1] >= 0.05] + def summary(self, min_time=0.05): + res = f"{self.total:.2f}s" + additions = [x for x in self.records.items() if x[1] >= min_time] if not additions: return res - - res += " (" - res += " ".join([f"{category}={time_taken:.1f}s" for category, time_taken in additions]) - res += ")" - + res += " { " + " ".join([f"{category}={time_taken:.2f}s" for category, time_taken in additions]) + " }" return res def reset(self): self.__init__() + +startup = Timer() diff --git a/modules/ui.py b/modules/ui.py index 0c914847e..a5a61f7cf 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -16,6 +16,8 @@ from modules.paths import script_path, data_path from modules.shared import opts, cmd_opts, readfile from modules.dml import directml_override_opts from modules import prompt_parser +from modules import timer +import modules.ui_symbols as symbols import modules.codeformer_model import modules.generation_parameters_copypaste as parameters_copypaste import modules.gfpgan_model @@ -50,19 +52,6 @@ sample_img2img = "assets/stable-samples/img2img/sketch-mountains-input.jpg" sample_img2img = sample_img2img if os.path.exists(sample_img2img) else None paste_function = None -# Using constants for these since the variation selector isn't visible. -# Important that they exactly match script.js for tooltip to work. -random_symbol = '\U0001f3b2\ufe0f' # 🎲️ -reuse_symbol = '\u267b\ufe0f' # ♻️ -paste_symbol = '\U0001F4D8' # '\u2199\ufe0f' # ↙ -refresh_symbol = '\U0001F504' # 🔄 -save_style_symbol = '\U0001F6C5' # '\U0001f4be' # 💾 -apply_style_symbol = '\U0001F9F3' # '\U0001f4cb' # 📋 -clear_prompt_symbol = '\U0001F6AE' # '\U0001f5d1\ufe0f' # 🗑️ -extra_networks_symbol = '\U0001F310' # '\U0001F3B4' # 🎴 -switch_values_symbol = '\U000021C5' # ⇅ -detect_image_size_symbol = '\U0001F4D0' # 📐 - def create_output_panel(tabname, outdir): # may be referenced by extensions a, b, c, _d, e = ui_common.create_output_panel(tabname, outdir) @@ -161,13 +150,13 @@ def create_seed_inputs(tab, visible): with FormRow(elem_id=f"{tab}_seed_row", variant="compact"): seed = gr.Number(label='Seed', value=-1, elem_id=f"{tab}_seed") seed.style(container=False) - random_seed = ToolButton(random_symbol, elem_id=f"{tab}_random_seed", label='Random seed') - reuse_seed = ToolButton(reuse_symbol, elem_id=f"{tab}_reuse_seed", label='Reuse seed') + random_seed = ToolButton(symbols.random, elem_id=f"{tab}_random_seed", label='Random seed') + reuse_seed = ToolButton(symbols.reuse, elem_id=f"{tab}_reuse_seed", label='Reuse seed') with FormRow(visible=True, elem_id=f"{tab}_subseed_row"): subseed = gr.Number(label='Variation seed', value=-1, elem_id=f"{tab}_subseed") subseed.style(container=False) - random_subseed = ToolButton(random_symbol, elem_id=f"{tab}_random_subseed") - reuse_subseed = ToolButton(reuse_symbol, elem_id=f"{tab}_reuse_subseed") + random_subseed = ToolButton(symbols.random, elem_id=f"{tab}_random_subseed") + reuse_subseed = ToolButton(symbols.reuse, elem_id=f"{tab}_reuse_subseed") subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01, elem_id=f"{tab}_subseed_strength") with FormRow(visible=False): seed_resize_from_w = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from width", value=0, elem_id=f"{tab}_seed_resize_from_w") @@ -268,11 +257,11 @@ def create_toprow(is_img2img): pause = gr.Button('Pause', elem_id=f"{id_part}_pause") pause.click(fn=lambda: modules.shared.state.pause(), _js='checkPaused', inputs=[], outputs=[]) with gr.Row(elem_id=f"{id_part}_tools"): - paste = ToolButton(value=paste_symbol, elem_id="paste") - clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt_btn") - extra_networks_button = ToolButton(value=extra_networks_symbol, elem_id=f"{id_part}_extra_networks_btn") - prompt_style_apply = ToolButton(value=apply_style_symbol, elem_id=f"{id_part}_style_apply_btn") - save_style = ToolButton(value=save_style_symbol, elem_id=f"{id_part}_style_create_btn") + paste = ToolButton(value=symbols.paste, elem_id="paste") + clear_prompt_button = ToolButton(value=symbols.clear, elem_id=f"{id_part}_clear_prompt_btn") + extra_networks_button = ToolButton(value=symbols.networks, elem_id=f"{id_part}_extra_networks_btn") + prompt_style_apply = ToolButton(value=symbols.apply, elem_id=f"{id_part}_style_apply_btn") + save_style = ToolButton(value=symbols.save, elem_id=f"{id_part}_style_create_btn") clear_prompt_button.click(fn=lambda *x: x, _js="confirm_clear_prompt", inputs=[prompt, negative_prompt], outputs=[prompt, negative_prompt]) with gr.Row(elem_id=f"{id_part}_counters"): token_counter = gr.HTML(value="0/75", elem_id=f"{id_part}_token_counter", elem_classes=["token-counter"]) @@ -348,8 +337,7 @@ def create_override_settings_dropdown(tabname, row): # pylint: disable=unused-ar def create_ui(startup_timer = None): if startup_timer is None: - from modules import timer - startup_timer = timer.Timer() + timer.startup = timer.Timer() reload_javascript() parameters_copypaste.reset() ui_defaults = readfile(cmd_opts.ui_config) @@ -372,7 +360,7 @@ def create_ui(startup_timer = None): with FormRow(): width = gr.Slider(minimum=64, maximum=4096, step=8, label="Width", value=512, elem_id="txt2img_width") height = gr.Slider(minimum=64, maximum=4096, step=8, label="Height", value=512, elem_id="txt2img_height") - res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn", label="Switch dims") + res_switch_btn = ToolButton(value=symbols.switch, elem_id="txt2img_res_switch_btn", label="Switch dims") with FormRow(elem_classes="checkboxes-row", variant="compact"): show_batch = gr.Checkbox(label='Batch', value=ui_defaults.get('txt2img/Batch/value', False), elem_id="txt2img_show_batch") @@ -384,7 +372,7 @@ def create_ui(startup_timer = None): with FormRow(elem_id="txt2img_row_batch"): batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count") batch_size = gr.Slider(minimum=1, maximum=32, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size") - batch_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_batch_switch_btn", label="Switch dims") + batch_switch_btn = ToolButton(value=symbols.switch, elem_id="txt2img_batch_switch_btn", label="Switch dims") seed_group, seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = create_seed_inputs('txt2img', show_seed.value) @@ -535,7 +523,7 @@ def create_ui(startup_timer = None): ui_extra_networks.setup_ui(extra_networks_ui, txt2img_gallery) log.debug(f'UI interface: tab=txt2img batch={show_batch.value} seed={show_seed.value} advanced={show_advanced.value} second_pass={show_second_pass.value}') - startup_timer.record("ui-txt2img") + timer.startup.record("ui-txt2img") import modules.img2img # pylint: disable=redefined-outer-name modules.scripts.scripts_current = modules.scripts.scripts_img2img @@ -647,8 +635,8 @@ def create_ui(startup_timer = None): height = gr.Slider(minimum=64, maximum=4096, step=8, label="Height", value=512, elem_id="img2img_height") with gr.Column(elem_id="img2img_column_dim", scale=1, elem_classes="dimensions-tools"): with FormRow(): - res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn") - detect_image_size_btn = ToolButton(value=detect_image_size_symbol, elem_id="img2img_detect_image_size_btn") + res_switch_btn = ToolButton(value=symbols.switch, elem_id="img2img_res_switch_btn") + detect_image_size_btn = ToolButton(value=symbols.detect, elem_id="img2img_detect_image_size_btn") with gr.Tab(label="Resize by") as tab_scale_by: scale_by = gr.Slider(minimum=0.05, maximum=4.0, step=0.05, label="Scale", value=1.0, elem_id="img2img_scale") @@ -895,21 +883,21 @@ def create_ui(startup_timer = None): log.debug(f'UI interface: tab=img2img seed={show_seed.value} resize={show_resize.value} batch={show_batch.value} denoise={show_denoise.value} advanced={show_advanced.value}') - startup_timer.record("ui-img2img") + timer.startup.record("ui-img2img") modules.scripts.scripts_current = None with gr.Blocks(analytics_enabled=False) as extras_interface: ui_postprocessing.create_ui() - startup_timer.record("ui-extras") + timer.startup.record("ui-extras") with gr.Blocks(analytics_enabled=False) as train_interface: ui_train.create_ui(txt2img_preview_params = [txt2img_prompt, txt2img_negative_prompt, steps, sampler_index, cfg_scale, seed, width, height]) - startup_timer.record("ui-train") + timer.startup.record("ui-train") with gr.Blocks(analytics_enabled=False) as models_interface: ui_models.create_ui() - startup_timer.record("ui-models") + timer.startup.record("ui-models") def create_setting_component(key, is_quicksettings=False): def fun(): @@ -1015,7 +1003,7 @@ def create_ui(startup_timer = None): return get_value_for_setting(key), opts.dumpjson() with gr.Blocks(analytics_enabled=False) as settings_interface: - with gr.Row(): + with gr.Row(elem_id="system_row"): restart_submit = gr.Button(value="Restart server", variant='primary', elem_id="restart_submit") shutdown_submit = gr.Button(value="Shutdown server", variant='primary', elem_id="shutdown_submit") unload_sd_model = gr.Button(value='Unload checkpoint', variant='primary', elem_id="sett_unload_sd_model") @@ -1025,7 +1013,7 @@ def create_ui(startup_timer = None): global ui_system_tabs # pylint: disable=global-statement ui_system_tabs = system_tabs with gr.TabItem("Settings", id="system_settings", elem_id="tab_settings"): - with gr.Row(): + with gr.Row(elem_id="settings_row"): settings_submit = gr.Button(value="Apply settings", variant='primary', elem_id="settings_submit") preview_theme = gr.Button(value="Preview theme", variant='primary', elem_id="settings_preview_theme") defaults_submit = gr.Button(value="Restore defaults", variant='primary', elem_id="defaults_submit") @@ -1096,7 +1084,7 @@ def create_ui(startup_timer = None): request_notifications.click(fn=lambda: None, inputs=[], outputs=[], _js='function(){}') preview_theme.click(fn=None, _js='preview_theme', inputs=[dummy_component], outputs=[dummy_component]) - startup_timer.record("ui-settings") + timer.startup.record("ui-settings") interfaces = [ (txt2img_interface, "From Text", "txt2img"), @@ -1109,7 +1097,7 @@ def create_ui(startup_timer = None): interfaces += [(settings_interface, "System", "system")] extensions_interface = ui_extensions.create_ui() interfaces += [(extensions_interface, "Extensions", "extensions")] - startup_timer.record("ui-extensions") + timer.startup.record("ui-extensions") modules.shared.tab_names = [] for _interface, label, _ifid in interfaces: @@ -1183,7 +1171,7 @@ def create_ui(startup_timer = None): queue=False, ) - startup_timer.record("ui-defaults") + timer.startup.record("ui-defaults") loadsave.dump_defaults() demo.ui_loadsave = loadsave return demo diff --git a/modules/ui_common.py b/modules/ui_common.py index 1b0484cc0..58ea9f8f8 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -7,12 +7,10 @@ import subprocess import gradio as gr from modules import call_queue, shared from modules.generation_parameters_copypaste import image_from_url_text +import modules.ui_symbols as symbols import modules.images -folder_symbol = '\U0001f4c2' # 📂 - - def update_generation_info(generation_info, html_info, img_index): try: generation_info = json.loads(generation_info) @@ -224,7 +222,6 @@ def create_refresh_button(refresh_component, refresh_method, refreshed_args, ele return gr.update(**(args or {})) from modules.ui_components import ToolButton - refresh_symbol = '\U0001f504' # 🔄 - refresh_button = ToolButton(value=refresh_symbol, elem_id=elem_id) + refresh_button = ToolButton(value=symbols.refresh, elem_id=elem_id) refresh_button.click(fn=refresh, inputs=[], outputs=[refresh_component]) return refresh_button diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index c38b3abdd..b8e473593 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -13,15 +13,13 @@ from starlette.responses import FileResponse, JSONResponse from modules import shared, scripts, modelloader from modules.generation_parameters_copypaste import image_from_url_text from modules.ui_components import ToolButton +import modules.ui_symbols as symbols extra_pages = [] allowed_dirs = set() dir_cache = {} # key=path, value=(mtime, listdir(path)) -refresh_symbol = '\U0001f504' # 🔄 -close_symbol = '\U0000274C' # ❌ - def listdir(path): if not os.path.exists(path): @@ -344,8 +342,8 @@ def create_ui(container, button, tabname, skip_indexing = False): ui.stored_extra_pages = extra_pages ui.tabname = tabname with gr.Tabs(elem_id=tabname+"_extra_tabs"): - button_refresh = ToolButton(refresh_symbol, elem_id=tabname+"_extra_refresh") - button_close = ToolButton(close_symbol, elem_id=tabname+"_extra_close") + button_refresh = ToolButton(symbols.refresh, elem_id=tabname+"_extra_refresh") + button_close = ToolButton(symbols.close, elem_id=tabname+"_extra_close") ui.search = gr.Textbox('', show_label=False, elem_id=tabname+"_extra_search", placeholder="Search...", elem_classes="textbox", lines=1) ui.description = gr.TextArea('', show_label=False, elem_id=tabname+"_description", placeholder="Save/Replace Extra Network Description...", elem_classes="textbox", lines=1) ui.preview_target_filename = gr.Textbox('Preview save filename', elem_id=tabname+"_preview_filename", visible=False) diff --git a/modules/ui_loadsave.py b/modules/ui_loadsave.py index 4d8514d02..b0c647e05 100644 --- a/modules/ui_loadsave.py +++ b/modules/ui_loadsave.py @@ -174,7 +174,7 @@ class UiLoadsave: def create_ui(self): """creates ui elements for editing defaults UI, without adding any logic to them""" gr.HTML(f"Review changed values and apply them as new user interface defaults
Config file: {self.filename}") - with gr.Row(): + with gr.Row(elem_id="config_row"): self.ui_defaults_view = gr.Button(value='View changes', elem_id="ui_defaults_view", variant="secondary") self.ui_defaults_apply = gr.Button(value='Set new defaults', elem_id="ui_defaults_apply", variant="primary") self.ui_defaults_restore = gr.Button(value='Restore system defaults', elem_id="ui_defaults_restore", variant="primary") diff --git a/modules/ui_symbols.py b/modules/ui_symbols.py new file mode 100644 index 000000000..86b9a5e64 --- /dev/null +++ b/modules/ui_symbols.py @@ -0,0 +1,14 @@ +refresh = '🔄' +close = '🛗' +load = '⬆️' +save = '⬇️' +apply = '⏩' +clear = '🚮' +fill = '⏫' +networks = '🌐' +switch = '⇅' +detect = '📐' +folder = '📂' +random = '🎲️' +reuse = '♻️' +paste = '📘' diff --git a/scripts/postprocessing_upscale.py b/scripts/postprocessing_upscale.py index fd9ccd893..12996eb09 100644 --- a/scripts/postprocessing_upscale.py +++ b/scripts/postprocessing_upscale.py @@ -3,7 +3,8 @@ import numpy as np import gradio as gr from modules import scripts_postprocessing, shared from modules.ui_components import FormRow, ToolButton -from modules.ui import switch_values_symbol +import modules.ui_symbols as symbols + upscale_cache = {} @@ -26,7 +27,7 @@ class ScriptPostprocessingUpscale(scripts_postprocessing.ScriptPostprocessing): with gr.Row(elem_id="upscaling_column_size", scale=4): upscaling_resize_w = gr.Slider(minimum=64, maximum=4096, step=8, label="Width", value=512, elem_id="extras_upscaling_resize_w") upscaling_resize_h = gr.Slider(minimum=64, maximum=4096, step=8, label="Height", value=512, elem_id="extras_upscaling_resize_h") - upscaling_res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="upscaling_res_switch_btn") + upscaling_res_switch_btn = ToolButton(value=symbols.switch, elem_id="upscaling_res_switch_btn") upscaling_crop = gr.Checkbox(label='Crop to fit', value=True, elem_id="extras_upscaling_crop") with FormRow(): @@ -114,7 +115,6 @@ class ScriptPostprocessingUpscaleSimple(ScriptPostprocessingUpscale): with FormRow(): upscaler_name = gr.Dropdown(label='Upscaler', choices=[x.name for x in shared.sd_upscalers], value=shared.sd_upscalers[0].name) upscale_by = gr.Slider(minimum=0.05, maximum=8.0, step=0.05, label="Upscale by", value=2) - return { "upscale_by": upscale_by, "upscaler_name": upscaler_name, @@ -123,10 +123,8 @@ class ScriptPostprocessingUpscaleSimple(ScriptPostprocessingUpscale): def process(self, pp: scripts_postprocessing.PostprocessedImage, upscale_by=2.0, upscaler_name=None): # pylint: disable=arguments-differ if upscaler_name is None or upscaler_name == "None": return - upscaler1 = next(iter([x for x in shared.sd_upscalers if x.name == upscaler_name]), None) if upscaler1 is None: shared.log.debug(f"Upscaler not found: {upscaler_name}") - pp.image = self.upscale(pp.image, pp.info, upscaler1, 0, upscale_by, 0, 0, False) pp.info["Postprocess upscaler"] = upscaler1.name diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index aee489013..57ad5bab5 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -15,9 +15,7 @@ import modules.shared as shared from modules import images, sd_samplers, processing, sd_models, sd_vae from modules.processing import process_images, Processed, StableDiffusionProcessingTxt2Img from modules.ui_components import ToolButton - -fill_values_symbol = "\U0001f4d2" # 📒 -AxisInfo = namedtuple('AxisInfo', ['axis', 'values']) +import modules.ui_symbols as symbols def apply_field(field): @@ -387,19 +385,19 @@ class Script(scripts.Script): x_type = gr.Dropdown(label="X type", choices=[x.label for x in self.current_axis_options], value=self.current_axis_options[0].label, type="index", elem_id=self.elem_id("x_type")) x_values = gr.Textbox(label="X values", lines=1, elem_id=self.elem_id("x_values")) x_values_dropdown = gr.Dropdown(label="X values",visible=False,multiselect=True,interactive=True) - fill_x_button = ToolButton(value=fill_values_symbol, elem_id="xyz_grid_fill_x_tool_button", visible=False) + fill_x_button = ToolButton(value=symbols.fill, elem_id="xyz_grid_fill_x_tool_button", visible=False) with gr.Row(): y_type = gr.Dropdown(label="Y type", choices=[x.label for x in self.current_axis_options], value=self.current_axis_options[0].label, type="index", elem_id=self.elem_id("y_type")) y_values = gr.Textbox(label="Y values", lines=1, elem_id=self.elem_id("y_values")) y_values_dropdown = gr.Dropdown(label="Y values",visible=False,multiselect=True,interactive=True) - fill_y_button = ToolButton(value=fill_values_symbol, elem_id="xyz_grid_fill_y_tool_button", visible=False) + fill_y_button = ToolButton(value=symbols.fill, elem_id="xyz_grid_fill_y_tool_button", visible=False) with gr.Row(): z_type = gr.Dropdown(label="Z type", choices=[x.label for x in self.current_axis_options], value=self.current_axis_options[0].label, type="index", elem_id=self.elem_id("z_type")) z_values = gr.Textbox(label="Z values", lines=1, elem_id=self.elem_id("z_values")) z_values_dropdown = gr.Dropdown(label="Z values",visible=False,multiselect=True,interactive=True) - fill_z_button = ToolButton(value=fill_values_symbol, elem_id="xyz_grid_fill_z_tool_button", visible=False) + fill_z_button = ToolButton(value=symbols.fill, elem_id="xyz_grid_fill_z_tool_button", visible=False) with gr.Row(variant="compact", elem_id="axis_options"): draw_legend = gr.Checkbox(label='Draw legend', value=True, elem_id=self.elem_id("draw_legend")) no_fixed_seeds = gr.Checkbox(label='Keep random for seeds', value=False, elem_id=self.elem_id("no_fixed_seeds")) @@ -570,6 +568,7 @@ class Script(scripts.Script): total_steps *= p.n_iter image_cell_count = p.n_iter * p.batch_size shared.log.info(f"XYZ grid: images={len(xs)*len(ys)*len(zs)*image_cell_count} grid={len(zs)} {len(xs)}x{len(ys)} cells={len(zs)} steps={total_steps}") + AxisInfo = namedtuple('AxisInfo', ['axis', 'values']) shared.state.xyz_plot_x = AxisInfo(x_opt, xs) shared.state.xyz_plot_y = AxisInfo(y_opt, ys) shared.state.xyz_plot_z = AxisInfo(z_opt, zs) diff --git a/webui.py b/webui.py index c8d1214ca..37bba31d1 100644 --- a/webui.py +++ b/webui.py @@ -1,51 +1,18 @@ -from __future__ import annotations import os -import re import sys import glob import signal import asyncio import logging -import warnings import importlib from threading import Thread -import urllib3 +import modules.loader +import torch # pylint: disable=wrong-import-order from modules import timer, errors, paths # pylint: disable=unused-import -startup_timer = timer.Timer() local_url = None - -logging.getLogger("DeepSpeed").disabled = True -import torch # pylint: disable=C0411 -try: - import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import -except Exception: - pass -errors.log.debug(f'Loaded Torch=={torch.__version__}') -urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) -import torchvision # pylint: disable=W0611,C0411 -import pytorch_lightning # pytorch_lightning should be imported after torch, but it re-enables warnings on import so import once to disable them # pylint: disable=W0611,C0411 -if ".dev" in torch.__version__ or "+git" in torch.__version__: - torch.__long_version__ = torch.__version__ - torch.__version__ = re.search(r'[\d.]+[\d]', torch.__version__).group(0) -logging.getLogger("xformers").addFilter(lambda record: 'A matching Triton is not available' not in record.getMessage()) -logging.getLogger("pytorch_lightning").disabled = True -warnings.filterwarnings(action="ignore", category=DeprecationWarning) -warnings.filterwarnings(action="ignore", category=FutureWarning) -warnings.filterwarnings(action="ignore", category=UserWarning, module="torchvision") -startup_timer.record("torch") - -from fastapi import FastAPI # pylint: disable=W0611,C0411 -import gradio # pylint: disable=W0611,C0411 -errors.log.debug(f'Loaded Gradio=={gradio.__version__}') -startup_timer.record("gradio") -errors.install([gradio]) - -import diffusers # pylint: disable=W0611,C0411 -errors.log.debug(f'Loaded Diffusers=={diffusers.__version__}') -startup_timer.record("diffusers") - -errors.log.debug('Loading Modules') +if not modules.loader.initialized: + errors.log.debug('Loading modules') from installer import log, setup_logging, git_commit import ldm.modules.encoders.modules # pylint: disable=W0611,C0411,E0401 from modules.call_queue import queue_lock, wrap_queued_call, wrap_gradio_gpu_call # pylint: disable=W0611,C0411,C0412 @@ -71,10 +38,12 @@ import modules.ui from modules.shared import cmd_opts, opts import modules.hypernetworks.hypernetwork from modules.middleware import setup_middleware -startup_timer.record("libraries") -log.info('Libraries loaded') -log.setLevel(logging.DEBUG if cmd_opts.debug else logging.INFO) -logging.disable(logging.NOTSET if cmd_opts.debug else logging.DEBUG) + +if not modules.loader.initialized: + timer.startup.record("libraries") + log.info('Loaded librareis') + log.setLevel(logging.DEBUG if cmd_opts.debug else logging.INFO) + logging.disable(logging.NOTSET if cmd_opts.debug else logging.DEBUG) if cmd_opts.server_name: server_name = cmd_opts.server_name else: @@ -92,7 +61,7 @@ fastapi_args = { "deepLinking": False, } } - +modules.loader.initialized = True def check_rollback_vae(): if shared.cmd_opts.rollback_vae: @@ -113,37 +82,38 @@ def initialize(): check_rollback_vae() modules.sd_samplers.list_samplers() - startup_timer.record("samplers") + timer.startup.record("samplers") modules.sd_vae.refresh_vae_list() - startup_timer.record("vae") + timer.startup.record("vae") extensions.list_extensions() - startup_timer.record("extensions") + timer.startup.record("extensions") modelloader.cleanup_models() modules.sd_models.setup_model() - startup_timer.record("models") + timer.startup.record("models") codeformer.setup_model(opts.codeformer_models_path) - startup_timer.record("codeformer") + timer.startup.record("codeformer") gfpgan.setup_model(opts.gfpgan_models_path) - startup_timer.record("gfpgan") + timer.startup.record("gfpgan") - log.debug('Loading scripts') - modules.scripts.load_scripts() - startup_timer.record("scripts") + log.debug('Loading extensions') + t_timer, t_total = modules.scripts.load_scripts() + timer.startup.record("extensions") + timer.startup.records["extensions"] = t_total # scripts can reset the time + setup_logging() # reset since scripts can hijaack logging + log.info(f'Extensions time: {t_timer.summary()}') modelloader.load_upscalers() - startup_timer.record("upscalers") - - setup_logging() # needs a reset since scripts can hijaack logging + timer.startup.record("upscalers") shared.opts.onchange("sd_vae", wrap_queued_call(lambda: modules.sd_vae.reload_vae_weights()), call=False) shared.opts.onchange("temp_dir", ui_tempdir.on_tmpdir_changed) shared.opts.onchange("gradio_theme", shared.reload_gradio_theme) - startup_timer.record("onchange") + timer.startup.record("onchange") modules.textual_inversion.textual_inversion.list_textual_inversion_templates() shared.reload_hypernetworks() @@ -152,7 +122,7 @@ def initialize(): ui_extra_networks.register_default_pages() extra_networks.initialize() extra_networks.register_default_extra_networks() - startup_timer.record("extra-networks") + timer.startup.record("extra-networks") if cmd_opts.tls_keyfile is not None and cmd_opts.tls_certfile is not None: try: @@ -165,7 +135,7 @@ def initialize(): log.error("TLS setup invalid, running webui without TLS") else: log.info("Running with TLS") - startup_timer.record("tls") + timer.startup.record("tls") # make the program just exit at ctrl+c without waiting for anything def sigint_handler(_sig, _frame): @@ -198,7 +168,7 @@ def load_model(): shared.opts.onchange("sd_model_dict", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(op='dict')), call=False) shared.opts.onchange("sd_vae", wrap_queued_call(lambda: modules.sd_vae.reload_vae_weights()), call=False) shared.opts.onchange("sd_backend", wrap_queued_call(lambda: modules.sd_models.change_backend()), call=False) - startup_timer.record("checkpoint") + timer.startup.record("checkpoint") def create_api(app): @@ -247,15 +217,15 @@ def start_common(): initialize() if shared.opts.clean_temp_dir_at_start: ui_tempdir.cleanup_tmpdr() - startup_timer.record("cleanup") + timer.startup.record("cleanup") def start_ui(): log.debug('Creating UI') modules.script_callbacks.before_ui_callback() - startup_timer.record("before-ui") - shared.demo = modules.ui.create_ui(startup_timer) - startup_timer.record("ui") + timer.startup.record("before-ui") + shared.demo = modules.ui.create_ui(timer.startup) + timer.startup.record("ui") if cmd_opts.disable_queue: log.info('Server queues disabled') shared.demo.progress_tracking = False @@ -303,19 +273,20 @@ def start_ui(): setup_middleware(app, cmd_opts) if cmd_opts.subpath: + import gradio gradio.mount_gradio_app(app, shared.demo, path=f"/{cmd_opts.subpath}") shared.log.info(f'Redirector mounted: /{cmd_opts.subpath}') - startup_timer.record("launch") + timer.startup.record("launch") modules.progress.setup_progress_api(app) create_api(app) - startup_timer.record("api") + timer.startup.record("api") ui_extra_networks.add_pages_to_demo(app) modules.script_callbacks.app_started_callback(shared.demo, app) - startup_timer.record("app-started") + timer.startup.record("app-started") time_setup = [f'{k}:{round(v,3)}s' for (k,v) in modules.scripts.time_setup.items() if v > 0.005] shared.log.debug(f'Scripts setup: {time_setup}') @@ -333,7 +304,7 @@ def webui(restart=False): modules.sd_models.write_metadata() load_model() shared.opts.save(shared.config_filename) - log.info(f"Startup time: {startup_timer.summary()}") + log.info(f"Startup time: {timer.startup.summary()}") if not restart: # override all loggers to use the same handlers as the main logger @@ -356,13 +327,14 @@ def webui(restart=False): def api_only(): start_common() + from fastapi import FastAPI app = FastAPI(**fastapi_args) setup_middleware(app, cmd_opts) api = create_api(app) api.wants_restart = False modules.script_callbacks.app_started_callback(None, app) modules.sd_models.write_metadata() - log.info(f"Startup time: {startup_timer.summary()}") + log.info(f"Startup time: {timer.startup.summary()}") server = api.launch() return server