diff --git a/CHANGELOG.md b/CHANGELOG.md
index 67f052a3a..3bc6b767c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,11 +15,16 @@
this is stage one of new styles functionality
old styles interface is still available, but will be removed in future
- cache file lists for much faster startup
+ speedups are 50+% for large number of extra networks
+ - ui refresh button now refreshes selected page, not all pages
- simplified handling of **descriptions**
now shows on-mouse-over without the need for user interaction
- **metadata** and **info** buttons only show if there is actual content
- diffusers:
- ability to interrupt (stop/skip) model generate
+ - add full support for **textual inversions** (embeddings)
+ this applies to both sd15 and sdxl
+ thanks @ai-casanova for porting compel/sdxl code
- mix&match **base** and **refiner** models (*experimental*):
most of those are "because why not" and can result in corrupt images, but some are actually useful
also note that if you're not using actual refiner model, you need to bump refiner steps
diff --git a/README.md b/README.md
index d2bccd752..bb5725346 100644
--- a/README.md
+++ b/README.md
@@ -27,9 +27,9 @@ All Individual features are not listed here, instead check [ChangeLog](CHANGELOG
- Support for multiple backends!
**original** and **diffusers**
- Support for multiple diffusion models!
- Stable Diffusion, SD-XL, Kandinsky, DeepFloyd IF, etc.
+ Stable Diffusion, SD-XL, Kandinsky, DeepFloyd IF, UniDiffusion, SD-Distilled, etc.
- Fully multiplatform with platform specific autodetection and tuning performed on install
- Windows / Linux / MacOS with CPU / nVidia / AMD / Intel / DirectML
+ Windows / Linux / MacOS with CPU / nVidia / AMD / Intel / DirectML / OpenVINO
- Improved prompt parser
- Enhanced *Lora*/*Locon*/*Lyco* code supporting latest trends in training
- Built-in queue management
@@ -54,21 +54,21 @@ All Individual features are not listed here, instead check [ChangeLog](CHANGELOG
Additional models will be added as they become available and there is public interest in them
-- Stable Diffusion 1.x and 2.x including all variants
+- Stable Diffusion 1.x and 2.x *(all variants)*
- Stable Diffusion XL
- Kandinsky 2.1 and 2.2
- DeepFloyd IF
- UniDiffusion
-- SD-Distilled (all variants)
+- SD-Distilled *(all variants)*
## Platform support
- *nVidia* GPUs using **CUDA** libraries on both *Windows and Linux*
- *AMD* GPUs using **ROCm** libraries on *Linux*.
Support will be extended to *Windows* once AMD releases ROCm for Windows
-- *Intel Arc* GPUs using **OneAPI** with *IPEX XPU* libraries on both *Windows and Linux*
- Any GPU compatibile with *DirectX* on *Windows* using **DirectML** libraries.
This includes support for AMD GPUs that are not supported by native ROCm libraries
+- *Intel Arc* GPUs using **OneAPI** with *IPEX XPU* libraries on both *Windows and Linux*
- *Intel* GPUs using **OpenVINO** libraries on both *Windows and Linux*
- *Apple M1/M2* on *OSX* using built-in support in Torch with **MPS** optimizations
diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js
index c286c2ce6..e6b905e9f 100644
--- a/javascript/extraNetworks.js
+++ b/javascript/extraNetworks.js
@@ -278,6 +278,12 @@ function extraNetworksSearchButton(event) {
updateInput(searchTextarea);
}
+function extraNetworksRefreshButton() {
+ const tabname = getENActiveTab();
+ const page = gradioApp().querySelector(`#${tabname}_extra_networks > .tabs > .tab-nav > .selected`);
+ return page ? page.innerText : '';
+}
+
let desiredStyle = '';
function selectStyle(name) {
desiredStyle = name;
diff --git a/modules/ui.py b/modules/ui.py
index c252f6e4a..fe0c8aa3b 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -1,6 +1,6 @@
+import os
import json
import mimetypes
-import os
from functools import reduce
import gradio as gr
diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py
index e6a7d64b5..2b5cf3172 100644
--- a/modules/ui_extra_networks.py
+++ b/modules/ui_extra_networks.py
@@ -19,6 +19,7 @@ import modules.ui_symbols as symbols
extra_pages = []
allowed_dirs = set()
dir_cache = {} # key=path, value=(mtime, listdir(path))
+refresh_time = None
def listdir(path):
@@ -171,6 +172,9 @@ class ExtraNetworksPage:
self.missing_thumbs.clear()
def create_page(self, tabname, skip = False):
+ if self.refresh_time is not None and self.refresh_time > refresh_time:
+ # shared.log.debug(f'Extra networks: {self.name} items={len(self.items)} tab={tabname} cached')
+ return self.html
t0 = time.time()
self_name_id = self.name.replace(" ", "_")
if skip:
@@ -191,16 +195,13 @@ class ExtraNetworksPage:
subdirs = OrderedDict(sorted(subdirs.items()))
subdirs_html = " "
subdirs_html += "".join([f" " for subdir in subdirs if subdir != ''])
- if len(self.html) > 0:
- res = f"
{subdirs_html}
{self.html}
"
- return res
self.html = ''
- if self.refresh_time is None or len(self.items) == 0:
- try:
- self.items = list(self.list_items())
- except Exception as e:
- self.items = []
- shared.log.error(f'Extra networks error listing items: class={self.__class__} tab={tabname} {e}')
+ try:
+ self.items = list(self.list_items())
+ self.refresh_time = time.time()
+ except Exception as e:
+ self.items = []
+ shared.log.error(f'Extra networks error listing items: class={self.__class__} tab={tabname} {e}')
self.create_xyz_grid()
htmls = []
for item in self.items:
@@ -209,13 +210,12 @@ class ExtraNetworksPage:
htmls.append(self.create_html(item, tabname))
self.html += ''.join(htmls)
if len(subdirs_html) > 0 or len(self.html) > 0:
- res = f"
{subdirs_html}
{self.html}
"
+ self.html = f"
{subdirs_html}
{self.html}
"
else:
return ''
t1 = time.time()
- shared.log.debug(f'Extra networks: {self.name} items={len(self.items)} subdirs={len(subdirs)} time={round(t1-t0, 2)}')
+ shared.log.debug(f'Extra networks: {self.name} items={len(self.items)} subdirs={len(subdirs)} tab={tabname} time={round(t1-t0, 2)}')
threading.Thread(target=self.create_thumb).start()
- return res
def list_items(self):
raise NotImplementedError
@@ -316,7 +316,6 @@ def register_default_pages():
class ExtraNetworksUi:
def __init__(self):
self.pages = None
- self.stored_extra_pages = []
self.button_save_preview = None
self.preview_target_filename = None
self.button_save_description = None
@@ -331,7 +330,6 @@ class ExtraNetworksUi:
def create_ui(container, button, tabname, skip_indexing = False):
ui = ExtraNetworksUi()
ui.pages = []
- ui.stored_extra_pages = extra_pages
ui.tabname = tabname
with gr.Tabs(elem_id=tabname+"_extra_tabs"):
button_refresh = ToolButton(symbols.refresh, elem_id=tabname+"_extra_refresh")
@@ -343,11 +341,13 @@ def create_ui(container, button, tabname, skip_indexing = False):
ui.description_target_filename = gr.Textbox('Description save filename', elem_id=tabname+"_description_filename", visible=False)
ui.button_save_description = gr.Button('Save description', elem_id=tabname+"_save_description", visible=False)
- for page in ui.stored_extra_pages:
- shared.log.debug(f"Extra network page: {page.title} tab={tabname}")
- page_html = page.create_page(ui.tabname, skip_indexing)
+ if ui.tabname == 'txt2img': # refresh only once
+ global refresh_time # pylint: disable=global-statement
+ refresh_time = time.time()
+ for page in extra_pages:
+ page.create_page(ui.tabname, skip_indexing)
with gr.Tab(page.title, id=page.title.lower().replace(" ", "_"), elem_classes="extra-networks-tab"):
- page_elem = gr.HTML(page_html, elem_id=f'{tabname}{page.name}_extra_page', elem_classes="extra-networks-page")
+ page_elem = gr.HTML(page.html, elem_id=f'{tabname}{page.name}_extra_page', elem_classes="extra-networks-page")
page_elem.change(fn=lambda: None, _js=f'() => refreshExtraNetworks("{tabname}")', inputs=[], outputs=[])
ui.pages.append(page_elem)
@@ -359,18 +359,18 @@ def create_ui(container, button, tabname, skip_indexing = False):
button.click(fn=toggle_visibility, inputs=[state_visible], outputs=[state_visible, container, button])
button_close.click(fn=toggle_visibility, inputs=[state_visible], outputs=[state_visible, container])
- def refresh():
- shared.log.debug("Refreshing UI Extra Networks Pages")
+ def refresh(title):
res = []
- for pg in ui.stored_extra_pages:
- pg.html = ''
- pg.refresh_time = None
- pg.refresh()
- res.append(pg.create_page(ui.tabname))
+ for page in extra_pages:
+ if title == '' or title == page.title:
+ shared.log.debug(f"Refreshing Extra networks: page={page.title} tab={ui.tabname}")
+ page.refresh()
+ page.create_page(ui.tabname)
+ res.append(page.html)
ui.search.update(value = ui.search.value)
return res
- button_refresh.click(fn=refresh, inputs=[], outputs=ui.pages)
+ button_refresh.click(_js='extraNetworksRefreshButton', fn=refresh, inputs=[ui.search], outputs=ui.pages)
return ui
@@ -381,16 +381,19 @@ def path_is_parent(parent_path, child_path):
def setup_ui(ui, gallery):
+
def save_preview(index, images, filename):
if len(images) == 0:
- return [page.create_page(ui.tabname) for page in ui.stored_extra_pages]
+ for page in extra_pages:
+ page.create_page(ui.tabname)
+ return [page.html for page in 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:
+ for extra_page in extra_pages:
if any(path_is_parent(x, filename) for x in extra_page.allowed_directories_for_previews()):
is_allowed = True
break
@@ -402,7 +405,7 @@ def setup_ui(ui, gallery):
shared.log.debug(f'Extra network delete thumbnail: {thumb}')
os.remove(thumb)
shared.log.info(f'Extra network save preview: {filename}')
- return [page.create_page(ui.tabname) for page in ui.stored_extra_pages]
+ return [page.create_page(ui.tabname) for page in extra_pages]
ui.button_save_preview.click(
fn=save_preview,
@@ -422,7 +425,7 @@ def setup_ui(ui, gallery):
shared.log.info(f'Extra network save description: {filename} {desc}')
except Exception as e:
shared.log.error(f'Extra network save description: {filename} {e}')
- return [page.create_page(ui.tabname) for page in ui.stored_extra_pages]
+ return [page.create_page(ui.tabname) for page in extra_pages]
ui.button_save_description.click(
fn=save_description,
diff --git a/modules/ui_extra_networks_textual_inversion.py b/modules/ui_extra_networks_textual_inversion.py
index aaf9c1138..4ad9ac10a 100644
--- a/modules/ui_extra_networks_textual_inversion.py
+++ b/modules/ui_extra_networks_textual_inversion.py
@@ -11,7 +11,12 @@ class ExtraNetworksPageTextualInversion(ui_extra_networks.ExtraNetworksPage):
self.allow_negative_prompt = True
def refresh(self):
- sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings(force_reload=True)
+ if sd_models.model_data.sd_model is None:
+ return
+ if shared.backend == shared.Backend.ORIGINAL:
+ sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings(force_reload=True)
+ elif hasattr(sd_models.model_data.sd_model, 'embedding_db'):
+ sd_models.model_data.sd_model.embedding_db.load_textual_inversion_embeddings(force_reload=True)
def list_items(self):
if sd_models.model_data.sd_model is None: