mirror of
https://github.com/vladmandic/automatic
synced 2026-09-20 01:31:13 +02:00
new extra networks
This commit is contained in:
@@ -38,31 +38,18 @@ class ExtraNetwork:
|
||||
|
||||
def activate(self, p, params_list):
|
||||
"""
|
||||
Called by processing on every run. Whatever the extra network is meant to do should be activated here.
|
||||
Passes arguments related to this extra network in params_list.
|
||||
User passes arguments by specifying this in his prompt:
|
||||
|
||||
Called by processing on every run. Whatever the extra network is meant to do should be activated here. Passes arguments related to this extra network in params_list. User passes arguments by specifying this in his prompt:
|
||||
<name:arg1:arg2:arg3>
|
||||
|
||||
Where name matches the name of this ExtraNetwork object, and arg1:arg2:arg3 are any natural number of text arguments
|
||||
separated by colon.
|
||||
|
||||
Even if the user does not mention this ExtraNetwork in his prompt, the call will stil be made, with empty params_list -
|
||||
in this case, all effects of this extra networks should be disabled.
|
||||
|
||||
Where name matches the name of this ExtraNetwork object, and arg1:arg2:arg3 are any natural number of text arguments separated by colon.
|
||||
Even if the user does not mention this ExtraNetwork in his prompt, the call will stil be made, with empty params_list - in this case, all effects of this extra networks should be disabled.
|
||||
Can be called multiple times before deactivate() - each new call should override the previous call completely.
|
||||
|
||||
For example, if this ExtraNetwork's name is 'hypernet' and user's prompt is:
|
||||
|
||||
> "1girl, <hypernet:agm:1.1> <extrasupernet:master:12:13:14> <hypernet:ray>"
|
||||
|
||||
params_list will be:
|
||||
|
||||
[
|
||||
ExtraNetworkParams(items=["agm", "1.1"]),
|
||||
ExtraNetworkParams(items=["ray"])
|
||||
]
|
||||
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -70,20 +57,16 @@ class ExtraNetwork:
|
||||
"""
|
||||
Called at the end of processing for housekeeping. No need to do anything here.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def activate(p, extra_network_data):
|
||||
"""call activate for extra networks in extra_network_data in specified order, then call
|
||||
activate for all remaining registered networks with an empty argument list"""
|
||||
|
||||
"""call activate for extra networks in extra_network_data in specified order, then call activate for all remaining registered networks with an empty argument list"""
|
||||
for extra_network_name, extra_network_args in extra_network_data.items():
|
||||
extra_network = extra_network_registry.get(extra_network_name, None)
|
||||
if extra_network is None:
|
||||
print(f"Skipping unknown extra network: {extra_network_name}")
|
||||
continue
|
||||
|
||||
try:
|
||||
extra_network.activate(p, extra_network_args)
|
||||
except Exception as e:
|
||||
@@ -93,7 +76,6 @@ def activate(p, extra_network_data):
|
||||
args = extra_network_data.get(extra_network_name, None)
|
||||
if args is not None:
|
||||
continue
|
||||
|
||||
try:
|
||||
extra_network.activate(p, [])
|
||||
except Exception as e:
|
||||
@@ -101,14 +83,11 @@ def activate(p, extra_network_data):
|
||||
|
||||
|
||||
def deactivate(p, extra_network_data):
|
||||
"""call deactivate for extra networks in extra_network_data in specified order, then call
|
||||
deactivate for all remaining registered networks"""
|
||||
|
||||
"""call deactivate for extra networks in extra_network_data in specified order, then call deactivate for all remaining registered networks"""
|
||||
for extra_network_name in extra_network_data:
|
||||
extra_network = extra_network_registry.get(extra_network_name, None)
|
||||
if extra_network is None:
|
||||
continue
|
||||
|
||||
try:
|
||||
extra_network.deactivate(p)
|
||||
except Exception as e:
|
||||
@@ -118,7 +97,6 @@ def deactivate(p, extra_network_data):
|
||||
args = extra_network_data.get(extra_network_name, None)
|
||||
if args is not None:
|
||||
continue
|
||||
|
||||
try:
|
||||
extra_network.deactivate(p)
|
||||
except Exception as e:
|
||||
@@ -134,13 +112,9 @@ def parse_prompt(prompt):
|
||||
def found(m):
|
||||
name = m.group(1)
|
||||
args = m.group(2)
|
||||
|
||||
res[name].append(ExtraNetworkParams(items=args.split(":")))
|
||||
|
||||
return ""
|
||||
|
||||
prompt = re.sub(re_extra_net, found, prompt)
|
||||
|
||||
return prompt, res
|
||||
|
||||
|
||||
@@ -150,10 +124,8 @@ def parse_prompts(prompts):
|
||||
|
||||
for prompt in prompts:
|
||||
updated_prompt, parsed_extra_data = parse_prompt(prompt)
|
||||
|
||||
if extra_data is None:
|
||||
extra_data = parsed_extra_data
|
||||
|
||||
res.append(updated_prompt)
|
||||
|
||||
return res, extra_data
|
||||
|
||||
@@ -105,11 +105,13 @@ def create_buttons(tabs_list):
|
||||
for tab in tabs_list:
|
||||
name = tab
|
||||
if name == 'txt2img':
|
||||
name = 'text'
|
||||
name = 'Text'
|
||||
elif name == 'img2img':
|
||||
name = 'image'
|
||||
name = 'Image'
|
||||
elif name == 'inpaint':
|
||||
name = 'Inpaint'
|
||||
elif name == 'extras':
|
||||
name = 'process'
|
||||
name = 'Process'
|
||||
buttons[tab] = gr.Button(f"➠ {name}", elem_id=f"{tab}_tab")
|
||||
return buttons
|
||||
|
||||
|
||||
+1
-1
Submodule modules/lycoris updated: 4c20011113...b3776a3ab9
+5
-4
@@ -519,14 +519,15 @@ options_templates.update(options_section(('upscaling', "Upscaling"), {
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('extra_networks', "Extra Networks"), {
|
||||
"extra_networks_card_cover": OptionInfo("inline", "UI position", gr.Radio, lambda: {"choices": ["cover", "inline", "sidebar"]}),
|
||||
"extra_networks_card_size": OptionInfo(200, "UI card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}),
|
||||
"extra_networks_card_square": OptionInfo(False, "UI disable variable aspect ratio"),
|
||||
"extra_networks_card_fit": OptionInfo("cover", "UI image contain method", gr.Radio, lambda: {"choices": ["contain", "cover", "fill"]}),
|
||||
"lyco_patch_lora": OptionInfo(False, "Use LyCoris handler for all Lora types", gr.Checkbox),
|
||||
"lora_disable": OptionInfo(False, "Disable built-in Lora handler", gr.Checkbox, { "visible": True }, onchange=lora_disable),
|
||||
"lora_functional": OptionInfo(False, "Use Kohya method for handling multiple Loras", gr.Checkbox),
|
||||
"extra_networks_default_view": OptionInfo("cards", "Default view for Extra Networks", gr.Dropdown, {"choices": ["cards", "thumbs"]}),
|
||||
"extra_networks_default_multiplier": OptionInfo(1.0, "Multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"extra_networks_card_width": OptionInfo(0, "Card width for Extra Networks (px)"),
|
||||
"extra_networks_card_height": OptionInfo(0, "Card height for Extra Networks (px)"),
|
||||
"extra_networks_add_text_separator": OptionInfo(" ", "Extra text to add before <...> when adding extra network to prompt", gr.Text, { "visible": False }),
|
||||
"extra_networks_default_multiplier": OptionInfo(1.0, "Multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"sd_hypernetwork": OptionInfo("None", "Add hypernetwork to prompt", gr.Dropdown, lambda: {"choices": ["None"] + list(hypernetworks.keys())}, refresh=reload_hypernetworks),
|
||||
}))
|
||||
|
||||
|
||||
+4
-4
@@ -329,13 +329,13 @@ def create_ui():
|
||||
modules.scripts.scripts_current = modules.scripts.scripts_txt2img
|
||||
modules.scripts.scripts_txt2img.initialize_scripts(is_img2img=False)
|
||||
with gr.Blocks(analytics_enabled=False) as txt2img_interface:
|
||||
txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=False)
|
||||
txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, submit, _interrogate, _deepbooru, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=False)
|
||||
dummy_component = gr.Label(visible=False)
|
||||
txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="binary", visible=False)
|
||||
with FormRow(variant='compact', elem_id="txt2img_extra_networks", visible=False) as extra_networks_ui:
|
||||
from modules import ui_extra_networks
|
||||
extra_networks_ui = ui_extra_networks.create_ui(extra_networks_ui, extra_networks_button, 'txt2img')
|
||||
with gr.Row().style(equal_height=False):
|
||||
with gr.Row().style(equal_height=False, elem_id="txt2img_interface"):
|
||||
with gr.Column(variant='compact', elem_id="txt2img_settings"):
|
||||
for category in ordered_ui_categories():
|
||||
if category == "sampler":
|
||||
@@ -504,14 +504,14 @@ def create_ui():
|
||||
from modules import ui_extra_networks
|
||||
extra_networks_ui_img2img = ui_extra_networks.create_ui(extra_networks_ui, extra_networks_button, 'img2img')
|
||||
|
||||
with FormRow().style(equal_height=False):
|
||||
with FormRow().style(equal_height=False, elem_id="img2img_interface"):
|
||||
with gr.Column(variant='compact', elem_id="img2img_settings"):
|
||||
copy_image_buttons = []
|
||||
copy_image_destinations = {}
|
||||
|
||||
def add_copy_image_controls(tab_name, elem):
|
||||
with gr.Row(variant="compact", elem_id=f"img2img_copy_to_{tab_name}"):
|
||||
for title, name in zip(['➠ image', '➠ sketch', '➠ inpaint', '➠ inpaint sketch'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']):
|
||||
for title, name in zip(['➠ Image', '➠ Sketch', '➠ Inpaint', '➠ Inpaint sketch'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']):
|
||||
if name == tab_name:
|
||||
gr.Button(title, interactive=False)
|
||||
copy_image_destinations[name] = elem
|
||||
|
||||
@@ -164,10 +164,10 @@ def create_output_panel(tabname, outdir):
|
||||
|
||||
with gr.Column():
|
||||
with gr.Row(elem_id=f"image_buttons_{tabname}", elem_classes="image-buttons"):
|
||||
open_folder_button = gr.Button('show', visible=not shared.cmd_opts.hide_ui_dir_config)
|
||||
save = gr.Button('save', elem_id=f'save_{tabname}')
|
||||
save_zip = gr.Button('zip', elem_id=f'save_zip_{tabname}')
|
||||
delete = gr.Button('delete', elem_id=f'delete_{tabname}')
|
||||
open_folder_button = gr.Button('Show', visible=not shared.cmd_opts.hide_ui_dir_config)
|
||||
save = gr.Button('Save', elem_id=f'save_{tabname}')
|
||||
save_zip = gr.Button('Zip', elem_id=f'save_zip_{tabname}')
|
||||
delete = gr.Button('Delete', elem_id=f'delete_{tabname}')
|
||||
buttons = parameters_copypaste.create_buttons(["img2img", "inpaint", "extras"])
|
||||
|
||||
open_folder_button.click(fn=lambda: open_folder(shared.opts.outdir_samples or outdir), inputs=[], outputs=[])
|
||||
|
||||
@@ -26,6 +26,8 @@ def register_page(page):
|
||||
|
||||
def fetch_file(filename: str = ""):
|
||||
from starlette.responses import FileResponse, JSONResponse
|
||||
if filename.startswith('html/'):
|
||||
return FileResponse(filename, headers={"Accept-Ranges": "bytes"})
|
||||
if not any(Path(x).absolute() in Path(filename).absolute().parents for x in allowed_dirs):
|
||||
return JSONResponse({"error": f"File cannot be fetched: {filename}. Must be in one of directories registered by extra pages."})
|
||||
if os.path.splitext(filename)[1].lower() not in (".png", ".jpg", ".webp"):
|
||||
@@ -37,28 +39,52 @@ def get_metadata(page: str = "", item: str = ""):
|
||||
from starlette.responses import JSONResponse
|
||||
page = next(iter([x for x in extra_pages if x.name == page]), None)
|
||||
if page is None:
|
||||
return JSONResponse({})
|
||||
metadata = page.metadata.get(item)
|
||||
if metadata is None:
|
||||
return JSONResponse({})
|
||||
return JSONResponse({ 'metadata': 'none' })
|
||||
metadata = page.metadata.get(item, 'none')
|
||||
return JSONResponse({"metadata": metadata})
|
||||
|
||||
|
||||
def get_info(page: str = "", item: str = ""):
|
||||
from starlette.responses import JSONResponse
|
||||
page = next(iter([x for x in extra_pages if x.name == page]), None)
|
||||
if page is None:
|
||||
return JSONResponse({ 'info': 'none' })
|
||||
info = page.info.get(item, 'none')
|
||||
return JSONResponse({"info": info})
|
||||
|
||||
|
||||
def add_pages_to_demo(app):
|
||||
app.add_api_route("/sd_extra_networks/thumb", fetch_file, methods=["GET"])
|
||||
app.add_api_route("/sd_extra_networks/metadata", get_metadata, methods=["GET"])
|
||||
app.add_api_route("/sd_extra_networks/info", get_info, methods=["GET"])
|
||||
|
||||
|
||||
class ExtraNetworksPage:
|
||||
def __init__(self, title):
|
||||
self.title = title
|
||||
self.name = title.lower()
|
||||
self.card_long = shared.html("extra-networks-card-long.html")
|
||||
self.card_short = shared.html("extra-networks-card-short.html")
|
||||
self.allow_negative_prompt = False
|
||||
self.metadata = {}
|
||||
self.info = {}
|
||||
self.items = []
|
||||
self.missing_thumbs = []
|
||||
self.card = '''
|
||||
<div class='card' onclick={card_click}>
|
||||
<div class='overlay'>
|
||||
<span style="display:none" class='search_term'>{search_term}</span>
|
||||
<div class='name'>{name}</div>
|
||||
<div class='description'>{description}</div>
|
||||
<div class='actions'>
|
||||
<span title="Save current image as preview image" onclick={card_save_preview}>💙</span>
|
||||
<span title="Read description" onclick={card_read_desc}>📖</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>
|
||||
</div>
|
||||
</div>
|
||||
<img class='preview' src='{preview}' style='width: {width}px; height: {height}px; object-fit: {fit}' loading='lazy'></img>
|
||||
</div>
|
||||
''' # noqa: RUF001
|
||||
|
||||
def refresh(self):
|
||||
pass
|
||||
@@ -93,8 +119,11 @@ class ExtraNetworksPage:
|
||||
return ""
|
||||
|
||||
def is_empty(self, folder):
|
||||
files = [f for f in os.listdir(folder) if f.lower().endswith(".ckpt") or f.lower().endswith(".safetensors") or f.lower().endswith(".pt")]
|
||||
return len(files) == 0
|
||||
for f in os.listdir(folder):
|
||||
_fn, ext = os.path.splitext(f)
|
||||
if ext.lower() in ['.ckpt', '.safetensors', '.pt'] or os.path.isdir(os.path.join(folder, f)):
|
||||
return False
|
||||
return True
|
||||
|
||||
def create_thumb(self):
|
||||
created = 0
|
||||
@@ -115,9 +144,7 @@ class ExtraNetworksPage:
|
||||
self.missing_thumbs.clear()
|
||||
|
||||
def create_html(self, tabname):
|
||||
view = shared.opts.extra_networks_default_view
|
||||
items_html = ''
|
||||
self.metadata = {}
|
||||
subdirs = {}
|
||||
allowed_folders = [os.path.abspath(x) for x in self.allowed_directories_for_previews()]
|
||||
for parentdir in [*set(allowed_folders)]:
|
||||
@@ -137,28 +164,27 @@ class ExtraNetworksPage:
|
||||
subdirs_html = "".join([f"""
|
||||
<button class='lg secondary gradio-button custom-button{" search-all" if subdir=="" else ""}' onclick='extraNetworksSearchButton("{tabname}_extra_tabs", event)'>
|
||||
{html.escape(subdir) if subdir!="" else "all"}
|
||||
</button>""" for subdir in subdirs])
|
||||
try:
|
||||
self.items = list(self.list_items())
|
||||
self.create_xyz_grid()
|
||||
for item in self.items:
|
||||
metadata = item.get("metadata")
|
||||
if metadata:
|
||||
self.metadata[item["name"]] = metadata
|
||||
items_html += self.create_html_for_item(item, tabname)
|
||||
if items_html == '':
|
||||
dirs = "".join([f"<li>{x}</li>" for x in self.allowed_directories_for_previews()])
|
||||
items_html = shared.html("extra-networks-no-cards.html").format(dirs=dirs)
|
||||
self_name_id = self.name.replace(" ", "_")
|
||||
res = f"""
|
||||
<div id='{tabname}_{self_name_id}_subdirs' class='extra-network-subdirs extra-network-subdirs-{view}'>{subdirs_html}</div>
|
||||
<div id='{tabname}_{self_name_id}_cards' class='extra-network-{view}'>{items_html}</div>
|
||||
"""
|
||||
threading.Thread(target=self.create_thumb).start()
|
||||
return res
|
||||
except Exception as e:
|
||||
shared.log.error(f'Extra networks page error: {e}')
|
||||
return ''
|
||||
</button><br>""" for subdir in subdirs])
|
||||
# try:
|
||||
self.items = list(self.list_items())
|
||||
self.create_xyz_grid()
|
||||
for item in self.items:
|
||||
self.metadata[item["name"]] = item.get("metadata", {})
|
||||
self.info[item["name"]] = self.find_info(item['filename'])
|
||||
items_html += self.create_html_for_item(item, tabname)
|
||||
if items_html == '':
|
||||
dirs = "".join([f"<li>{x}</li>" for x in self.allowed_directories_for_previews()])
|
||||
items_html = f'<div class="nocards">No models found: ${dirs}</div>'
|
||||
self_name_id = self.name.replace(" ", "_")
|
||||
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'>{items_html}</div>
|
||||
"""
|
||||
threading.Thread(target=self.create_thumb).start()
|
||||
return res
|
||||
# except Exception as e:
|
||||
# shared.log.error(f'Extra networks page error: {e}')
|
||||
# return ''
|
||||
|
||||
def list_items(self):
|
||||
raise NotImplementedError
|
||||
@@ -168,35 +194,28 @@ class ExtraNetworksPage:
|
||||
|
||||
def create_html_for_item(self, item, tabname):
|
||||
preview = item.get("preview", None)
|
||||
onclick = item.get("onclick", None)
|
||||
if onclick is None:
|
||||
onclick = '"' + html.escape(f"""return cardClicked({json.dumps(tabname)}, {item["prompt"]}, {"true" if self.allow_negative_prompt else "false"})""") + '"'
|
||||
height = f"height: {shared.opts.extra_networks_card_height}px;" if shared.opts.extra_networks_card_height else ''
|
||||
width = f"width: {shared.opts.extra_networks_card_width}px;" if shared.opts.extra_networks_card_width else ''
|
||||
background_image = f"background-image: url(\"{html.escape(preview)}\");" if preview else ''
|
||||
args = {
|
||||
"style": f"'{height}{width}{background_image}'",
|
||||
"preview": html.escape(preview),
|
||||
"width": shared.opts.extra_networks_card_size,
|
||||
"height": shared.opts.extra_networks_card_size if shared.opts.extra_networks_card_square else 'auto',
|
||||
"fit": shared.opts.extra_networks_card_fit,
|
||||
"prompt": item.get("prompt", None),
|
||||
"tabname": json.dumps(tabname),
|
||||
"local_preview": json.dumps(item["local_preview"]),
|
||||
"name": item["name"],
|
||||
"description": (item.get("description") or ""),
|
||||
"card_clicked": onclick,
|
||||
"save_card_description": '"' + html.escape(f"""return saveCardDescription(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])})""") + '"',
|
||||
"save_card_preview": '"' + html.escape(f"""return saveCardPreview(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])})""") + '"',
|
||||
"read_card_description": '"' + html.escape(f"""return readCardDescription(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])}, {json.dumps(item.get("description", ""))}, {json.dumps(self.name)}, {json.dumps(item["name"])})""") + '"',
|
||||
"search_term": item.get("search_term", ""),
|
||||
"read_card_metadata": '"' + html.escape(f"""return readCardMetadata(event, {json.dumps(self.name)}, {json.dumps(item["name"])})""") + '"',
|
||||
"card_click": item.get("onclick", '"' + html.escape(f"""return cardClicked({json.dumps(tabname)}, {item.get("prompt", None)}, {"true" if self.allow_negative_prompt else "false"})""") + '"'),
|
||||
"card_save_desc": '"' + html.escape(f"""return saveCardDescription(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])})""") + '"',
|
||||
"card_save_preview": '"' + html.escape(f"""return saveCardPreview(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])})""") + '"',
|
||||
"card_read_desc": '"' + html.escape(f"""return readCardDescription(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])}, {json.dumps(item.get("description", ""))}, {json.dumps(self.name)}, {json.dumps(item["name"])})""") + '"',
|
||||
"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"])})""") + '"',
|
||||
}
|
||||
if item.get("metadata"):
|
||||
return self.card_long.format(**args)
|
||||
else:
|
||||
return self.card_short.format(**args)
|
||||
self.card.format(**args)
|
||||
return self.card.format(**args)
|
||||
|
||||
def find_preview(self, path):
|
||||
"""
|
||||
Find a preview PNG for a given path (without extension) and call link_preview on it.
|
||||
"""
|
||||
preview_extensions = ["jpg", "jpeg", "png", "webp", "tiff", "jp2"]
|
||||
for file in sum([[f'{path}.thumb.{ext}'] for ext in preview_extensions], []): # use thumbnail if exists
|
||||
if os.path.isfile(file):
|
||||
@@ -205,12 +224,9 @@ class ExtraNetworksPage:
|
||||
if os.path.isfile(file):
|
||||
self.missing_thumbs.append(file)
|
||||
return self.link_preview(file)
|
||||
return None
|
||||
return self.link_preview('html/card-no-preview.png')
|
||||
|
||||
def find_description(self, path):
|
||||
"""
|
||||
Find and read a description file for a given path (without extension).
|
||||
"""
|
||||
for file in [f"{path}.txt", f"{path}.description.txt"]:
|
||||
try:
|
||||
with open(file, "r", encoding="utf-8", errors="replace") as f:
|
||||
@@ -219,6 +235,16 @@ class ExtraNetworksPage:
|
||||
pass
|
||||
return None
|
||||
|
||||
def find_info(self, path):
|
||||
for file in [f"{path}.info", f"{path}.civitai.info"]:
|
||||
try:
|
||||
with open(file, "r", encoding="utf-8", errors="replace") as f:
|
||||
return f.read()
|
||||
except OSError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def initialize():
|
||||
extra_pages.clear()
|
||||
@@ -242,19 +268,21 @@ class ExtraNetworksUi:
|
||||
self.button_save_description = None
|
||||
self.button_read_description = None
|
||||
self.description_target_filename = None
|
||||
self.description_input = None
|
||||
self.description = None
|
||||
self.tabname = None
|
||||
self.search = None
|
||||
|
||||
|
||||
def pages_in_preferred_order(pages):
|
||||
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])
|
||||
|
||||
@@ -262,21 +290,23 @@ def pages_in_preferred_order(pages):
|
||||
def create_ui(container, button, tabname):
|
||||
ui = ExtraNetworksUi()
|
||||
ui.pages = []
|
||||
ui.stored_extra_pages = pages_in_preferred_order(extra_pages.copy())
|
||||
ui.stored_extra_pages = sort_extra_pages(extra_pages)
|
||||
ui.tabname = tabname
|
||||
with gr.Tabs(elem_id=tabname+"_extra_tabs"):
|
||||
ui.search = gr.Textbox('', show_label=False, elem_id=tabname+"_extra_search", placeholder="Search...", visible=True)
|
||||
ui.description_input = gr.TextArea('', show_label=False, elem_id=tabname+"_description_input", placeholder="Save/Replace Extra Network Description...", lines=2)
|
||||
button_refresh = ToolButton(refresh_symbol, elem_id=tabname+"_extra_refresh")
|
||||
button_close = ToolButton(close_symbol, elem_id=tabname+"_extra_close")
|
||||
ui.search = gr.Textbox('', show_label=False, elem_id=tabname+"_extra_search", placeholder="Search...", visible=True, elem_classes="textbox")
|
||||
ui.description = gr.TextArea('', show_label=False, elem_id=tabname+"_description", placeholder="Save/Replace Extra Network Description...", lines=2, elem_classes="textbox")
|
||||
|
||||
ui.button_save_preview = gr.Button('Save preview', elem_id=tabname+"_save_preview", visible=False)
|
||||
ui.preview_target_filename = gr.Textbox('Preview save filename', elem_id=tabname+"_preview_filename", visible=False)
|
||||
ui.button_save_description = gr.Button('Save description', elem_id=tabname+"_save_description", visible=False)
|
||||
ui.button_read_description = gr.Button('Read description', elem_id=tabname+"_read_description", visible=False)
|
||||
ui.description_target_filename = gr.Textbox('Description save filename', elem_id=tabname+"_description_filename", visible=False)
|
||||
|
||||
for page in ui.stored_extra_pages:
|
||||
with gr.Tab(page.title, id=page.title.lower().replace(" ", "_")):
|
||||
page_elem = gr.HTML(page.create_html(ui.tabname))
|
||||
with gr.Tab(page.title, id=page.title.lower().replace(" ", "_"), elem_classes="extra-networks-tab"):
|
||||
page_elem = gr.HTML(page.create_html(ui.tabname), elem_id=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)
|
||||
|
||||
@@ -322,6 +352,11 @@ def setup_ui(ui, gallery):
|
||||
break
|
||||
assert is_allowed, f'writing to {filename} is not allowed'
|
||||
image.save(filename)
|
||||
fn, _ext = os.path.splitext(filename)
|
||||
thumb = fn + '.thumb.jpg'
|
||||
if os.path.exists(thumb):
|
||||
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]
|
||||
|
||||
@@ -348,6 +383,6 @@ def setup_ui(ui, gallery):
|
||||
ui.button_save_description.click(
|
||||
fn=save_description,
|
||||
_js="function(x,y){return [x,y]}",
|
||||
inputs=[ui.description_target_filename, ui.description_input],
|
||||
inputs=[ui.description_target_filename, ui.description],
|
||||
outputs=[*ui.pages]
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user