diff --git a/CHANGELOG.md b/CHANGELOG.md index 6650290b6..71749b1ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log for SD.Next +## Update for 2023-12-05 + +- **General** + - **Extra networks** new settting -> extra networks -> build info on first access + indexes all networks on first access instead of server startup + - disable google fonts check on server startup + - fix torchvision/basicsr compatibility + ## Update for 2023-12-04 What's new? Native video in SD.Next via both **AnimateDiff** and **Stable-Video-Diffusion** - and including native MP4 encoding and smooth video outputs out-of-the-box, not just animated-GIFs. diff --git a/html/locale_en.json b/html/locale_en.json index 27d4beaa7..82383808f 100644 --- a/html/locale_en.json +++ b/html/locale_en.json @@ -484,8 +484,8 @@ {"id":"","label":"Dark","localized":"","hint":""}, {"id":"","label":"Light","localized":"","hint":""}, {"id":"","label":"Show grid in results","localized":"","hint":""}, - {"id":"","label":"For inpainting, include the greyscale mask in results","localized":"","hint":""}, - {"id":"","label":"For inpainting, include masked composite in results","localized":"","hint":""}, + {"id":"","label":"Inpainting include greyscale mask in results","localized":"","hint":""}, + {"id":"","label":"Inpainting include masked composite in results","localized":"","hint":""}, {"id":"","label":"Do not change selected model when reading generation parameters","localized":"","hint":""}, {"id":"","label":"Send seed when sending prompt or image to other interface","localized":"","hint":""}, {"id":"","label":"Send size when sending prompt or image to another interface","localized":"","hint":""}, diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js index 216673ede..075b10f80 100644 --- a/javascript/extraNetworks.js +++ b/javascript/extraNetworks.js @@ -90,14 +90,23 @@ function readCardDescription(page, item) { }); } -async function filterExtraNetworksForTab(tabname, searchTerm) { +function getCardsForActivePage() { + const pagename = getENActivePage(); + if (!pagename) return []; + const allCards = Array.from(gradioApp().querySelectorAll('.extra-network-cards > .card')); + const cards = allCards.filter((el) => el.dataset.page.toLowerCase().includes(pagename.toLowerCase())); + log('getCardsForActivePage', pagename, cards.length); + return allCards; +} + +async function filterExtraNetworksForTab(searchTerm) { let found = 0; let items = 0; const t0 = performance.now(); const pagename = getENActivePage(); if (!pagename) return; const allPages = Array.from(gradioApp().querySelectorAll('.extra-network-cards')); - const pages = allPages.filter((el) => el.id.includes(pagename.toLowerCase())); + const pages = allPages.filter((el) => el.id.toLowerCase().includes(pagename.toLowerCase())); for (const pg of pages) { const cards = Array.from(pg.querySelectorAll('.card') || []); cards.forEach((elem) => { @@ -158,7 +167,7 @@ function sortExtraNetworks() { const pagename = getENActivePage(); if (!pagename) return 'sort error: unknown page'; const allPages = Array.from(gradioApp().querySelectorAll('.extra-network-cards')); - const pages = allPages.filter((el) => el.id.includes(pagename.toLowerCase())); + const pages = allPages.filter((el) => el.id.toLowerCase().includes(pagename.toLowerCase())); let num = 0; for (const pg of pages) { const cards = Array.from(pg.querySelectorAll('.card') || []); @@ -255,8 +264,17 @@ function refeshDetailsEN(args) { return args; } -// init +// refresh on en show +function refreshENpage() { + if (getCardsForActivePage().length === 0) { + log('refreshENpage'); + const tabname = getENActiveTab(); + const btnRefresh = gradioApp().getElementById(`${tabname}_extra_refresh`); + if (btnRefresh) btnRefresh.click(); + } +} +// init function setupExtraNetworksForTab(tabname) { gradioApp().querySelector(`#${tabname}_extra_tabs`).classList.add('extra-networks'); const en = gradioApp().getElementById(`${tabname}_extra_networks`); @@ -307,7 +325,7 @@ function setupExtraNetworksForTab(tabname) { txtSearchValue.addEventListener('input', (evt) => { if (searchTimer) clearTimeout(searchTimer); searchTimer = setTimeout(() => { - filterExtraNetworksForTab(tabname, txtSearchValue.value.toLowerCase()); + filterExtraNetworksForTab(txtSearchValue.value.toLowerCase()); searchTimer = null; }, 150); }); @@ -339,6 +357,7 @@ function setupExtraNetworksForTab(tabname) { el.parentElement.style.width = '-webkit-fill-available'; } if (entries[0].intersectionRatio > 0) { + refreshENpage(); if (window.opts.extra_networks_card_cover === 'cover') { en.style.transition = ''; en.style.zIndex = 100; diff --git a/modules/extensions.py b/modules/extensions.py index 4e37e4611..3ad20acec 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -153,3 +153,4 @@ def list_extensions(): for dirname, path, is_builtin in extension_paths: extension = Extension(name=dirname, path=path, enabled=dirname not in disabled_extensions, is_builtin=is_builtin) extensions.append(extension) + shared.log.info(f'Disabled extensions: {[e.name for e in extensions if not e.enabled]}') diff --git a/modules/loader.py b/modules/loader.py index 8b06f09ac..bb6b120a1 100644 --- a/modules/loader.py +++ b/modules/loader.py @@ -1,5 +1,6 @@ from __future__ import annotations import re +import sys import logging import warnings import urllib3 @@ -55,3 +56,12 @@ try: errors.log.debug(f'Detected: cores={cores} affinity={affinity} set threads={threads}') except Exception: pass + +try: # fix changed import in torchvision 0.17+, which breaks basicsr + import torchvision.transforms.functional_tensor # pylint: disable=unused-import, ungrouped-imports +except ImportError: + try: + import torchvision.transforms.functional as functional + sys.modules["torchvision.transforms.functional_tensor"] = functional + except ImportError: + pass # shrug... diff --git a/modules/sd_models.py b/modules/sd_models.py index 0956353ce..e123a64b2 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -806,7 +806,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No sd_model = None try: - if shared.cmd_opts.ckpt is not None and model_data.initial: # initial load + if shared.cmd_opts.ckpt is not None and os.path.isdir(shared.cmd_opts.ckpt) and model_data.initial: # initial load ckpt_basename = os.path.basename(shared.cmd_opts.ckpt) model_name = modelloader.find_diffuser(ckpt_basename) if model_name is not None: @@ -833,6 +833,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No if vae is not None: diffusers_load_config["vae"] = vae + shared.log.debug(f'Diffusers loading: path="{checkpoint_info.path}"') if os.path.isdir(checkpoint_info.path): err1 = None err2 = None diff --git a/modules/shared.py b/modules/shared.py index 7c2bea684..2808f7f2a 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -166,17 +166,14 @@ def temp_disable_extensions(): for ext in disable_safe: if ext not in opts.disabled_extensions: disabled.append(ext) - log.info(f'Safe mode disabling extensions: {disabled}') if backend == Backend.DIFFUSERS: for ext in disable_diffusers: if ext not in opts.disabled_extensions: disabled.append(ext) - log.info(f'Disabling uncompatible extensions: backend={backend} {disabled}') if backend == Backend.ORIGINAL: for ext in disable_original: if ext not in opts.disabled_extensions: disabled.append(ext) - log.info(f'Disabling uncompatible extensions: backend={backend} {disabled}') cmd_opts.controlnet_loglevel = 'WARNING' return disabled @@ -469,8 +466,8 @@ options_templates.update(options_section(('ui', "User Interface"), { "gallery_height": OptionInfo("", "Gallery height", gr.Textbox), "compact_view": OptionInfo(False, "Compact view"), "return_grid": OptionInfo(True, "Show grid in results"), - "return_mask": OptionInfo(False, "For inpainting, include the greyscale mask in results"), - "return_mask_composite": OptionInfo(False, "For inpainting, include masked composite in results"), + "return_mask": OptionInfo(False, "Inpainting include greyscale mask in results"), + "return_mask_composite": OptionInfo(False, "Inpainting include masked composite in results"), "disable_weights_auto_swap": OptionInfo(True, "Do not change selected model when reading generation parameters"), "send_seed": OptionInfo(True, "Send seed when sending prompt or image to other interface"), "send_size": OptionInfo(True, "Send size when sending prompt or image to another interface"), @@ -601,18 +598,15 @@ options_templates.update(options_section(('extra_networks', "Extra Networks"), { "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, {"choices": ["contain", "cover", "fill"], "visible": False}), - "extra_networks_sep2": OptionInfo("

Extra networks general

", "", gr.HTML), - "extra_network_skip_indexing": OptionInfo(False, "Do not automatically build extra network pages", gr.Checkbox), + "extra_network_skip_indexing": OptionInfo(False, "Build info on first access", gr.Checkbox), "extra_networks_default_multiplier": OptionInfo(1.0, "Default multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), - "extra_networks_sep3": OptionInfo("

Extra networks settings

", "", gr.HTML), "extra_networks_styles": OptionInfo(True, "Show built-in styles"), "lora_preferred_name": OptionInfo("filename", "LoRA preffered name", gr.Radio, {"choices": ["filename", "alias"]}), "lora_add_hashes_to_infotext": OptionInfo(True, "LoRA add hash info"), "lora_in_memory_limit": OptionInfo(0, "LoRA memory cache", gr.Slider, {"minimum": 0, "maximum": 24, "step": 1}), "lora_functional": OptionInfo(False, "Use Kohya method for handling multiple LoRA", gr.Checkbox, { "visible": False }), - "sd_hypernetwork": OptionInfo("None", "Add hypernetwork to prompt", gr.Dropdown, { "choices": ["None"], "visible": False }), })) diff --git a/modules/theme.py b/modules/theme.py index 83a14c902..35f98fe55 100644 --- a/modules/theme.py +++ b/modules/theme.py @@ -1,6 +1,5 @@ import os import json -import urllib.request import gradio as gr import modules.shared # from modules.shared import log, opts, req, writefile @@ -51,18 +50,21 @@ def reload_gradio_theme(theme_name=None): if not theme_name: theme_name = modules.shared.opts.gradio_theme default_font_params = {} + """ res = 0 try: + import urllib.request request = urllib.request.Request("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono", method="HEAD") res = urllib.request.urlopen(request, timeout=3.0).status # pylint: disable=consider-using-with except Exception: res = 0 if res != 200: modules.shared.log.info('No internet access detected, using default fonts') - default_font_params = { - 'font':['Helvetica', 'ui-sans-serif', 'system-ui', 'sans-serif'], - 'font_mono':['IBM Plex Mono', 'ui-monospace', 'Consolas', 'monospace'] - } + """ + default_font_params = { + 'font':['Helvetica', 'ui-sans-serif', 'system-ui', 'sans-serif'], + 'font_mono':['IBM Plex Mono', 'ui-monospace', 'Consolas', 'monospace'] + } is_builtin = theme_name in list_builtin_themes() modules.shared.log.info(f'Load UI theme: name="{theme_name}" style={modules.shared.opts.theme_style} base={"sdnext.css" if is_builtin else "base.css"}') if is_builtin: diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index 6a3e1e6b1..8cf67bc67 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -250,13 +250,14 @@ def refresh_extensions_list(search_text, sort_column): global extensions_list # pylint: disable=global-statement import urllib.request try: - with urllib.request.urlopen(extensions_index) as response: + shared.log.debug(f'Updating extensions list: url={extensions_index}') + with urllib.request.urlopen(extensions_index, timeout=3.0) as response: text = response.read() extensions_list = json.loads(text) with open(os.path.join(paths.script_path, "html", "extensions.json"), "w", encoding="utf-8") as outfile: json_object = json.dumps(extensions_list, indent=2) outfile.write(json_object) - shared.log.debug(f'Updated extensions list: {len(extensions_list)} {extensions_index}') + shared.log.info(f'Updated extensions list: items={len(extensions_list)} url={extensions_index}') except Exception as e: shared.log.warning(f'Updated extensions list failed: {extensions_index} {e}') list_extensions() diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index f30dba2cc..f424402e2 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -343,7 +343,6 @@ class ExtraNetworksPage: self.text += '\n' fn = os.path.splitext(path)[0] + '.txt' - # if os.path.exists(fn): if fn in listdir(os.path.dirname(path)): try: with open(fn, "r", encoding="utf-8", errors="replace") as f: @@ -364,7 +363,6 @@ class ExtraNetworksPage: def find_info(self, path): t0 = time.time() fn = os.path.splitext(path)[0] + '.json' - # if os.path.exists(fn): data = {} if fn in listdir(os.path.dirname(path)): data = shared.readfile(fn, silent=True) @@ -382,12 +380,15 @@ def initialize(): def register_page(page: ExtraNetworksPage): # registers extra networks page for the UI; recommend doing it in on_before_ui() callback for extensions debug(f'EN register-page: {page}') + if page in shared.extra_networks: + debug(f'EN register-page: {page} already registered') + return shared.extra_networks.append(page) - allowed_dirs.clear() - for pg in shared.extra_networks: - for folder in pg.allowed_directories_for_previews(): - if folder not in allowed_dirs: - allowed_dirs.append(os.path.abspath(folder)) + # allowed_dirs.clear() + # for pg in shared.extra_networks: + for folder in page.allowed_directories_for_previews(): + if folder not in allowed_dirs: + allowed_dirs.append(os.path.abspath(folder)) def register_pages(): @@ -396,6 +397,7 @@ def register_pages(): from modules.ui_extra_networks_checkpoints import ExtraNetworksPageCheckpoints from modules.ui_extra_networks_styles import ExtraNetworksPageStyles from modules.ui_extra_networks_vae import ExtraNetworksPageVAEs + debug('EN register-pages') register_page(ExtraNetworksPageCheckpoints()) register_page(ExtraNetworksPageStyles()) register_page(ExtraNetworksPageTextualInversion()) @@ -556,15 +558,16 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): if ui.tabname == 'txt2img': # refresh only once global refresh_time # pylint: disable=global-statement refresh_time = time.time() - threads = [] - for page in get_pages(): - if os.environ.get('SD_EN_DEBUG', None) is not None: - threads.append(threading.Thread(target=page.create_items, args=[ui.tabname])) - threads[-1].start() - else: - page.create_items(ui.tabname) - for thread in threads: - thread.join() + if not skip_indexing: + threads = [] + for page in get_pages(): + if os.environ.get('SD_EN_DEBUG', None) is not None: + threads.append(threading.Thread(target=page.create_items, args=[ui.tabname])) + threads[-1].start() + else: + page.create_items(ui.tabname) + for thread in threads: + thread.join() for page in get_pages(): page.create_page(ui.tabname, skip_indexing) with gr.Tab(page.title, id=page.title.lower().replace(" ", "_"), elem_classes="extra-networks-tab") as tab: @@ -574,7 +577,6 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): if shared.cmd_opts.profile: errors.profile(pr, 'ExtraNetworks') pr.disable() - # ui.tabs.change(fn=ui_tab_change, inputs=[], outputs=[ui.button_scan, ui.button_save]) def fn_save_img(image):