add styles to extra networks

This commit is contained in:
Vladimir Mandic
2023-09-03 15:00:48 -04:00
parent cbe779b541
commit d41baddf50
21 changed files with 225 additions and 95 deletions
+9 -1
View File
@@ -4,15 +4,23 @@
- extra networks:
- support for **tags**
search by tag, list tags, add to prompt, etc.
show tags on hover, search by tag, list tags, add to prompt, etc.
- **styles** are now also listed as part of extra networks
existing `styles.csv` is converted upon startup to individual styles inside `models/style`
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
- 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 `diffusers_force_zeros` setting
create zero-tensor for prompt if prompt is empty (positive or negative)
- add `diffusers_aesthetics_score` setting
automatically guide unet towards higher pleasing images
- fixes:
- pre-create all system folders on startup
## Update for 2023-08-30
@@ -37,6 +37,7 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage):
"hash": lora_on_disk.shorthash,
"preview": self.find_preview(path),
"description": self.find_description(path),
"info": self.find_info(path),
"search_term": self.search_terms_from_path(lora_on_disk.filename) + ' '.join(tags.keys()),
"prompt": prompt,
"local_preview": f"{path}.{shared.opts.samples_format}",
+4
View File
@@ -478,6 +478,10 @@ def check_modified_files():
res = git('status --porcelain')
files = [x[2:].strip() for x in res.split('\n')]
files = [x for x in files if len(x) > 0 and (not x.startswith('extensions')) and (not x.startswith('wiki')) and (not x.endswith('.json')) and ('.log' not in x)]
deleted = [x for x in files if not os.path.exists(x)]
if len(deleted) > 0:
log.warning(f'Deleted files: {files}')
files = [x for x in files if os.path.exists(x) and not os.path.isdir(x)]
if len(files) > 0:
log.warning(f'Modified files: {files}')
except Exception:
+17
View File
@@ -278,4 +278,21 @@ function extraNetworksSearchButton(event) {
updateInput(searchTextarea);
}
let desiredStyle = '';
function selectStyle(name) {
desiredStyle = name;
const tabname = getENActiveTab();
const button = gradioApp().querySelector(`#${tabname}_styles_select`);
button.click();
}
function applyStyles(styles) {
let newStyles = [];
if (styles) newStyles = Array.isArray(styles) ? styles : [styles];
const index = newStyles.indexOf(desiredStyle);
if (index > -1) newStyles.splice(index, 1);
else newStyles.push(desiredStyle);
return newStyles.join('|');
}
onUiLoaded(setupExtraNetworks);
+1 -1
View File
@@ -235,7 +235,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
.extra-networks-page { display: flex }
.extra-networks .custom-button { width: 120px; width: 100%; background: none; justify-content: left; text-align: left; padding: 2px 8px 2px 16px; text-indent: -8px; box-shadow: none; line-break: auto; }
.extra-networks .custom-button:hover { background: var(--button-primary-background-fill) }
.extra-network-cards { display: flex; flex-wrap: wrap; overflow-y: scroll; overflow-x: hidden; width: -webkit-fill-available; }
.extra-network-cards { display: flex; flex-wrap: wrap; overflow-y: auto; overflow-x: hidden; align-content: flex-start; width: -webkit-fill-available; }
.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); }
+1 -1
View File
@@ -204,7 +204,7 @@ class PreprocessResponse(BaseModel):
fields = {}
for key, metadata in shared.opts.data_labels.items():
value = shared.opts.data.get(key)
value = shared.opts.data.get(key) or shared.opts.data_labels[key].default
optType = shared.opts.typemap.get(type(metadata.default), type(value))
if metadata is not None:
+16 -7
View File
@@ -50,29 +50,37 @@ for d, must_exist, what, _options in path_dirs:
paths[what] = d
def create_paths(opts):
def create_paths(opts, log=None):
def create_path(folder):
if folder is None or folder == '':
return
if not os.path.exists(folder):
try:
os.makedirs(folder, exist_ok=True)
except Exception:
pass
if log is not None:
log.debug(f'Create path: {folder}')
except Exception as e:
if log is not None:
log.error(f'Failed to create path: {folder} {e}')
def fix_path(folder):
if opts.data.get(folder, None) is None or opts.data[folder] is None or opts.data[folder] == '':
tgt = opts.data.get(folder, None) or opts.data_labels[folder].default
if tgt is None or tgt == '':
return
if os.path.isabs(opts.data[folder]) or (len(data_path) > 0 and opts.data[folder].startswith(data_path)) and not opts.data[folder].startswith(script_path):
if os.path.isabs(tgt) or (len(data_path) > 0 and tgt.startswith(data_path)) and not tgt.startswith(script_path):
return
fullpath = os.path.join(data_path, opts.data[folder])
fullpath = os.path.join(data_path, tgt)
relpath = os.path.relpath(fullpath, script_path)
opts.data[folder] = relpath
return
create_path(fix_path('temp_dir'))
create_path(data_path)
create_path(script_path)
create_path(models_path)
create_path(sd_configs_path)
create_path(extensions_dir)
create_path(extensions_builtin_dir)
create_path(fix_path('temp_dir'))
create_path(fix_path('hypernetwork_dir'))
create_path(fix_path('ckpt_dir'))
create_path(fix_path('vae_dir'))
@@ -86,6 +94,7 @@ def create_paths(opts):
create_path(fix_path('outdir_txt2img_grids'))
create_path(fix_path('outdir_img2img_grids'))
create_path(fix_path('outdir_save'))
create_path(fix_path('styles_dir'))
class Prioritize:
+3 -1
View File
@@ -536,7 +536,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
return None
stored_opts = {}
for k in p.override_settings.keys():
stored_opts[k] = shared.opts.data.get(k, None)
stored_opts[k] = shared.opts.data.get(k, None) or shared.opts.data_labels[k].default
try:
# if no checkpoint override or the override checkpoint can't be found, remove override entry and load opts checkpoint
if p.override_settings.get('sd_model_checkpoint', None) is not None and sd_models.checkpoint_aliases.get(p.override_settings.get('sd_model_checkpoint')) is None:
@@ -575,6 +575,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
setattr(shared.opts, k, v)
if k == 'sd_model_checkpoint':
sd_models.reload_model_weights()
if k == 'sd_model_refiner':
sd_models.reload_model_weights()
if k == 'sd_vae':
sd_vae.reload_vae_weights()
return res
+4 -1
View File
@@ -329,12 +329,15 @@ def read_metadata_from_safetensors(filename):
json_data = json_start + file.read(metadata_len-2)
json_obj = json.loads(json_data)
for k, v in json_obj.get("__metadata__", {}).items():
res[k] = v
if k == 'format' and v == 'pt':
continue
if isinstance(v, str) and v[0:1] == '{':
try:
res[k] = json.loads(v)
except Exception:
pass
else:
res[k] = v
sd_metadata[filename] = res
global sd_metadata_pending # pylint: disable=global-statement
sd_metadata_pending += 1
+1 -2
View File
@@ -631,7 +631,6 @@ options_templates.update(options_section(('interrogate', "Interrogate"), {
}))
options_templates.update(options_section(('extra_networks', "Extra Networks"), {
"ui_extra_networks_tab_reorder": OptionInfo("Checkpoints, Lora, LyCORIS, Textual Inversion, Hypernetworks", "Extra networks tab order"),
"extra_networks_card_cover": OptionInfo("sidebar", "UI position", gr.Radio, lambda: {"choices": ["cover", "inline", "sidebar"]}),
"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}),
@@ -820,7 +819,7 @@ opts.data['uni_pc_lower_order_final'] = opts.schedulers_use_loworder
opts.data['uni_pc_order'] = opts.schedulers_solver_order
log.info(f'Engine: backend={backend}')
prompt_styles = modules.styles.StyleDatabase(opts.styles_dir)
prompt_styles = modules.styles.StyleDatabase(opts)
cmd_opts.disable_extension_access = (cmd_opts.share or cmd_opts.listen or (cmd_opts.server_name or False)) and not cmd_opts.insecure
devices.device, devices.device_interrogate, devices.device_gfpgan, devices.device_esrgan, devices.device_codeformer = (devices.cpu if any(y in cmd_opts.use_cpu for y in [x, 'all']) else devices.get_optimal_device() for x in ['sd', 'interrogate', 'gfpgan', 'esrgan', 'codeformer'])
device = devices.device
+61 -17
View File
@@ -2,11 +2,11 @@
from __future__ import annotations
import csv
import os
import os.path
import tempfile
import json
import shutil
import typing
from installer import log
from modules import paths
if typing.TYPE_CHECKING:
@@ -18,6 +18,7 @@ class PromptStyle(typing.NamedTuple):
name: str
prompt: str
negative_prompt: str
extra: str = ""
def merge_prompts(style_prompt: str, prompt: str) -> str:
@@ -41,26 +42,38 @@ def apply_styles_to_prompt(prompt, styles):
class StyleDatabase:
def __init__(self, path: str):
def __init__(self, opts):
self.no_style = PromptStyle("None", "", "")
self.styles = {}
self.path = path
self.path = opts.styles_dir
if os.path.isfile(opts.styles_dir):
legacy_file = opts.styles_dir
self.load_csv(legacy_file)
opts.styles_dir = os.path.join(paths.models_path, "styles")
self.path = opts.styles_dir
self.mkdir()
self.save_styles(opts.styles_dir, verbose=True)
log.debug(f'Migrated styles: file={legacy_file} folder={self.path}')
self.mkdir()
self.reload()
def mkdir(self):
if not os.path.isdir(self.path):
os.makedirs(self.path, exist_ok=True)
log.debug(f'Created styles: folder={self.path}')
def reload(self):
self.styles.clear()
if not os.path.exists(self.path):
self.save_styles(self.path)
with open(self.path, "r", encoding="utf-8-sig", newline='') as file:
reader = csv.DictReader(file, skipinitialspace=True)
for row in reader:
for fn in os.listdir(self.path):
if not fn.endswith(".json"):
continue
with open(os.path.join(self.path, fn), 'r', encoding='utf-8') as f:
try:
prompt = row["prompt"] if "prompt" in row else row["text"]
negative_prompt = row.get("negative_prompt", "")
self.styles[row["name"]] = PromptStyle(row["name"], prompt, negative_prompt)
except Exception:
log.error(f'Styles error: {self.path} {row}')
log.debug(f'Loaded styles: {self.path} items={len(self.styles.keys())}')
style = json.load(f)
self.styles[style["name"]] = PromptStyle(style["name"], style["prompt"], style["negative"], style["extra"])
except Exception as e:
log.error(f'Failed to load style: file={fn} error={e}')
log.debug(f'Loaded styles: folder={self.path} items={len(self.styles.keys())}')
def get_style_prompts(self, styles):
return [self.styles.get(x, self.no_style).prompt for x in styles]
@@ -74,7 +87,38 @@ class StyleDatabase:
def apply_negative_styles_to_prompt(self, prompt, styles):
return apply_styles_to_prompt(prompt, [self.styles.get(x, self.no_style).negative_prompt for x in styles])
def save_styles(self, path: str) -> None:
def save_styles(self, path, verbose=False):
for name in list(self.styles):
style = {
"name": name,
"prompt": self.styles[name].prompt,
"negative": self.styles[name].negative_prompt,
"extra": "",
}
fn = os.path.join(path, name + ".json")
try:
with open(fn, 'w', encoding='utf-8') as f:
json.dump(style, f, indent=2)
if verbose:
log.debug(f'Saved style: name={name} file={fn}')
except Exception as e:
log.error(f'Failed to save style: name={name} file={path} error={e}')
log.debug(f'Saved styles: {path} {len(self.styles.keys())}')
def load_csv(self, legacy_file):
with open(legacy_file, "r", encoding="utf-8-sig", newline='') as file:
reader = csv.DictReader(file, skipinitialspace=True)
for row in reader:
try:
prompt = row["prompt"] if "prompt" in row else row["text"]
negative_prompt = row.get("negative_prompt", "")
self.styles[row["name"]] = PromptStyle(row["name"], prompt, negative_prompt)
except Exception:
log.error(f'Styles error: file={legacy_file} row={row}')
log.debug(f'Loaded legacy styles: file={legacy_file} items={len(self.styles.keys())}')
def save_csv(self, path: str) -> None:
import tempfile
basedir = os.path.dirname(path)
if basedir is not None and len(basedir) > 0:
os.makedirs(basedir, exist_ok=True)
@@ -83,5 +127,5 @@ class StyleDatabase:
writer = csv.DictWriter(file, fieldnames=PromptStyle._fields)
writer.writeheader()
writer.writerows(style._asdict() for k, style in self.styles.items())
log.debug(f'Saved styles: {path} {len(self.styles.keys())}')
log.debug(f'Saved legacy styles: {path} {len(self.styles.keys())}')
shutil.move(temp_path, path)
@@ -120,11 +120,11 @@ class EmbeddingDatabase:
return embedding
def get_expected_shape(self):
if shared.backend == shared.Backend.DIFFUSERS:
return 0
if shared.sd_model is None:
shared.log.error('Model not loaded')
return 0
if shared.backend == shared.Backend.DIFFUSERS:
return 0
vec = shared.sd_model.cond_stage_model.encode_embedding_init_text(",", 1)
return vec.shape[1]
@@ -213,11 +213,14 @@ class EmbeddingDatabase:
self.skipped_embeddings[name] = embedding
def load_from_dir(self, embdir):
if sd_models.model_data.sd_model is None:
shared.log.info('Skipping embeddings load: model not loaded')
return
if not os.path.isdir(embdir.path):
return
is_ext = extension_filter(['.PNG', '.WEBP', '.JXL', '.AVIF', '.BIN', '.PT', '.SAFETENSORS'])
is_not_preview = lambda fp: not next(iter(os.path.splitext(fp))).upper().endswith('.PREVIEW')
is_not_preview = lambda fp: not next(iter(os.path.splitext(fp))).upper().endswith('.PREVIEW') # pylint: disable=unnecessary-lambda-assignment
for file_path in [*filter(lambda fp: is_ext(fp) and is_not_preview(fp), directory_files(embdir.path))]:
try:
+6
View File
@@ -117,6 +117,10 @@ def apply_styles(prompt, prompt_neg, styles):
return [gr.Textbox.update(value=prompt), gr.Textbox.update(value=prompt_neg), gr.Dropdown.update(value=[])]
def parse_style(styles):
return styles.split('|')
def process_interrogate(interrogation_function, mode, ii_input_files, ii_input_dir, ii_output_dir, *ii_singles):
if mode in {0, 1, 3, 4}:
return [interrogation_function(ii_singles[mode]), None]
@@ -278,6 +282,8 @@ def create_toprow(is_img2img):
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 modules.shared.prompt_styles.styles.items()], value=[], multiselect=True)
create_refresh_button(prompt_styles, modules.shared.prompt_styles.reload, lambda: {"choices": [k for k, v in modules.shared.prompt_styles.styles.items()]}, f"refresh_{id_part}_styles")
prompt_styles_btn = gr.Button('Apply', elem_id=f"{id_part}_styles_select", visible=False)
prompt_styles_btn.click(_js="applyStyles", fn=parse_style, inputs=[prompt_styles], outputs=[prompt_styles])
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
+55 -58
View File
@@ -91,6 +91,7 @@ class ExtraNetworksPage:
self.html = ''
self.items = []
self.missing_thumbs = []
self.refresh_time = None
# class additional is to keep old extensions happy
self.card = '''
<div class='card' onclick={card_click} title='{title}' data-filename='{local_preview}' data-description='{description}' data-tags='{tags}'>
@@ -102,13 +103,12 @@ class ExtraNetworksPage:
<div class='additional'><ul></ul></div>
<span title="Save current image as preview image" onclick={card_save_preview}></span>
<span title="Save current description" onclick={card_save_desc}>🛅</span>
<span title="Read metadata" onclick={card_read_meta}>📘</span>
<span title="Read info" onclick={card_read_info}></span>
{card_extra}
</div>
</div>
<img class='preview' src='{preview}' style='width: {width}px; height: {height}px; object-fit: {fit}' loading='{loading}'></img>
</div>
''' # noqa: RUF001
'''
def refresh(self):
pass
@@ -168,11 +168,11 @@ class ExtraNetworksPage:
created += 1
except Exception as e:
shared.log.error(f'Extra network error creating thumbnail: {f} {e}')
if len(self.missing_thumbs) > 0:
if created > 0:
shared.log.info(f"Extra network created thumbnails: {self.name} {created}")
self.missing_thumbs.clear()
def create_html(self, tabname, skip = False):
def create_page(self, tabname, skip = False):
t0 = time.time()
self_name_id = self.name.replace(" ", "_")
if skip:
@@ -197,35 +197,35 @@ class ExtraNetworksPage:
<button class='lg secondary gradio-button custom-button{" search-all" if subdir=="" else ""}' onclick='extraNetworksSearchButton(event)'>
{html.escape(subdir) if subdir!="" else "all"}
</button><br>""" for subdir in subdirs])
try:
if len(self.html) > 0:
res = f"<div id='{tabname}_{self_name_id}_subdirs' class='extra-network-subdirs'>{subdirs_html}</div><div id='{tabname}_{self_name_id}_cards' class='extra-network-cards'>{self.html}</div>"
return res
self.html = ''
# try:
if len(self.html) > 0:
res = f"<div id='{tabname}_{self_name_id}_subdirs' class='extra-network-subdirs'>{subdirs_html}</div><div id='{tabname}_{self_name_id}_cards' class='extra-network-cards'>{self.html}</div>"
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}')
self.create_xyz_grid()
htmls = []
items = self.items
for item in items:
self.metadata[item["name"]] = item.get("metadata", {})
self.info[item["name"]] = self.find_info(item['filename'])
htmls.append(self.create_html_for_item(item, tabname))
self.html += ''.join(htmls)
if len(subdirs_html) > 0 or len(self.html) > 0:
res = f"<div id='{tabname}_{self_name_id}_subdirs' class='extra-network-subdirs'>{subdirs_html}</div><div id='{tabname}_{self_name_id}_cards' class='extra-network-cards'>{self.html}</div>"
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)}')
threading.Thread(target=self.create_thumb).start()
return res
except Exception as e:
shared.log.error(f'Extra networks page error: title={self.title} tab={tabname} class={e.__class__.__name__} {e}')
return f"<div id='{tabname}_{self_name_id}_subdirs' class='extra-network-subdirs'></div><div id='{tabname}_{self_name_id}_cards' class='extra-network-cards'>Extra network error<br>{e}</div>"
self.create_xyz_grid()
htmls = []
for item in self.items:
self.metadata[item["name"]] = item.get("metadata", {})
self.info[item["name"]] = item.get('info', None) or self.find_info(item['filename'])
htmls.append(self.create_html(item, tabname))
self.html += ''.join(htmls)
if len(subdirs_html) > 0 or len(self.html) > 0:
res = f"<div id='{tabname}_{self_name_id}_subdirs' class='extra-network-subdirs'>{subdirs_html}</div><div id='{tabname}_{self_name_id}_cards' class='extra-network-cards'>{self.html}</div>"
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)}')
threading.Thread(target=self.create_thumb).start()
return res
# except Exception as e:
# shared.log.error(f'Extra networks page error: title={self.title} tab={tabname} class={e.__class__.__name__} {e}')
# return f"<div id='{tabname}_{self_name_id}_subdirs' class='extra-network-subdirs'></div><div id='{tabname}_{self_name_id}_cards' class='extra-network-cards'>Extra network error<br>{e}</div>"
def list_items(self):
raise NotImplementedError
@@ -233,7 +233,7 @@ class ExtraNetworksPage:
def allowed_directories_for_previews(self):
return []
def create_html_for_item(self, item, tabname):
def create_html(self, item, tabname):
try:
args = {
"tabname": json.dumps(tabname),
@@ -252,11 +252,19 @@ class ExtraNetworksPage:
"card_click": item.get("onclick", '"' + html.escape(f'return cardClicked({item.get("prompt", None)}, {"true" if self.allow_negative_prompt else "false"})') + '"'),
"card_save_preview": '"' + html.escape('return saveCardPreview(event)') + '"',
"card_save_desc": '"' + html.escape('return saveCardDescription(event)') + '"',
"card_read_meta": '"' + html.escape(f'return readCardMetadata(event, {json.dumps(self.name)}, {json.dumps(item["name"])})') + '"',
"card_read_info": '"' + html.escape(f'return readCardInformation(event, {json.dumps(self.name)}, {json.dumps(item["name"])})') + '"',
"card_extra": "",
}
if item.get("alias", None) is not None:
args['title'] += f'\nAlias: {item["alias"]}'
metadata = item.get("metadata", None)
if metadata is not None and len(metadata) > 0:
card_read_meta = '"' + html.escape(f'return readCardMetadata(event, {json.dumps(self.name)}, {json.dumps(item["name"])})') + '"'
args['card_extra'] += f'<span title="Read metadata" onclick={card_read_meta}>📘</span>'
info = item.get("info", None)
if info is not None and len(info) > 0:
card_read_info = '"' + html.escape(f'return readCardInformation(event, {json.dumps(self.name)}, {json.dumps(item["name"])})') + '"'
args['card_extra'] += f'<span title="Read info" onclick={card_read_info}>️</span>' # noqa
alias = item.get("alias", None)
if alias is not None:
args['title'] += f'\nAlias: {alias}'
return self.card.format(**args)
except Exception as e:
shared.log.error(f'Extra networks item error: page={tabname} item={item["name"]} {e}')
@@ -308,9 +316,11 @@ def register_default_pages():
from modules.ui_extra_networks_textual_inversion import ExtraNetworksPageTextualInversion
from modules.ui_extra_networks_hypernets import ExtraNetworksPageHypernetworks
from modules.ui_extra_networks_checkpoints import ExtraNetworksPageCheckpoints
from modules.ui_extra_networks_styles import ExtraNetworksPageStyles
register_page(ExtraNetworksPageCheckpoints())
register_page(ExtraNetworksPageStyles())
register_page(ExtraNetworksPageTextualInversion())
register_page(ExtraNetworksPageHypernetworks())
register_page(ExtraNetworksPageCheckpoints())
class ExtraNetworksUi:
@@ -328,24 +338,10 @@ class ExtraNetworksUi:
self.search = None
def sort_extra_pages(pages):
tab_order = [x.lower().strip() for x in shared.opts.ui_extra_networks_tab_reorder.split(",")]
def tab_name_score(name):
name = name.lower()
for i, possible_match in enumerate(tab_order):
if possible_match in name:
return i
return len(pages)
tab_scores = {page.name: (tab_name_score(page.name), original_index) for original_index, page in enumerate(pages)}
return sorted(pages, key=lambda x: tab_scores[x.name])
def create_ui(container, button, tabname, skip_indexing = False):
ui = ExtraNetworksUi()
ui.pages = []
ui.stored_extra_pages = sort_extra_pages(extra_pages)
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")
@@ -359,9 +355,9 @@ def create_ui(container, button, tabname, skip_indexing = False):
for page in ui.stored_extra_pages:
shared.log.debug(f"Extra network page: {page.title} tab={tabname}")
page_html = page.create_html(ui.tabname, skip_indexing)
page_html = 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=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)
@@ -378,8 +374,9 @@ def create_ui(container, button, tabname, skip_indexing = False):
res = []
for pg in ui.stored_extra_pages:
pg.html = ''
pg.refresh_time = None
pg.refresh()
res.append(pg.create_html(ui.tabname))
res.append(pg.create_page(ui.tabname))
ui.search.update(value = ui.search.value)
return res
@@ -396,7 +393,7 @@ 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_html(ui.tabname) for page in ui.stored_extra_pages]
return [page.create_page(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
@@ -415,11 +412,11 @@ 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_html(ui.tabname) for page in ui.stored_extra_pages]
return [page.create_page(ui.tabname) for page in ui.stored_extra_pages]
ui.button_save_preview.click(
fn=save_preview,
_js="function(x, y, z){return [selected_gallery_index(), y, z]}",
_js="function(x, y, z) {return [selected_gallery_index(), y, z]}",
inputs=[ui.preview_target_filename, gallery, ui.preview_target_filename],
outputs=[*ui.pages]
)
@@ -435,11 +432,11 @@ 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_html(ui.tabname) for page in ui.stored_extra_pages]
return [page.create_page(ui.tabname) for page in ui.stored_extra_pages]
ui.button_save_description.click(
fn=save_description,
_js="function(x,y) {return [x,y]}",
_js="function(x, y) { return [x, y] }",
inputs=[ui.description_target_filename, ui.description],
outputs=[*ui.pages]
)
+1
View File
@@ -23,6 +23,7 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage):
"hash": checkpoint.shorthash,
"preview": self.find_preview(path),
"description": self.find_description(path),
"info": self.find_info(path),
"search_term": f'{self.search_terms_from_path(checkpoint.filename)} {(checkpoint.sha256 or "")} /{checkpoint.type}/',
"onclick": '"' + html.escape(f"""return selectCheckpoint({json.dumps(name)})""") + '"',
"local_preview": f"{path}.{shared.opts.samples_format}",
+1
View File
@@ -18,6 +18,7 @@ class ExtraNetworksPageHypernetworks(ui_extra_networks.ExtraNetworksPage):
"filename": path,
"preview": self.find_preview(path),
"description": self.find_description(path),
"info": self.find_info(path),
"search_term": self.search_terms_from_path(path),
"prompt": json.dumps(f"<hypernet:{name}:{shared.opts.extra_networks_default_multiplier}>"),
"local_preview": f"{path}.preview.{shared.opts.samples_format}",
+34
View File
@@ -0,0 +1,34 @@
import os
import html
import json
from modules import shared, ui_extra_networks
class ExtraNetworksPageStyles(ui_extra_networks.ExtraNetworksPage):
def __init__(self):
super().__init__('Styles')
def refresh(self):
shared.prompt_styles.reload()
def list_items(self):
styles = list(shared.prompt_styles.styles)
for style in styles:
path = os.path.join(shared.opts.styles_dir, style)
txt = f'Prompt: {shared.prompt_styles.styles[style].prompt}'
negative = shared.prompt_styles.styles[style].negative_prompt
if negative is not None and len(negative) > 0:
txt += f'\nNegative: {negative}'
yield {
"name": style,
"search_term": path,
"filename": path,
"preview": self.find_preview(path),
"description": txt,
"onclick": '"' + html.escape(f"""return selectStyle({json.dumps(style)})""") + '"',
"local_preview": f"{path}.{shared.opts.samples_format}",
}
def allowed_directories_for_previews(self):
return [v for v in [shared.opts.styles_dir] if v is not None]
@@ -29,6 +29,7 @@ class ExtraNetworksPageTextualInversion(ui_extra_networks.ExtraNetworksPage):
"filename": embedding.filename,
"preview": self.find_preview(path),
"description": self.find_description(path),
"info": self.find_info(path),
"search_term": self.search_terms_from_path(embedding.filename),
"prompt": json.dumps(os.path.splitext(embedding.name)[0]),
"local_preview": f"{path}.preview.{shared.opts.samples_format}",
+1 -1
View File
@@ -47,7 +47,7 @@ requests==2.31.0
tqdm==4.65.0
accelerate==0.20.3
opencv-python-headless==4.7.0.72
diffusers==0.20.1
diffusers==0.20.2
einops==0.4.1
gradio==3.41.2
huggingface_hub==0.16.4
+1 -1
View File
@@ -242,7 +242,7 @@ def start_common():
log.info(f'Using data path: {shared.cmd_opts.data_dir}')
if shared.cmd_opts.models_dir is not None and len(shared.cmd_opts.models_dir) > 0:
log.info(f'Using models path: {shared.cmd_opts.data_dir}')
create_paths(opts)
create_paths(opts, log)
async_policy()
initialize()
if shared.opts.clean_temp_dir_at_start: