add extra networks list view

pull/2440/head
Vladimir Mandic 2023-11-03 13:55:40 -04:00
parent da3d5d0fc7
commit 8432e68d30
10 changed files with 68 additions and 26 deletions

View File

@ -42,16 +42,20 @@ Some highlights: [OpenVINO](https://github.com/vladmandic/automatic/wiki/OpenVIN
- **compile** option, thanks @disty0
- **chaiNNer** add high quality models from [Helaman](https://openmodeldb.info/users/helaman)
- redesigned **Progress bar** with full details on current operation
- **Extra networks** sort by name, size, date, etc.
- new option: *settings -> images -> keep incomplete*
can be used to skip vae decode on aborted/skipped/interrupted image generations
- new option: *settings -> system paths -> models*
can be used to set custom base path for *all* models (previously only as cli option)
- remove external clone of items in `/repositories`
- **UI**
- **UI**
- UI tweaks for default themes
- UI switch core font in default theme to **noto-sans**
previously default font was simply *system-ui*, but it lead to too much variations between browsers and platforms
- updated **Context menu**
right-click on prompt or generate button
- **Extra networks**
- sort by name, size, date, etc.
- switch between *gallery* and *list* views
- **Packages**
- updated `diffusers` to 0.22.0, `transformers` to 4.34.1
- update **openvino**, thanks @disty0

View File

@ -21,7 +21,8 @@
{"id":"","label":"✕","localized":"","hint":"Close"},
{"id":"","label":"⊜","localized":"","hint":"Fill"},
{"id":"","label":"⌾","localized":"","hint":"Load model as refiner model when selected, otherwise load as base model"},
{"id":"","label":"🕸️","localized":"","hint":"Scan CivitAI for missing metadata and previews"},
{"id":"","label":"🔎︎","localized":"","hint":"Scan CivitAI for missing metadata and previews"},
{"id":"","label":"☲","localized":"","hint":"Change view type"},
{"id":"","label":"📐","localized":"","hint":"Measure"},
{"id":"","label":"🔍","localized":"","hint":"Search"}
],

View File

@ -108,7 +108,8 @@ svg.feather.feather-image, .feather .feather-image { display: none }
#img2img_label_copy_to_img2img { font-weight: normal; }
#txt2img_prompt, #txt2img_neg_prompt, #img2img_prompt, #img2img_neg_prompt { background-color: var(--background-color); box-shadow: 4px 4px 4px 0px #333333 !important; }
#txt2img_prompt > label > textarea, #txt2img_neg_prompt > label > textarea, #img2img_prompt > label > textarea, #img2img_neg_prompt > label > textarea { font-size: 1.0em; line-height: 1.4em; }
#txt2img_styles, #img2img_styles { margin-top: -5px; }
#txt2img_styles, #img2img_styles { padding: 0; }
#txt2img_styles_refresh, #img2img_styles_refresh { padding: 0; margin-top: 1em; }
#img2img_settings { min-width: calc(2 * var(--left-column)); max-width: calc(2 * var(--left-column)); background-color: #111111; padding-top: 16px; }
#interrogate, #deepbooru { margin: 0 0px 10px 0px; max-width: 80px; max-height: 80px; font-weight: normal; font-size: 0.95em; }
#quicksettings .gr-button-tool { font-size: 1.6rem; box-shadow: none; margin-left: -20px; margin-top: -2px; height: 2.4em; }

View File

@ -241,6 +241,7 @@ function setupExtraNetworksForTab(tabname) {
const btnSave = gradioApp().getElementById(`${tabname}_extra_save`);
const btnClose = gradioApp().getElementById(`${tabname}_extra_close`);
const btnSort = gradioApp().getElementById(`${tabname}_extra_sort`);
const btnView = gradioApp().getElementById(`${tabname}_extra_view`);
const btnModel = gradioApp().getElementById(`${tabname}_extra_model`);
const btnApply = gradioApp().getElementById(`${tabname}_extra_apply`);
const buttons = document.createElement('span');
@ -251,6 +252,7 @@ function setupExtraNetworksForTab(tabname) {
if (btnScan) buttons.appendChild(btnScan);
if (btnSave) buttons.appendChild(btnSave);
if (btnSort) buttons.appendChild(btnSort);
if (btnView) buttons.appendChild(btnView);
if (btnClose) buttons.appendChild(btnClose);
btnModel.onclick = () => btnModel.classList.toggle('toolbutton-selected');
tabs.appendChild(buttons);

View File

@ -106,7 +106,8 @@ svg.feather.feather-image, .feather .feather-image { display: none }
#img2img_label_copy_to_img2img { font-weight: normal; }
#txt2img_prompt, #txt2img_neg_prompt, #img2img_prompt, #img2img_neg_prompt { background-color: var(--background-color); box-shadow: 4px 4px 4px 0px #333333 !important; }
#txt2img_prompt > label > textarea, #txt2img_neg_prompt > label > textarea, #img2img_prompt > label > textarea, #img2img_neg_prompt > label > textarea { font-size: 1.0em; line-height: 1.4em; }
#txt2img_styles, #img2img_styles { margin-top: -5px; }
#txt2img_styles, #img2img_styles { padding: 0; }
#txt2img_styles_refresh, #img2img_styles_refresh { padding: 0; margin-top: 1em; }
#img2img_settings { min-width: calc(2 * var(--left-column)); max-width: calc(2 * var(--left-column)); background-color: #111111; padding-top: 16px; }
#interrogate, #deepbooru { margin: 0 0px 10px 0px; max-width: 80px; max-height: 80px; font-weight: normal; font-size: 0.95em; }
#quicksettings .gr-button-tool { font-size: 1.6rem; box-shadow: none; margin-left: -20px; margin-top: -2px; height: 2.4em; }

View File

@ -34,7 +34,8 @@ textarea { overflow-y: auto !important; }
.gradio-dropdown ul.options { z-index: 1000; min-width: fit-content; max-height: 33vh !important; white-space: nowrap; }
.gradio-dropdown ul.options li.item { padding: var(--spacing-xs); }
.gradio-dropdown ul.options li.item:not(:has(.hide)) { background-color: var(--primary-500); }
.gradio-dropdown span { margin-bottom: 0 !important; }
.gradio-dropdown .token { padding: var(--spacing-xs); }
.gradio-dropdown span { margin-bottom: 0 !important; font-size: 0.9em; }
.gradio-dropdown .reference { margin-bottom: var(--spacing-sm) !important; }
.gradio-html { color: var(--body-text-color); }
.gradio-html .min { min-height: 0; }
@ -183,7 +184,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
.extra-networks .description { flex: 3; }
.extra-networks .tab-nav > button { margin-right: 0; height: 24px; padding: 2px 4px 2px 4px; }
.extra-networks .buttons { position: absolute; right: 0; margin: -4px; background: var(--background-color); }
.extra-networks .buttons>button { height: 1.2em; margin-top: var(--spacing-md); }
.extra-networks .buttons > button { margin-left: -0.4em; height: 1.4em; color: var(--primary-300) !important; }
.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-networks-tab { padding: 0 !important; }
@ -204,6 +205,8 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
.extra-network-cards .card:hover .actions { display: block; }
.extra-network-cards .card:hover .overlay .tags { display: block; }
.extra-network-cards .card .actions { font-size: 3em; display: none; text-align-last: right; cursor: pointer; font-variant: unicase; position: absolute; z-index: 100; right: 0; height: 0.7em; width: 100%; background: rgba(0, 0, 0, 0.40); }
.extra-network-cards .card-list { display: flex; margin: 0.3em; padding: 0.3em; background: var(--input-background-fill); cursor: pointer; border-radius: var(--button-large-radius); }
.extra-network-cards .card-list .tag { color: var(--primary-500); margin-left: 0.8em; }
.extra-details-close { position: fixed; top: 0.2em; right: 0.2em; z-index: 99; background: var(--button-secondary-background-fill) !important; }
#txt2img_description, #img2img_description { max-height: 63px; overflow-y: auto !important; }
#txt2img_description > label > textarea, #img2img_description > label > textarea { font-size: 0.9em }

View File

@ -572,6 +572,7 @@ options_templates.update(options_section(('interrogate', "Interrogate"), {
options_templates.update(options_section(('extra_networks', "Extra Networks"), {
"extra_networks_sep1": OptionInfo("<h2>Extra networks UI</h2>", "", gr.HTML),
"extra_networks": OptionInfo(["All"], "Extra networks", ui_components.DropdownMulti, lambda: {"choices": ['All'] + [en.title for en in extra_networks]}),
"extra_networks_view": OptionInfo("gallery", "UI view", gr.Radio, {"choices": ["gallery", "list"]}),
"extra_networks_card_cover": OptionInfo("sidebar", "UI position", gr.Radio, {"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}),
@ -784,7 +785,6 @@ mem_mon = modules.memmon.MemUsageMonitor("MemMon", devices.device)
if devices.backend == "directml":
directml_do_hijack()
class TotalTQDM: # compatibility with previous global-tqdm
# import tqdm
def __init__(self):

View File

@ -273,7 +273,10 @@ def create_toprow(is_img2img):
negative_token_counter = gr.HTML(value="<span>0/75</span>", elem_id=f"{id_part}_negative_token_counter", elem_classes=["token-counter"])
negative_token_button = gr.Button(visible=False, elem_id=f"{id_part}_negative_token_button")
with gr.Row(elem_id=f"{id_part}_styles_row"):
prompt_styles = gr.Dropdown(label="Styles", elem_id=f"{id_part}_styles", choices=[style.name for style in modules.shared.prompt_styles.styles.values()], value=[], multiselect=True)
# prompt_styles = gr.Dropdown(label="Styles", elem_id=f"{id_part}_styles", choices=[style.name for style in modules.shared.prompt_styles.styles.values()], value=[], multiselect=True)
prompt_styles = gr.Dropdown(label="Styles", elem_id=f"{id_part}_styles", choices=['aaa'], value=[], multiselect=True)
prompt_styles_btn_refresh = ToolButton(symbols.refresh, elem_id=f"{id_part}_styles_refresh", visible=True)
prompt_styles_btn_refresh.click(fn=lambda: gr.update(choices=[style.name for style in modules.shared.prompt_styles.styles.values()]), inputs=[], outputs=[prompt_styles])
prompt_styles_btn_select = gr.Button('Select', elem_id=f"{id_part}_styles_select", visible=False)
prompt_styles_btn_select.click(_js="applyStyles", fn=parse_style, inputs=[prompt_styles], outputs=[prompt_styles])
prompt_styles_btn_apply = ToolButton(symbols.apply, elem_id=f"{id_part}_extra_apply", visible=False)

View File

@ -24,6 +24,28 @@ dir_cache = {} # key=path, value=(mtime, listdir(path))
refresh_time = 0
extra_pages = shared.extra_networks
debug = shared.log.info if os.environ.get('SD_EN_DEBUG', None) is not None else lambda *args, **kwargs: None
card_full = '''
<div class='card' onclick={card_click} title='{name}' data-tab='{tabname}' data-page='{page}' data-name='{name}' data-filename='{filename}' data-tags='{tags}' data-mtime='{mtime}' data-size='{size}'>
<div class='overlay'>
<span style="display:none" class='search_term'>{search_term}</span>
<div class='tags'></div>
<div class='name'>{title}</div>
</div>
<div class='actions'>
<span class='details' title="Get details" onclick="showCardDetails(event)">&#x1f6c8;</span>
<div class='additional'><ul></ul></div>
</div>
<img class='preview' src='{preview}' style='width: {width}px; height: {height}px; object-fit: {fit}' loading='lazy'></img>
</div>
'''
card_list = '''
<div class='card card-list' onclick={card_click} title='{name}' data-tab='{tabname}' data-page='{page}' data-name='{name}' data-filename='{filename}' data-tags='{tags}' data-mtime='{mtime}' data-size='{size}'>
<span class='details' title="Get details" onclick="showCardDetails(event)">&#x1f6c8;</span>&nbsp;
<div class='name'>{title}</div>&nbsp;
<div class='tags tags-list'></div>
<span style="display:none" class='search_term'>{search_term}</span>
</div>
'''
def listdir(path):
@ -116,21 +138,8 @@ class ExtraNetworksPage:
self.refresh_time = 0
self.page_time = 0
self.list_time = 0
# class additional is to keep old extensions happy
self.card = '''
<div class='card' onclick={card_click} title='{name}' data-tab='{tabname}' data-page='{page}' data-name='{name}' data-filename='{filename}' data-tags='{tags}' data-mtime='{mtime}' data-size='{size}'>
<div class='overlay'>
<span style="display:none" class='search_term'>{search_term}</span>
<div class='tags'></div>
<div class='name'>{title}</div>
</div>
<div class='actions'>
<span class='details' title="Get details" onclick="showCardDetails(event)">&#x1f6c8;</span>
<div class='additional'><ul></ul></div>
</div>
<img class='preview' src='{preview}' style='width: {width}px; height: {height}px; object-fit: {fit}' loading='lazy'></img>
</div>
'''
self.view = shared.opts.extra_networks_view
self.card = card_full if shared.opts.extra_networks_view == 'gallery' else card_list
def refresh(self):
pass
@ -219,7 +228,7 @@ class ExtraNetworksPage:
def create_page(self, tabname, skip = False):
debug(f'EN create-page: {self.name}')
if self.page_time > refresh_time: # cached page
if self.page_time > refresh_time and len(self.html) > 0: # cached page
return self.html
self_name_id = self.name.replace(" ", "_")
if skip:
@ -393,6 +402,7 @@ class ExtraNetworksUi:
self.button_details: gr.Button = None
self.button_refresh: gr.Button = None
self.button_scan: gr.Button = None
self.button_view: gr.Button = None
self.button_quicksave: gr.Button = None
self.button_save: gr.Button = None
self.button_sort: gr.Button = None
@ -495,6 +505,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
ui.button_quicksave = ToolButton(symbols.book, elem_id=tabname+"_extra_quicksave", visible=False)
ui.button_save = ToolButton(symbols.book, elem_id=tabname+"_extra_save", visible=False)
ui.button_sort = ToolButton(symbols.sort, elem_id=tabname+"_extra_sort", visible=True)
ui.button_view = ToolButton(symbols.view, elem_id=tabname+"_extra_view", visible=True)
ui.button_close = ToolButton(symbols.close, elem_id=tabname+"_extra_close", visible=True)
ui.button_model = ToolButton(symbols.refine, elem_id=tabname+"_extra_model", visible=True)
ui.search = gr.Textbox('', show_label=False, elem_id=tabname+"_extra_search", placeholder="Search...", elem_classes="textbox", lines=2, container=False)
@ -692,6 +703,20 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
ui.search.update(value = ui.search.value)
return pages
def ui_view_cards(title):
pages = []
for page in get_pages():
if title is None or title == '' or title == page.title or len(page.html) == 0:
shared.opts.extra_networks_view = page.view
page.view = 'gallery' if page.view == 'list' else 'list'
page.card = card_full if page.view == 'gallery' else card_list
page.html = ''
page.create_page(ui.tabname)
shared.log.debug(f"Refreshing Extra networks: page='{page.title}' items={len(page.items)} tab={ui.tabname} view={page.view}")
pages.append(page.html)
ui.search.update(value = ui.search.value)
return pages
def ui_scan_click(title):
from modules import ui_models
if ui_models.search_metadata_civit is not None:
@ -744,6 +769,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
button_parent.click(fn=toggle_visibility, inputs=[ui.visible], outputs=[ui.visible, container, button_parent])
ui.button_close.click(fn=toggle_visibility, inputs=[ui.visible], outputs=[ui.visible, container])
ui.button_sort.click(fn=ui_sort_cards, _js='sortExtraNetworks', inputs=[ui.search], outputs=[ui.description])
ui.button_view.click(fn=ui_view_cards, inputs=[ui.search], outputs=ui.pages)
ui.button_refresh.click(fn=ui_refresh_click, _js='getENActivePage', inputs=[ui.search], outputs=ui.pages)
ui.button_scan.click(fn=ui_scan_click, _js='getENActivePage', inputs=[ui.search], outputs=ui.pages)
ui.button_save.click(fn=ui_save_click, inputs=[], outputs=ui.details_components + [ui.details])

View File

@ -6,7 +6,8 @@ book = '🕮'
apply = ''
clear = ''
fill = ''
scan = '🕸️'
scan = '🔎︎'
view = ''
networks = '🌐'
paste = ''
refine = ''