From c5b089cbb665cdb02b8d3876b7340153da289e4c Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 26 Jul 2023 11:39:58 -0400 Subject: [PATCH] major ui simplification --- extensions-builtin/sd-webui-controlnet | 2 +- javascript/black-orange.css | 8 +- javascript/style.css | 17 +- modules/images.py | 4 +- modules/img2img.py | 3 +- modules/processing.py | 8 +- modules/shared.py | 13 - modules/ui.py | 433 ++++++++++++------------- modules/ui_extra_networks.py | 59 ++-- requirements.txt | 3 +- 10 files changed, 256 insertions(+), 294 deletions(-) diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index e9679f8fc..ff7aad9a7 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit e9679f8fc50880a92d6f1b6fc1aabad41079efd5 +Subproject commit ff7aad9a7045a4224da447c87bd37a189db01b94 diff --git a/javascript/black-orange.css b/javascript/black-orange.css index f7459095a..71bf1abcf 100644 --- a/javascript/black-orange.css +++ b/javascript/black-orange.css @@ -40,7 +40,7 @@ input[type=range]::-moz-range-thumb { box-shadow: 2px 2px 3px #111111; border: 0 ::-webkit-scrollbar { width: 12px; } ::-webkit-scrollbar-track { background: #333333; } ::-webkit-scrollbar-thumb { background-color: var(--highlight-color); border-radius: var(--radius-lg); border-width: 0; box-shadow: 2px 2px 3px #111111; } -div.form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; gap: 1em; margin-bottom: 6px; } +div.form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; margin-bottom: 6px; } div.compact { gap: 1em; } /* gradio style classes */ @@ -93,7 +93,7 @@ svg.feather.feather-image, .feather .feather-image { display: none } #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; } -#quicksettings > div, #quicksettings > fieldset { min-width: 24em; max-width: 26em; line-height: 1.6em; margin-top: 0.4em; } +#quicksettings > div, #quicksettings > fieldset { line-height: 1.6em; margin-top: 0.4em; } #open_folder_extras, #footer, #style_pos_col, #style_neg_col, #roll_col, #extras_upscaler_2, #extras_upscaler_2_visibility, #txt2img_seed_resize_from_w, #txt2img_seed_resize_from_h { display: none; } #save-animation { border-radius: var(--radius-sm) !important; margin-bottom: 16px; background-color: #111111; } #script_list { padding: 4px; margin-top: 20px; margin-bottom: 20px; } @@ -110,11 +110,7 @@ svg.feather.feather-image, .feather .feather-image { display: none } #extras_upscale { margin-top: 10px } #txt2img_progress_row > div { min-width: var(--left-column); max-width: var(--left-column); } #txt2img_results, #img2img_results, #extras_results { background-color: var(--background-color); padding: 0; } -#txt2img_seed_row { padding: 0; margin-top: 8px; } #txt2img_settings { min-width: var(--left-column); max-width: var(--left-column); background-color: #111111; padding-top: 16px; } -#txt2img_subseed_row { padding: 0; margin-top: 16px; } -#txt2img_subseed_show, #img2img_subseed_show { display: None } -#txt2img_subseed_strength { margin-top: 0; } #txtimg_hr_finalres { max-width: 200px; } #pnginfo_html2_info { margin-top: -18px; background-color: var(--input-background-fill); padding: var(--input-padding) } #txt2img_tools > div > button, #img2img_tools > div > button { filter: hue-rotate(180deg) saturate(0.5); } diff --git a/javascript/style.css b/javascript/style.css index f2fbcd3f2..1a90ee377 100644 --- a/javascript/style.css +++ b/javascript/style.css @@ -3,7 +3,7 @@ a { font-weight: bold; cursor: pointer; } h2 { margin-top: 1em !important; font-size: 1.4em !important; } div.gradio-container{ max-width: unset !important; padding: 8px !important; } div.tabitem { padding: 0 !important; } -div.form{ border-width: 0; box-shadow: none; background: transparent; overflow: visible; gap: 1em; } +div.form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; gap: 0.5em 1em; } div.compact{ gap: 1em; } div.gradio-html.min{ min-height: 0; } .block.gradio-checkbox { margin: 0.75em 1.5em 0 0; } @@ -34,7 +34,7 @@ td { border-bottom: none !important; } .gradio-button.secondary-down{ background: var(--button-secondary-background-fill); color: var(--button-secondary-text-color); } .gradio-button.secondary-down, .gradio-button.secondary-down:hover{ box-shadow: 1px 1px 1px rgba(0,0,0,0.25) inset, 0px 0px 3px rgba(0,0,0,0.15) inset; } .gradio-button.secondary-down:hover{ background: var(--button-secondary-background-fill-hover); color: var(--button-secondary-text-color-hover); } -.checkboxes-row{ margin-bottom: 0.5em; margin-left: 0em; } +.checkboxes-row { margin-bottom: 1em; gap: 0 !important; justify-content: space-around; } .checkboxes-row > div{ flex: 0; white-space: nowrap; min-width: auto; } button.custom-button{ @@ -120,6 +120,8 @@ button.custom-button{ flex: 1; } +#img2img_copy_to_img2img { margin-bottom: 2em; } + #txtimg_hr_finalres{ min-height: 0 !important; padding: .625rem .75rem; @@ -139,11 +141,6 @@ div#extras_scale_to_tab div.form{ flex-direction: row; } -#img2img_column_batch{ - align-self: end; - margin-bottom: 0.9em; -} - #img2img_unused_scale_by_slider { visibility: hidden; width: 0.5em; @@ -155,10 +152,6 @@ div#extras_scale_to_tab div.form{ opacity: 0.5; } -[id$=_column_batch] { - min-width: min(13.5em, 100%) !important; -} - div.dimensions-tools { min-width: 0 !important; max-width: fit-content; @@ -215,7 +208,7 @@ div#extras_scale_to_tab div.form{ /* settings */ #quicksettings { width: fit-content; align-items: end; } -#quicksettings > div, #quicksettings > fieldset{ max-width: 20em; min-width: 20em; padding: 0; border: none; box-shadow: none; background: none; } +#quicksettings > div, #quicksettings > fieldset{ max-width: 20em; min-width: 24em; padding: 0; border: none; box-shadow: none; background: none; } #quicksettings > button { margin-left: -0.5em; } #settings{ diff --git a/modules/images.py b/modules/images.py index 43e192989..fdcbac1de 100644 --- a/modules/images.py +++ b/modules/images.py @@ -236,8 +236,10 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None): return im if resize_mode == 0: - res = resize(im, width, height) + res = im.copy() elif resize_mode == 1: + res = resize(im, width, height) + elif resize_mode == 2: ratio = width / height src_ratio = im.width / im.height src_w = width if ratio > src_ratio else im.width * height // im.height diff --git a/modules/img2img.py b/modules/img2img.py index 9e822603e..661a0b023 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -131,8 +131,7 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s mask = None if image is not None: image = ImageOps.exif_transpose(image) - if selected_scale_tab == 1: - assert image, "Can't scale by because no image is selected" + if selected_scale_tab == 1 and resize_mode != 0: width = int(image.width * scale_by) height = int(image.height * scale_by) diff --git a/modules/processing.py b/modules/processing.py index 6c972e00a..7b54c29c9 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -1050,9 +1050,11 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): self.init_img_hash = hashlib.md5(img.tobytes()).hexdigest() # pylint: disable=attribute-defined-outside-init images.save_image(img, path=shared.opts.outdir_init_images, basename=None, forced_filename=self.init_img_hash, save_to_dirs=False) image = images.flatten(img, shared.opts.img2img_background_color) - if crop_region is None and self.resize_mode != 3: + if crop_region is None and self.resize_mode != 4: image = images.resize_image(self.resize_mode, image, self.width, self.height) - if image_mask is not None: + self.width = image.width + self.height = image.height + print('HERE2', self.width, self.height) image_masked = Image.new('RGBa', (image.width, image.height)) image_masked.paste(image.convert("RGBA").convert("RGBa"), mask=ImageOps.invert(self.mask_for_overlay.convert('L'))) self.mask = image_mask # assign early for diffusers @@ -1089,7 +1091,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): image = 2. * image - 1. image = image.to(device=shared.device, dtype=devices.dtype_vae) self.init_latent = self.sd_model.get_first_stage_encoding(self.sd_model.encode_first_stage(image)) - if self.resize_mode == 3: + if self.resize_mode == 4: self.init_latent = torch.nn.functional.interpolate(self.init_latent, size=(self.height // opt_f, self.width // opt_f), mode="bilinear") if image_mask is not None: init_mask = latent_mask diff --git a/modules/shared.py b/modules/shared.py index c3ed13535..75c60f99f 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -65,18 +65,6 @@ restricted_opts = { "outdir_save", "outdir_init_images" } -ui_reorder_categories = [ - "inpaint", - "sampler", - "dimensions", - "cfg", - "seed", - "batch", - "checkboxes", - "second_pass", - "override_settings", - "scripts", -] def is_url(string): @@ -513,7 +501,6 @@ options_templates.update(options_section(('ui', "User Interface"), { "hidden_tabs": OptionInfo([], "Hidden UI tabs", ui_components.DropdownMulti, lambda: {"choices": list(tab_names)}), "ui_tab_reorder": OptionInfo("From Text, From Image, Process Image", "UI tabs order"), "ui_scripts_reorder": OptionInfo("Enable Dynamic Thresholding, ControlNet", "UI scripts order"), - "ui_reorder": OptionInfo(", ".join(ui_reorder_categories), "txt2img/img2img UI item order"), })) options_templates.update(options_section(('live-preview', "Live Previews"), { diff --git a/modules/ui.py b/modules/ui.py index a31fa104c..21dba7504 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -148,24 +148,25 @@ def interrogate_deepbooru(image): return gr.update() if prompt is None else prompt -def create_seed_inputs(target_interface): - with FormRow(elem_id=f"{target_interface}_seed_row", variant="compact"): - seed = gr.Number(label='Seed', value=-1, elem_id=f"{target_interface}_seed") - seed.style(container=False) - random_seed = ToolButton(random_symbol, elem_id=f"{target_interface}_random_seed", label='Random seed') - reuse_seed = ToolButton(reuse_symbol, elem_id=f"{target_interface}_reuse_seed", label='Reuse seed') - with FormRow(visible=True, elem_id=f"{target_interface}_subseed_row"): - subseed = gr.Number(label='Variation seed', value=-1, elem_id=f"{target_interface}_subseed") - subseed.style(container=False) - random_subseed = ToolButton(random_symbol, elem_id=f"{target_interface}_random_subseed") - reuse_subseed = ToolButton(reuse_symbol, elem_id=f"{target_interface}_reuse_subseed") - subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01, elem_id=f"{target_interface}_subseed_strength") - with FormRow(visible=False): - seed_resize_from_w = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from width", value=0, elem_id=f"{target_interface}_seed_resize_from_w") - seed_resize_from_h = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from height", value=0, elem_id=f"{target_interface}_seed_resize_from_h") - random_seed.click(fn=lambda: [-1, -1], show_progress=False, inputs=[], outputs=[seed, subseed]) - random_subseed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[subseed]) - return seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w +def create_seed_inputs(tab, visible): + with FormGroup(visible=visible, elem_id=f"{tab}_seed_group") as seed_group: + with FormRow(elem_id=f"{tab}_seed_row", variant="compact"): + seed = gr.Number(label='Seed', value=-1, elem_id=f"{tab}_seed") + seed.style(container=False) + random_seed = ToolButton(random_symbol, elem_id=f"{tab}_random_seed", label='Random seed') + reuse_seed = ToolButton(reuse_symbol, elem_id=f"{tab}_reuse_seed", label='Reuse seed') + with FormRow(visible=True, elem_id=f"{tab}_subseed_row"): + subseed = gr.Number(label='Variation seed', value=-1, elem_id=f"{tab}_subseed") + subseed.style(container=False) + random_subseed = ToolButton(random_symbol, elem_id=f"{tab}_random_subseed") + reuse_subseed = ToolButton(reuse_symbol, elem_id=f"{tab}_reuse_subseed") + subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01, elem_id=f"{tab}_subseed_strength") + with FormRow(visible=False): + seed_resize_from_w = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from width", value=0, elem_id=f"{tab}_seed_resize_from_w") + seed_resize_from_h = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from height", value=0, elem_id=f"{tab}_seed_resize_from_h") + random_seed.click(fn=lambda: [-1, -1], show_progress=False, inputs=[], outputs=[seed, subseed]) + random_subseed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[subseed]) + return seed_group, seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w def connect_clear_prompt(button): @@ -313,12 +314,6 @@ def create_sampler_and_steps_selection(choices, tabname, primary: bool = True): return steps, sampler_index -def ordered_ui_categories(): - user_order = {x.strip(): i * 2 + 1 for i, x in enumerate(modules.shared.opts.ui_reorder.split(","))} - for _i, category in sorted(enumerate(modules.shared.ui_reorder_categories), key=lambda x: user_order.get(x[1], x[0] * 2 + 0)): - yield category - - def get_value_for_setting(key): value = getattr(opts, key) info = opts.data_labels[key] @@ -337,10 +332,10 @@ def create_ui(startup_timer = None): if startup_timer is None: from modules import timer startup_timer = timer.Timer() - import modules.img2img # pylint: disable=redefined-outer-name - import modules.txt2img # pylint: disable=redefined-outer-name reload_javascript() parameters_copypaste.reset() + + import modules.txt2img # pylint: disable=redefined-outer-name 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: @@ -352,67 +347,68 @@ def create_ui(startup_timer = None): extra_networks_ui = ui_extra_networks.create_ui(extra_networks_ui, extra_networks_button, 'txt2img', skip_indexing=opts.extra_network_skip_indexing) 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": - modules.sd_samplers.set_samplers() - steps, sampler_index = create_sampler_and_steps_selection(modules.sd_samplers.samplers, "txt2img", True) - elif category == "dimensions": - with FormRow(): - with gr.Column(elem_id="txt2img_column_size", scale=4): - with FormRow(elem_id="txt2img_row_dimension"): - width = gr.Slider(minimum=64, maximum=4096, step=8, label="Width", value=512, elem_id="txt2img_width") - height = gr.Slider(minimum=64, maximum=4096, step=8, label="Height", value=512, elem_id="txt2img_height") - with gr.Column(elem_id="txt2img_dimensions_row", scale=1, elem_classes="dimensions-tools"): - res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn", label="Switch dims") - with gr.Column(elem_id="txt2img_column_batch"): - with FormRow(elem_id="txt2img_row_batch"): - batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count") - batch_size = gr.Slider(minimum=1, maximum=32, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size") - elif category == "cfg": - with FormRow(): - cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='CFG Scale', value=6.0, elem_id="txt2img_cfg_scale") - clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=1, maximum=14, step=1, elem_id='txt2img_clip_skip', interactive=True) - elif category == "seed": - seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = create_seed_inputs('txt2img') - elif category == "checkboxes": - with FormRow(elem_classes="checkboxes-row", variant="compact"): - second_pass = gr.Checkbox(label='Second pass', value=False, elem_id="txt2img_enable_hr") - restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(modules.shared.face_restorers) > 1, elem_id="txt2img_restore_faces") - tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling") - elif category == "second_pass": - with FormGroup(visible=False, elem_id="txt2img_second_pass") as hr_options: - hr_second_pass_steps, latent_index = create_sampler_and_steps_selection(modules.sd_samplers.samplers, "txt2img", False) - with FormRow(elem_id="txt2img_hires_fix_row1", variant="compact"): - denoising_strength = gr.Slider(minimum=0.05, maximum=1.0, step=0.01, label='Denoising strength', value=0.3, elem_id="txt2img_denoising_strength") + modules.sd_samplers.set_samplers() + steps, sampler_index = create_sampler_and_steps_selection(modules.sd_samplers.samplers, "txt2img", True) - with FormRow(): - hr_final_resolution = FormHTML(value="", elem_id="txtimg_hr_finalres", label="Upscaled resolution", interactive=False) - with FormRow(elem_id="txt2img_hires_fix_row2", variant="compact"): - hr_upscaler = gr.Dropdown(label="Upscaler", elem_id="txt2img_hr_upscaler", choices=[*modules.shared.latent_upscale_modes, *[x.name for x in modules.shared.sd_upscalers]], value=modules.shared.latent_upscale_default_mode) - hr_scale = gr.Slider(minimum=1.0, maximum=4.0, step=0.05, label="Upscale by", value=2.0, elem_id="txt2img_hr_scale") - with FormRow(elem_id="txt2img_hires_fix_row3", variant="compact"): - hr_resize_x = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize width to", value=0, elem_id="txt2img_hr_resize_x") - hr_resize_y = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize height to", value=0, elem_id="txt2img_hr_resize_y") + with FormRow(): + width = gr.Slider(minimum=64, maximum=4096, step=8, label="Width", value=512, elem_id="txt2img_width") + height = gr.Slider(minimum=64, maximum=4096, step=8, label="Height", value=512, elem_id="txt2img_height") + res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn", label="Switch dims") - with FormRow(): - hr_refiner = FormHTML(value="Refiner", elem_id="txtimg_hr_finalres", interactive=False) - with FormRow(elem_id="txt2img_refiner_row1", variant="compact"): - image_cfg_scale = gr.Slider(minimum=1.1, maximum=30.0, step=0.1, label='Secondary CFG Scale', value=6.0, elem_id="txt2img_image_cfg_scale") - diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance rescale', value=0.7, elem_id="txt2img_image_cfg_rescale") - refiner_denoise_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise start', value=0.8, elem_id="txt2img_refiner_denoise_start") - refiner_denoise_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise end', value=1.0, elem_id="txt2img_refiner_denoise_end") - with FormRow(elem_id="txt2img_refiner_row2", variant="compact"): - refiner_prompt = gr.Textbox(value='', label='Prompt') - with FormRow(elem_id="txt2img_refiner_row3", variant="compact"): - refiner_negative = gr.Textbox(value='', label='Negative prompt') + with FormRow(elem_classes="checkboxes-row", variant="compact"): + show_batch = gr.Checkbox(label='Batch', value=True, elem_id="txt2img_show_batch") + show_seed = gr.Checkbox(label='Seed', value=False, elem_id="txt2img_show_seed") + show_advanced = gr.Checkbox(label='Advanced', value=False, elem_id="txt2img_show_advanced") + show_second_pass = gr.Checkbox(label='Second pass', value=False, elem_id="txt2img_show_second_pass") - elif category == "override_settings": - with FormRow(elem_id="txt2img_override_settings_row") as row: - override_settings = create_override_settings_dropdown('txt2img', row) - elif category == "scripts": - with FormGroup(elem_id="txt2img_script_container"): - custom_inputs = modules.scripts.scripts_txt2img.setup_ui() - hr_resolution_preview_inputs = [second_pass, width, height, hr_scale, hr_resize_x, hr_resize_y] + with FormGroup(visible=show_batch.value, elem_id="txt2img_batch") as batch_group: + with FormRow(elem_id="txt2img_row_batch"): + batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count") + batch_size = gr.Slider(minimum=1, maximum=32, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size") + batch_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_batch_switch_btn", label="Switch dims") + + seed_group, seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = create_seed_inputs('txt2img', show_seed.value) + + with FormGroup(visible=show_advanced.value, elem_id="txt2img_advanced") as advanced_group: + with FormRow(): + cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='CFG Scale', value=6.0, elem_id="txt2img_cfg_scale") + clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=1, maximum=14, step=1, elem_id='txt2img_clip_skip', interactive=True) + with FormRow(elem_classes="checkboxes-row", variant="compact"): + restore_faces = gr.Checkbox(label='Face restore', value=False, visible=len(modules.shared.face_restorers) > 1, elem_id="txt2img_restore_faces") + tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling") + + with FormGroup(visible=show_second_pass.value, elem_id="txt2img_second_pass") as second_pass: + hr_second_pass_steps, latent_index = create_sampler_and_steps_selection(modules.sd_samplers.samplers, "txt2img", False) + with FormRow(elem_id="txt2img_hires_fix_row1", variant="compact"): + denoising_strength = gr.Slider(minimum=0.05, maximum=1.0, step=0.01, label='Denoising strength', value=0.3, elem_id="txt2img_denoising_strength") + with FormRow(): + hr_final_resolution = FormHTML(value="", elem_id="txtimg_hr_finalres", label="Upscaled resolution", interactive=False) + with FormRow(elem_id="txt2img_hires_fix_row2", variant="compact"): + hr_upscaler = gr.Dropdown(label="Upscaler", elem_id="txt2img_hr_upscaler", choices=[*modules.shared.latent_upscale_modes, *[x.name for x in modules.shared.sd_upscalers]], value=modules.shared.latent_upscale_default_mode) + hr_scale = gr.Slider(minimum=1.0, maximum=4.0, step=0.05, label="Upscale by", value=2.0, elem_id="txt2img_hr_scale") + with FormRow(elem_id="txt2img_hires_fix_row3", variant="compact"): + hr_resize_x = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize width to", value=0, elem_id="txt2img_hr_resize_x") + hr_resize_y = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize height to", value=0, elem_id="txt2img_hr_resize_y") + + with FormRow(): + hr_refiner = FormHTML(value="Refiner", elem_id="txtimg_hr_refiner", interactive=False) + with FormRow(elem_id="txt2img_refiner_row1", variant="compact"): + image_cfg_scale = gr.Slider(minimum=1.1, maximum=30.0, step=0.1, label='Secondary CFG Scale', value=6.0, elem_id="txt2img_image_cfg_scale") + diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance rescale', value=0.7, elem_id="txt2img_image_cfg_rescale") + refiner_denoise_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise start', value=0.8, elem_id="txt2img_refiner_denoise_start") + refiner_denoise_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise end', value=1.0, elem_id="txt2img_refiner_denoise_end") + with FormRow(elem_id="txt2img_refiner_row2", variant="compact"): + refiner_prompt = gr.Textbox(value='', label='Prompt') + with FormRow(elem_id="txt2img_refiner_row3", variant="compact"): + refiner_negative = gr.Textbox(value='', label='Negative prompt') + + with FormRow(elem_id="txt2img_override_settings_row") as row: + override_settings = create_override_settings_dropdown('txt2img', row) + + with FormGroup(elem_id="txt2img_script_container"): + custom_inputs = modules.scripts.scripts_txt2img.setup_ui() + + hr_resolution_preview_inputs = [show_second_pass, width, height, hr_scale, hr_resize_x, hr_resize_y] for preview_input in hr_resolution_preview_inputs: preview_input.change( fn=calc_resolution_hires, @@ -455,18 +451,19 @@ def create_ui(startup_timer = None): ], show_progress=False, ) - txt2img_prompt.submit(**txt2img_args) submit.click(**txt2img_args) - res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False) - - txt_prompt_img.change(fn=modules.images.image_data, inputs=[txt_prompt_img], outputs=[txt2img_prompt, txt_prompt_img]) - def enable_hr_change(visible: bool): return {"visible": visible, "__type__": "update"}, f'Refiner{": disabled" if modules.shared.sd_refiner is None else ""}' - second_pass.change(enable_hr_change, inputs=[second_pass], outputs=[hr_options, hr_refiner], show_progress = False) + res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False) + batch_switch_btn.click(lambda w, h: (h, w), inputs=[batch_count, batch_size], outputs=[batch_count, batch_size], show_progress=False) + txt_prompt_img.change(fn=modules.images.image_data, inputs=[txt_prompt_img], outputs=[txt2img_prompt, txt_prompt_img]) + show_second_pass.change(enable_hr_change, inputs=[show_second_pass], outputs=[second_pass, hr_refiner], show_progress = False) + show_seed.change(gr_show, inputs=[show_seed], outputs=[seed_group], show_progress = False) + show_batch.change(gr_show, inputs=[show_batch], outputs=[batch_group], show_progress = False) + show_advanced.change(gr_show, inputs=[show_advanced], outputs=[advanced_group], show_progress = False) txt2img_paste_fields = [ (txt2img_prompt, "Prompt"), @@ -487,7 +484,7 @@ def create_ui(startup_timer = None): (seed_resize_from_h, "Seed resize from-2"), (denoising_strength, "Denoising strength"), (second_pass, lambda d: "Denoising strength" in d), - (hr_options, lambda d: gr.Row.update(visible="Denoising strength" in d)), + (second_pass, lambda d: gr.Row.update(visible="Denoising strength" in d)), (hr_scale, "Hires upscale"), (hr_upscaler, "Hires upscaler"), (hr_second_pass_steps, "Hires steps"), @@ -505,11 +502,11 @@ def create_ui(startup_timer = None): startup_timer.record("ui-txt2img") + import modules.img2img # pylint: disable=redefined-outer-name modules.scripts.scripts_current = modules.scripts.scripts_img2img modules.scripts.scripts_img2img.initialize_scripts(is_img2img=True) with gr.Blocks(analytics_enabled=False) as img2img_interface: img2img_prompt, img2img_prompt_styles, img2img_negative_prompt, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, img2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=True) - img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="binary", visible=False) with FormRow(variant='compact', elem_id="img2img_extra_networks", visible=False) as extra_networks_ui: @@ -521,6 +518,9 @@ def create_ui(startup_timer = None): copy_image_buttons = [] copy_image_destinations = {} + def copy_image(img): + return img['image'] if isinstance(img, dict) and 'image' in img else img + 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']): @@ -528,7 +528,6 @@ def create_ui(startup_timer = None): gr.Button(title, interactive=False) copy_image_destinations[name] = elem continue - button = gr.Button(title) copy_image_buttons.append((button, name, elem)) @@ -582,139 +581,122 @@ def create_ui(startup_timer = None): for i, tab in enumerate(img2img_tabs): tab.select(fn=lambda tabnum=i: tabnum, inputs=[], outputs=[img2img_selected_tab]) - def copy_image(img): - if isinstance(img, dict) and 'image' in img: - return img['image'] - - return img - for button, name, elem in copy_image_buttons: - button.click( - fn=copy_image, - inputs=[elem], - outputs=[copy_image_destinations[name]], - ) - button.click( - fn=lambda: None, - _js=f"switch_to_{name.replace(' ', '_')}", - inputs=[], - outputs=[], - ) + button.click(fn=copy_image, inputs=[elem], outputs=[copy_image_destinations[name]]) + button.click(fn=lambda: None, _js=f"switch_to_{name.replace(' ', '_')}", inputs=[], outputs=[]) - with FormRow(): - resize_mode = gr.Radio(label="Resize mode", elem_id="resize_mode", choices=["Resize fixed", "Crop and resize", "Resize and fill", "Resize using Latent upscale"], type="index", value="Resize and fill") + modules.sd_samplers.set_samplers() + steps, sampler_index = create_sampler_and_steps_selection(modules.sd_samplers.samplers_for_img2img, "img2img", True) - for category in ordered_ui_categories(): - if category == "sampler": - modules.sd_samplers.set_samplers() - steps, sampler_index = create_sampler_and_steps_selection(modules.sd_samplers.samplers_for_img2img, "img2img", True) + with FormRow(elem_classes="checkboxes-row", variant="compact"): + show_seed = gr.Checkbox(label='Seed', value=False, elem_id="img2img_show_seed") + show_resize = gr.Checkbox(label='Resize', value=False, elem_id="img2img_show_resize") + show_batch = gr.Checkbox(label='Batch', value=False, elem_id="img2img_show_batch") + show_denoise = gr.Checkbox(label='Denoise', value=True, elem_id="img2img_show_denoise") + show_advanced = gr.Checkbox(label='Advanced', value=False, elem_id="txt2img_show_advanced") - elif category == "dimensions": - with FormRow(): - with gr.Column(elem_id="img2img_column_size", scale=4): - selected_scale_tab = gr.State(value=0) # pylint: disable=abstract-class-instantiated + with FormGroup(visible=show_resize.value, elem_id=f"{tab}_resize_group") as resize_group: + with FormRow(): + resize_mode = gr.Radio(label="Resize mode", elem_id="resize_mode", choices=["None", "Resize fixed", "Crop and resize", "Resize and fill", "Resize using Latent upscale"], type="index", value="None") - with gr.Tabs(): - with gr.Tab(label="Resize to") as tab_scale_to: - with FormRow(): - with gr.Column(elem_id="img2img_column_size", scale=4): - with FormRow(): - width = gr.Slider(minimum=64, maximum=4096, step=8, label="Width", value=512, elem_id="img2img_width") - height = gr.Slider(minimum=64, maximum=4096, step=8, label="Height", value=512, elem_id="img2img_height") - with gr.Column(elem_id="img2img_column_dim", scale=1, elem_classes="dimensions-tools"): - with FormRow(): - res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn") - detect_image_size_btn = ToolButton(value=detect_image_size_symbol, elem_id="img2img_detect_image_size_btn") + with FormRow(): + with gr.Column(elem_id="img2img_column_size", scale=4): + selected_scale_tab = gr.State(value=0) # pylint: disable=abstract-class-instantiated - with gr.Tab(label="Resize by") as tab_scale_by: - scale_by = gr.Slider(minimum=0.05, maximum=4.0, step=0.05, label="Scale", value=1.0, elem_id="img2img_scale") + with gr.Tabs(): + with gr.Tab(label="Resize to") as tab_scale_to: + with FormRow(): + with gr.Column(elem_id="img2img_column_size", scale=4): + with FormRow(): + width = gr.Slider(minimum=64, maximum=4096, step=8, label="Width", value=512, elem_id="img2img_width") + height = gr.Slider(minimum=64, maximum=4096, step=8, label="Height", value=512, elem_id="img2img_height") + with gr.Column(elem_id="img2img_column_dim", scale=1, elem_classes="dimensions-tools"): + with FormRow(): + res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn") + detect_image_size_btn = ToolButton(value=detect_image_size_symbol, elem_id="img2img_detect_image_size_btn") - with FormRow(): - scale_by_html = FormHTML(resize_from_to_html(0, 0, 0.0), elem_id="img2img_scale_resolution_preview") - gr.Slider(label="Unused", elem_id="img2img_unused_scale_by_slider") - button_update_resize_to = gr.Button(visible=False, elem_id="img2img_update_resize_to") + with gr.Tab(label="Resize by") as tab_scale_by: + scale_by = gr.Slider(minimum=0.05, maximum=4.0, step=0.05, label="Scale", value=1.0, elem_id="img2img_scale") - on_change_args = dict( - fn=resize_from_to_html, - _js="currentImg2imgSourceResolution", - inputs=[dummy_component, dummy_component, scale_by], - outputs=scale_by_html, - show_progress=False, - ) + with FormRow(): + scale_by_html = FormHTML(resize_from_to_html(0, 0, 0.0), elem_id="img2img_scale_resolution_preview") + gr.Slider(label="Unused", elem_id="img2img_unused_scale_by_slider") + button_update_resize_to = gr.Button(visible=False, elem_id="img2img_update_resize_to") - scale_by.release(**on_change_args) - button_update_resize_to.click(**on_change_args) - - # the code below is meant to update the resolution label after the image in the image selection UI has changed. - # as it is now the event keeps firing continuously for inpaint edits, which ruins the page with constant requests. - # I assume this must be a gradio bug and for now we'll just do it for non-inpaint inputs. - for component in [init_img, sketch]: - component.change(fn=lambda: None, _js="updateImg2imgResizeToTextAfterChangingImage", inputs=[], outputs=[], show_progress=False) - - tab_scale_to.select(fn=lambda: 0, inputs=[], outputs=[selected_scale_tab]) - tab_scale_by.select(fn=lambda: 1, inputs=[], outputs=[selected_scale_tab]) - - with FormRow(elem_id="img2img_column_batch"): - batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count") - batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="img2img_batch_size") - clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=1, maximum=4, step=1, elem_id='img2img_clip_skip', interactive=True) - - elif category == "cfg": - with FormGroup(): - with FormRow(): - cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=6.0, elem_id="img2img_cfg_scale") - image_cfg_scale = gr.Slider(minimum=0, maximum=30.0, step=0.05, label='Image CFG Scale', value=1.5, elem_id="img2img_image_cfg_scale") - diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance Rescale', value=0.7, elem_id="txt2img_image_cfg_rescale") - with FormRow(): - denoising_strength = gr.Slider(minimum=0.05, maximum=1.0, step=0.01, label='Denoising strength', value=0.75, elem_id="img2img_denoising_strength") - refiner_denoise_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise start', value=0.0, elem_id="txt2img_refiner_denoise_start") - refiner_denoise_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise end', value=1.0, elem_id="txt2img_refiner_denoise_end") - - elif category == "seed": - seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = create_seed_inputs('img2img') - - elif category == "checkboxes": - with FormRow(elem_classes="checkboxes-row", variant="compact"): - restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(modules.shared.face_restorers) > 1, elem_id="img2img_restore_faces") - tiling = gr.Checkbox(label='Tiling', value=False, elem_id="img2img_tiling") - - elif category == "override_settings": - with FormRow(elem_id="img2img_override_settings_row") as row: - override_settings = create_override_settings_dropdown('img2img', row) - - elif category == "scripts": - with FormGroup(elem_id="img2img_script_container"): - custom_inputs = modules.scripts.scripts_img2img.setup_ui() - - elif category == "inpaint": - with FormGroup(elem_id="inpaint_controls", visible=False) as inpaint_controls: - with FormRow(): - mask_blur = gr.Slider(label='Mask blur', minimum=0, maximum=64, step=1, value=4, elem_id="img2img_mask_blur") - mask_alpha = gr.Slider(label="Mask transparency", visible=False, elem_id="img2img_mask_alpha") - - with FormRow(): - inpainting_mask_invert = gr.Radio(label='Mask mode', choices=['Inpaint masked', 'Inpaint not masked'], value='Inpaint masked', type="index", elem_id="img2img_mask_mode") - - with FormRow(): - inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='original', type="index", elem_id="img2img_inpainting_fill") - - with FormRow(): - with gr.Column(): - inpaint_full_res = gr.Radio(label="Inpaint area", choices=["Whole picture", "Only masked"], type="index", value="Whole picture", elem_id="img2img_inpaint_full_res") - - with gr.Column(scale=4): - inpaint_full_res_padding = gr.Slider(label='Only masked padding, pixels', minimum=0, maximum=256, step=4, value=32, elem_id="img2img_inpaint_full_res_padding") - - def select_img2img_tab(tab): - return gr.update(visible=tab in [2, 3, 4]), gr.update(visible=tab == 3) - - for i, elem in enumerate(img2img_tabs): - elem.select( - fn=lambda tab=i: select_img2img_tab(tab), # pylint: disable=cell-var-from-loop - inputs=[], - outputs=[inpaint_controls, mask_alpha], + on_change_args = dict( + fn=resize_from_to_html, + _js="currentImg2imgSourceResolution", + inputs=[dummy_component, dummy_component, scale_by], + outputs=scale_by_html, + show_progress=False, ) + scale_by.release(**on_change_args) + button_update_resize_to.click(**on_change_args) + + # the code below is meant to update the resolution label after the image in the image selection UI has changed. + # as it is now the event keeps firing continuously for inpaint edits, which ruins the page with constant requests. + # I assume this must be a gradio bug and for now we'll just do it for non-inpaint inputs. + for component in [init_img, sketch]: + component.change(fn=lambda: None, _js="updateImg2imgResizeToTextAfterChangingImage", inputs=[], outputs=[], show_progress=False) + + tab_scale_to.select(fn=lambda: 0, inputs=[], outputs=[selected_scale_tab]) + tab_scale_by.select(fn=lambda: 1, inputs=[], outputs=[selected_scale_tab]) + + with FormGroup(visible=show_batch.value, elem_id=f"{tab}_resize_group") as batch_group: + with FormRow(elem_id="img2img_column_batch"): + batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count") + batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="img2img_batch_size") + + seed_group, seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = create_seed_inputs('img2img', show_seed.value) + + with FormGroup(visible=show_denoise.value, elem_id=f"{tab}_denoise_group") as denoise_group: + with FormRow(): + denoising_strength = gr.Slider(minimum=0.05, maximum=1.0, step=0.01, label='Denoising strength', value=0.75, elem_id="img2img_denoising_strength") + refiner_denoise_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise start', value=0.0, elem_id="txt2img_refiner_denoise_start") + refiner_denoise_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise end', value=1.0, elem_id="txt2img_refiner_denoise_end") + + with FormGroup(visible=show_advanced.value, elem_id=f"{tab}_advanced_group") as advanced_group: + with FormRow(): + cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=6.0, elem_id="img2img_cfg_scale") + image_cfg_scale = gr.Slider(minimum=0, maximum=30.0, step=0.05, label='Image CFG Scale', value=1.5, elem_id="img2img_image_cfg_scale") + with FormRow(): + clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=1, maximum=4, step=1, elem_id='img2img_clip_skip', interactive=True) + diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance Rescale', value=0.7, elem_id="txt2img_image_cfg_rescale") + with FormRow(elem_classes="img2img_checkboxes_row", variant="compact"): + restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(modules.shared.face_restorers) > 1, elem_id="img2img_restore_faces") + tiling = gr.Checkbox(label='Tiling', value=False, elem_id="img2img_tiling") + + with FormRow(elem_id="img2img_override_settings_row") as row: + override_settings = create_override_settings_dropdown('img2img', row) + + with FormGroup(elem_id="img2img_script_container"): + custom_inputs = modules.scripts.scripts_img2img.setup_ui() + + with FormGroup(elem_id="inpaint_controls", visible=False) as inpaint_controls: + with FormRow(): + mask_blur = gr.Slider(label='Mask blur', minimum=0, maximum=64, step=1, value=4, elem_id="img2img_mask_blur") + mask_alpha = gr.Slider(label="Mask transparency", visible=False, elem_id="img2img_mask_alpha") + + with FormRow(): + inpainting_mask_invert = gr.Radio(label='Mask mode', choices=['Inpaint masked', 'Inpaint not masked'], value='Inpaint masked', type="index", elem_id="img2img_mask_mode") + + with FormRow(): + inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='original', type="index", elem_id="img2img_inpainting_fill") + + with FormRow(): + with gr.Column(): + inpaint_full_res = gr.Radio(label="Inpaint area", choices=["Whole picture", "Only masked"], type="index", value="Whole picture", elem_id="img2img_inpaint_full_res") + + with gr.Column(scale=4): + inpaint_full_res_padding = gr.Slider(label='Only masked padding, pixels', minimum=0, maximum=256, step=4, value=32, elem_id="img2img_inpaint_full_res_padding") + + def select_img2img_tab(tab): + return gr.update(visible=tab in [2, 3, 4]), gr.update(visible=tab == 3) + + for i, elem in enumerate(img2img_tabs): + elem.select(fn=lambda tab=i: select_img2img_tab(tab), inputs=[], outputs=[inpaint_controls, mask_alpha]) # pylint: disable=cell-var-from-loop + img2img_gallery, generation_info, html_info, _html_info_formatted, html_log = ui_common.create_output_panel("img2img", opts.outdir_img2img_samples) connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False) @@ -773,6 +755,8 @@ def create_ui(startup_timer = None): ], show_progress=False, ) + img2img_prompt.submit(**img2img_args) + submit.click(**img2img_args) interrogate_args = dict( _js="get_img2img_tab_index", @@ -789,10 +773,15 @@ def create_ui(startup_timer = None): ], outputs=[img2img_prompt, dummy_component], ) + img2img_interrogate.click(fn=lambda *args: process_interrogate(interrogate, *args), **interrogate_args) + img2img_deepbooru.click(fn=lambda *args: process_interrogate(interrogate_deepbooru, *args), **interrogate_args) - img2img_prompt.submit(**img2img_args) - submit.click(**img2img_args) res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False) + show_seed.change(gr_show, inputs=[show_seed], outputs=[seed_group], show_progress = False) + show_resize.change(gr_show, inputs=[show_resize], outputs=[resize_group], show_progress = False) + show_batch.change(gr_show, inputs=[show_batch], outputs=[batch_group], show_progress = False) + show_denoise.change(gr_show, inputs=[show_denoise], outputs=[denoise_group], show_progress = False) + show_advanced.change(gr_show, inputs=[show_advanced], outputs=[advanced_group], show_progress = False) detect_image_size_btn.click( fn=lambda w, h, _: (w or gr.update(), h or gr.update()), @@ -802,16 +791,6 @@ def create_ui(startup_timer = None): show_progress=False, ) - img2img_interrogate.click( - fn=lambda *args: process_interrogate(interrogate, *args), - **interrogate_args, - ) - - img2img_deepbooru.click( - fn=lambda *args: process_interrogate(interrogate_deepbooru, *args), - **interrogate_args, - ) - prompts = [(txt2img_prompt, txt2img_negative_prompt), (img2img_prompt, img2img_negative_prompt)] style_dropdowns = [txt2img_prompt_styles, img2img_prompt_styles] style_js_funcs = ["update_txt2img_tokens", "update_img2img_tokens"] diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 3f7c3d09f..9372f2397 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -207,33 +207,38 @@ class ExtraNetworksPage: return [] def create_html_for_item(self, item, tabname): - args = { - "preview": html.escape(item.get("preview", None)), - "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 ""), - "search_term": item.get("search_term", ""), - "loading": "lazy" if shared.opts.extra_networks_card_lazy else "eager", - "card_click": item.get("onclick", '"' + html.escape(f"""return cardClicked({item.get("prompt", None)}, {"true" if self.allow_negative_prompt else "false"})""") + '"'), - "card_read_desc": '"' + html.escape(f"""return readCardDescription(event, {json.dumps(item["local_preview"])}, {json.dumps(item.get("description", ""))})""") + '"', - "card_save_desc": '"' + html.escape(f"""return saveCardDescription(event, {json.dumps(item["local_preview"])})""") + '"', - "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_read_tags": '"' + html.escape(f"""return readCardTags(event, {json.dumps(self.name)}, {json.dumps(list(item.get("tags", {}).keys()))})""") + '"', - "card_save_preview": '"' + html.escape(f"""return saveCardPreview(event, {json.dumps(item["local_preview"])})""") + '"', - "title": f'Name: {item["name"]}', - } - if item.get("alias", None) is not None: - args['title'] += f'\nAlias: {item["alias"]}' - if item.get("tags", None) is not None: - args['title'] += f'\nTags: {", ".join(item.get("tags", {}).keys())}' - self.card.format(**args) - return self.card.format(**args) + try: + tags = [item.get("tags")] if isinstance(item.get("tags", {}), str) else list(item.get("tags", {}).keys()) + args = { + "preview": html.escape(item.get("preview", None)), + "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 ""), + "search_term": item.get("search_term", ""), + "loading": "lazy" if shared.opts.extra_networks_card_lazy else "eager", + "card_click": item.get("onclick", '"' + html.escape(f"""return cardClicked({item.get("prompt", None)}, {"true" if self.allow_negative_prompt else "false"})""") + '"'), + "card_read_desc": '"' + html.escape(f"""return readCardDescription(event, {json.dumps(item["local_preview"])}, {json.dumps(item.get("description", ""))})""") + '"', + "card_save_desc": '"' + html.escape(f"""return saveCardDescription(event, {json.dumps(item["local_preview"])})""") + '"', + "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_read_tags": '"' + html.escape(f"""return readCardTags(event, {json.dumps(self.name)}, {json.dumps(tags)})""") + '"', + "card_save_preview": '"' + html.escape(f"""return saveCardPreview(event, {json.dumps(item["local_preview"])})""") + '"', + "title": f'Name: {item["name"]}', + } + if item.get("alias", None) is not None: + args['title'] += f'\nAlias: {item["alias"]}' + if item.get("tags", None) is not None: + args['title'] += f'\nTags: {", ".join(tags)}' + self.card.format(**args) + return self.card.format(**args) + except Exception as e: + shared.log.error(f'Extra networks item error: page={tabname} item={item["name"]} {e}') + return "" def find_preview(self, path): preview_extensions = ["jpg", "jpeg", "png", "webp", "tiff", "jp2"] diff --git a/requirements.txt b/requirements.txt index 6d6673631..841cde46c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -43,7 +43,6 @@ scikit-image basicsr compel fasteners -pyarrow==11.0.0 typing-extensions==4.7.1 antlr4-python3-runtime==4.9.3 requests==2.31.0 @@ -59,7 +58,7 @@ numba==0.57.0 pandas==1.5.3 protobuf==3.20.3 pytorch_lightning==1.9.4 -transformers==4.30.2 +transformers==4.31.0 tomesd==0.1.3 urllib3==1.26.15 Pillow==9.5.0