diff --git a/modules/ui.py b/modules/ui.py index d9b13122..c18a09e2 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -2,83 +2,74 @@ import datetime import mimetypes import os import sys -from functools import reduce import warnings from contextlib import ExitStack +from functools import reduce import gradio as gr import gradio.utils -from gradio.components.image_editor import Brush from PIL import Image, PngImagePlugin # noqa: F401 -from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call, wrap_gradio_call_no_job # noqa: F401 - -from modules import gradio_extensions, sd_schedulers # noqa: F401 -from modules import sd_hijack, sd_models, script_callbacks, paths_internal, ui_extensions, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, shared_items, ui_settings, timer, sysinfo, ui_checkpoint_merger, scripts, sd_samplers, processing, ui_extra_networks, ui_toprow, launch_utils -from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML, InputAccordion, ResizeHandleRow -from modules.paths import script_path -from modules.ui_common import create_refresh_button -from modules.ui_gradio_extensions import reload_javascript - -from modules.shared import opts, cmd_opts import modules.infotext_utils as parameters_copypaste -import modules.shared as shared -from modules import prompt_parser -from modules.infotext_utils import image_from_url_text, PasteField -from modules_forge.forge_canvas.canvas import ForgeCanvas, canvas_head -from modules_forge import main_entry import modules.processing_scripts.comments as comments - +import modules.shared as shared +from modules import extra_networks, gradio_extensions, launch_utils, paths_internal, processing, progress, prompt_parser, script_callbacks, scripts, sd_hijack, sd_models, sd_samplers, sd_schedulers, shared_items, sysinfo, timer, ui_checkpoint_merger, ui_common, ui_extensions, ui_extra_networks, ui_loadsave, ui_postprocessing, ui_settings, ui_toprow # noqa: F401 +from modules.call_queue import wrap_gradio_call, wrap_gradio_call_no_job, wrap_gradio_gpu_call, wrap_queued_call # noqa: F401 +from modules.infotext_utils import PasteField, image_from_url_text +from modules.paths import script_path +from modules.shared import cmd_opts, opts +from modules.ui_common import create_refresh_button # noqa: F401 +from modules.ui_components import FormGroup, FormHTML, FormRow, InputAccordion, ResizeHandleRow, ToolButton +from modules.ui_gradio_extensions import reload_javascript +from modules_forge import main_entry +from modules_forge.forge_canvas.canvas import ForgeCanvas, canvas_head create_setting_component = ui_settings.create_setting_component -warnings.filterwarnings("default" if opts.show_warnings else "ignore", category=UserWarning) -warnings.filterwarnings("default" if opts.show_gradio_deprecation_warnings else "ignore", category=gradio_extensions.GradioDeprecationWarning) +if not opts.show_warnings: + warnings.filterwarnings("ignore", category=UserWarning) + warnings.filterwarnings("ignore", category=FutureWarning) +if not opts.show_gradio_deprecation_warnings: + warnings.filterwarnings("ignore", category=gradio_extensions.GradioDeprecationWarning) # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the browser will not show any UI mimetypes.init() -mimetypes.add_type('application/javascript', '.js') -mimetypes.add_type('application/javascript', '.mjs') +mimetypes.add_type("application/javascript", ".js") +mimetypes.add_type("application/javascript", ".mjs") # Likewise, add explicit content-type header for certain missing image types -mimetypes.add_type('image/webp', '.webp') -mimetypes.add_type('image/avif', '.avif') +mimetypes.add_type("image/webp", ".webp") +mimetypes.add_type("image/avif", ".avif") if not cmd_opts.share and not cmd_opts.listen: # fix gradio phoning home gradio.utils.version_check = lambda: None - gradio.utils.get_local_ip_address = lambda: '127.0.0.1' + gradio.utils.get_local_ip_address = lambda: "127.0.0.1" if cmd_opts.ngrok is not None: import modules.ngrok as ngrok - print('ngrok authtoken detected, trying to connect...') - ngrok.connect( - cmd_opts.ngrok, - cmd_opts.port if cmd_opts.port is not None else 7860, - cmd_opts.ngrok_options - ) + + print("ngrok authtoken detected, trying to connect...") + ngrok.connect(cmd_opts.ngrok, cmd_opts.port if cmd_opts.port is not None else 7860, cmd_opts.ngrok_options) def gr_show(visible=True): return {"visible": visible, "__type__": "update"} -sample_img2img = "assets/stable-samples/img2img/sketch-mountains-input.jpg" -sample_img2img = sample_img2img if os.path.exists(sample_img2img) else None - # Using constants for these since the variation selector isn't visible. # Important that they exactly match script.js for tooltip to work. -random_symbol = '\U0001f3b2\ufe0f' # 🎲️ -reuse_symbol = '\u267b\ufe0f' # ♻️ -paste_symbol = '\u2199\ufe0f' # ↙ -refresh_symbol = '\U0001f504' # 🔄 -save_style_symbol = '\U0001f4be' # 💾 -apply_style_symbol = '\U0001f4cb' # 📋 -clear_prompt_symbol = '\U0001f5d1\ufe0f' # 🗑️ -extra_networks_symbol = '\U0001F3B4' # 🎴 -switch_values_symbol = '\U000021C5' # ⇅ -restore_progress_symbol = '\U0001F300' # 🌀 -detect_image_size_symbol = '\U0001F4D0' # 📐 +random_symbol = "\U0001f3b2\ufe0f" # 🎲️ +reuse_symbol = "\u267b\ufe0f" # ♻️ +paste_symbol = "\u2199\ufe0f" # ↙ +refresh_symbol = "\U0001f504" # 🔄 +save_style_symbol = "\U0001f4be" # 💾 +apply_style_symbol = "\U0001f4cb" # 📋 +clear_prompt_symbol = "\U0001f5d1\ufe0f" # 🗑️ +extra_networks_symbol = "\U0001f3b4" # 🎴 +switch_values_symbol = "\U000021c5" # ⇅ +restore_progress_symbol = "\U0001f300" # 🌀 +detect_image_size_symbol = "\U0001f4d0" # 📐 plaintext_to_html = ui_common.plaintext_to_html @@ -100,7 +91,7 @@ def calc_resolution_hires(enable, width, height, hr_scale, hr_resize_x, hr_resiz new_width = p.hr_resize_x or p.hr_upscale_to_x new_height = p.hr_resize_y or p.hr_upscale_to_y - new_width -= new_width % 8 # note: hardcoded latent size 8 + new_width -= new_width % 8 # note: hardcoded latent size 8 new_height -= new_height % 8 return f"from {p.width}x{p.height} to {new_width}x{new_height}" @@ -113,22 +104,12 @@ def resize_from_to_html(width, height, scale_by): if not target_width or not target_height: return "no image selected" - target_width -= target_width % 8 # note: hardcoded latent size 8 + target_width -= target_width % 8 # note: hardcoded latent size 8 target_height -= target_height % 8 return f"resize: from {width}x{height} to {target_width}x{target_height}" -def connect_clear_prompt(button): - """Given clear button, prompt, and token_counter objects, setup clear prompt button click event""" - button.click( - _js="clear_prompt", - fn=None, - inputs=[], - outputs=[], - ) - - def update_token_counter(text, steps, styles, *, is_positive=True): params = script_callbacks.BeforeTokenCounterParams(text, steps, styles, is_positive=is_positive) script_callbacks.before_token_counter_callback(params) @@ -164,7 +145,7 @@ def update_token_counter(text, steps, styles, *, is_positive=True): except Exception: return f"?/?" - flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules) + flat_prompts = reduce(lambda list1, list2: list1 + list2, prompt_schedules) prompts = [prompt_text for step, prompt_text in flat_prompts] token_count, max_length = max([get_prompt_lengths_on_ui(prompt) for prompt in prompts], key=lambda args: args[0]) return f"{token_count}/{max_length}" @@ -174,10 +155,6 @@ def update_negative_prompt_token_counter(*args): return update_token_counter(*args, is_positive=False) -def setup_progressbar(*args, **kwargs): - pass - - def apply_setting(key, value): if value is None: return gr.update() @@ -198,7 +175,7 @@ def apply_setting(key, value): return gr.update() comp_args = opts.data_labels[key].component_args - if comp_args and isinstance(comp_args, dict) and comp_args.get('visible') is False: + if comp_args and isinstance(comp_args, dict) and comp_args.get("visible") is False: return valtype = type(opts.data_labels[key].default) @@ -261,7 +238,7 @@ def create_ui(): with ExitStack() as stack: if shared.opts.txt2img_settings_accordion: stack.enter_context(gr.Accordion("Open for Settings", open=False)) - stack.enter_context(gr.Column(variant='compact', elem_id="txt2img_settings")) + stack.enter_context(gr.Column(variant="compact", elem_id="txt2img_settings")) scripts.scripts_txt2img.prepare_ui() @@ -280,20 +257,16 @@ def create_ui(): if opts.dimensions_and_batch_together: with gr.Column(elem_id="txt2img_column_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=8, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size") + 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=8, step=1, label="Batch size", value=1, elem_id="txt2img_batch_size") elif category == "cfg": with gr.Row(): - distilled_cfg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='Distilled CFG Scale', value=3.5, elem_id="txt2img_distilled_cfg_scale", scale=4) - cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='CFG Scale', value=7.0, elem_id="txt2img_cfg_scale", scale=4) + distilled_cfg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label="Distilled CFG Scale", value=3.5, elem_id="txt2img_distilled_cfg_scale", scale=4) + cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label="CFG Scale", value=7.0, elem_id="txt2img_cfg_scale", scale=4) cfg_scale.change(lambda x: gr.update(interactive=(x != 1)), inputs=[cfg_scale], outputs=[toprow.negative_prompt], queue=False, show_progress=False) scripts.scripts_txt2img.setup_ui_for_section(category) - # elif category == "checkboxes": - # with FormRow(elem_classes="checkboxes-row", variant="compact"): - # pass - elif category == "accordions": with gr.Row(elem_id="txt2img_accordions", elem_classes="accordions"): with InputAccordion(False, label="Hires. fix", elem_id="txt2img_hr") as enable_hr: @@ -302,8 +275,8 @@ def create_ui(): with FormRow(elem_id="txt2img_hires_fix_row1", variant="compact"): hr_upscaler = gr.Dropdown(label="Upscaler", elem_id="txt2img_hr_upscaler", choices=[*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]], value=shared.latent_upscale_default_mode) - hr_second_pass_steps = gr.Slider(minimum=0, maximum=150, step=1, label='Hires steps', value=0, elem_id="txt2img_hires_steps") - denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7, elem_id="txt2img_denoising_strength") + hr_second_pass_steps = gr.Slider(minimum=0, maximum=150, step=1, label="Hires steps", value=0, elem_id="txt2img_hires_steps") + denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label="Denoising strength", value=0.7, elem_id="txt2img_denoising_strength") with FormRow(elem_id="txt2img_hires_fix_row2", variant="compact"): hr_scale = gr.Slider(minimum=1.0, maximum=4.0, step=0.05, label="Upscale by", value=2.0, elem_id="txt2img_hr_scale") @@ -315,12 +288,12 @@ def create_ui(): hr_cfg = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label="Hires CFG Scale", value=7.0, elem_id="txt2img_hr_cfg") with FormRow(elem_id="txt2img_hires_fix_row3", variant="compact", visible=shared.opts.hires_fix_show_sampler) as hr_checkpoint_container: - hr_checkpoint_name = gr.Dropdown(label='Hires Checkpoint', elem_id="hr_checkpoint", choices=["Use same checkpoint"] + modules.sd_models.checkpoint_tiles(use_short=True), value="Use same checkpoint", scale=2) + hr_checkpoint_name = gr.Dropdown(label="Hires Checkpoint", elem_id="hr_checkpoint", choices=["Use same checkpoint"] + modules.sd_models.checkpoint_tiles(use_short=True), value="Use same checkpoint", scale=2) hr_checkpoint_refresh = ToolButton(value=refresh_symbol) def get_additional_modules(): - modules_list = ['Use same choices'] + modules_list = ["Use same choices"] if main_entry.module_list == {}: _, modules = main_entry.refresh_models() modules_list += list(modules) @@ -334,13 +307,13 @@ def create_ui(): modules_list = get_additional_modules() return gr.update(choices=["Use same checkpoint"] + modules.sd_models.checkpoint_tiles(use_short=True)), gr.update(choices=modules_list) - hr_additional_modules = gr.Dropdown(label='Hires VAE / Text Encoder', elem_id="hr_vae_te", choices=modules_list, value=["Use same choices"], multiselect=True, scale=3) + hr_additional_modules = gr.Dropdown(label="Hires VAE / Text Encoder", elem_id="hr_vae_te", choices=modules_list, value=["Use same choices"], multiselect=True, scale=3) hr_checkpoint_refresh.click(fn=refresh_model_and_modules, outputs=[hr_checkpoint_name, hr_additional_modules], show_progress=False) with FormRow(elem_id="txt2img_hires_fix_row3b", variant="compact", visible=shared.opts.hires_fix_show_sampler) as hr_sampler_container: - hr_sampler_name = gr.Dropdown(label='Hires sampling method', elem_id="hr_sampler", choices=["Use same sampler"] + sd_samplers.visible_sampler_names(), value="Use same sampler") - hr_scheduler = gr.Dropdown(label='Hires schedule type', elem_id="hr_scheduler", choices=["Use same scheduler"] + [x.label for x in sd_schedulers.schedulers], value="Use same scheduler") + hr_sampler_name = gr.Dropdown(label="Hires sampling method", elem_id="hr_sampler", choices=["Use same sampler"] + sd_samplers.visible_sampler_names(), value="Use same sampler") + hr_scheduler = gr.Dropdown(label="Hires schedule type", elem_id="hr_scheduler", choices=["Use same scheduler"] + [x.label for x in sd_schedulers.schedulers], value="Use same scheduler") with FormRow(elem_id="txt2img_hires_fix_row4", variant="compact", visible=shared.opts.hires_fix_show_prompts) as hr_prompts_container: with gr.Column(): @@ -355,12 +328,12 @@ def create_ui(): elif category == "batch": if not opts.dimensions_and_batch_together: with FormRow(elem_id="txt2img_column_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=8, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size") + 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=8, step=1, label="Batch size", value=1, elem_id="txt2img_batch_size") elif category == "override_settings": with FormRow(elem_id="txt2img_override_settings_row") as row: - override_settings = create_override_settings_dropdown('txt2img', row) + override_settings = create_override_settings_dropdown("txt2img", row) elif category == "scripts": with FormGroup(elem_id="txt2img_script_container"): @@ -384,7 +357,6 @@ def create_ui(): None, _js="onCalcResolutionHires", inputs=hr_resolution_preview_inputs, - outputs=[], show_progress=False, ) @@ -440,7 +412,7 @@ def create_ui(): def select_gallery_image(index): index = int(index) - if getattr(shared.opts, 'hires_button_gallery_insert', False): + if getattr(shared.opts, "hires_button_gallery_insert", False): index += 1 return gr.update(selected_index=index) @@ -499,21 +471,26 @@ def create_ui(): PasteField(hr_cfg, "Hires CFG Scale", api="hr_cfg"), PasteField(hr_distilled_cfg, "Hires Distilled CFG Scale", api="hr_distilled_cfg"), PasteField(hr_prompts_container, lambda d: gr.update(visible=True) if d.get("Hires prompt", "") != "" or d.get("Hires negative prompt", "") != "" else gr.update()), - *scripts.scripts_txt2img.infotext_fields + *scripts.scripts_txt2img.infotext_fields, ] parameters_copypaste.add_paste_fields("txt2img", None, txt2img_paste_fields, override_settings) - parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding( - paste_button=toprow.paste, tabname="txt2img", source_text_component=toprow.prompt, source_image_component=None, - )) + parameters_copypaste.register_paste_params_button( + parameters_copypaste.ParamBinding( + paste_button=toprow.paste, + tabname="txt2img", + source_text_component=toprow.prompt, + source_image_component=None, + ) + ) - steps = scripts.scripts_txt2img.script('Sampler').steps + steps = scripts.scripts_txt2img.script("Sampler").steps toprow.ui_styles.dropdown.change(fn=wrap_queued_call(update_token_counter), inputs=[toprow.prompt, steps, toprow.ui_styles.dropdown], outputs=[toprow.token_counter]) toprow.ui_styles.dropdown.change(fn=wrap_queued_call(update_negative_prompt_token_counter), inputs=[toprow.negative_prompt, steps, toprow.ui_styles.dropdown], outputs=[toprow.negative_token_counter]) toprow.token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[toprow.prompt, steps, toprow.ui_styles.dropdown], outputs=[toprow.token_counter]) toprow.negative_token_button.click(fn=wrap_queued_call(update_negative_prompt_token_counter), inputs=[toprow.negative_prompt, steps, toprow.ui_styles.dropdown], outputs=[toprow.negative_token_counter]) - extra_networks_ui = ui_extra_networks.create_ui(txt2img_interface, [txt2img_generation_tab], 'txt2img') + extra_networks_ui = ui_extra_networks.create_ui(txt2img_interface, [txt2img_generation_tab], "txt2img") ui_extra_networks.setup_ui(extra_networks_ui, output_panel.gallery) extra_tabs.__exit__() @@ -534,14 +511,14 @@ def create_ui(): with ExitStack() as stack: if shared.opts.img2img_settings_accordion: stack.enter_context(gr.Accordion("Open for Settings", open=False)) - stack.enter_context(gr.Column(variant='compact', elem_id="img2img_settings")) + stack.enter_context(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(['to img2img', 'to sketch', 'to inpaint', 'to inpaint sketch'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']): + for title, name in zip(["to img2img", "to sketch", "to inpaint", "to inpaint sketch"], ["img2img", "sketch", "inpaint", "inpaint_sketch"]): if name == tab_name: gr.Button(title, interactive=False) copy_image_destinations[name] = elem @@ -560,44 +537,39 @@ def create_ui(): with gr.Tabs(elem_id="mode_img2img"): img2img_selected_tab = gr.Number(value=0, visible=False) - with gr.TabItem('img2img', id='img2img', elem_id="img2img_img2img_tab") as tab_img2img: + with gr.TabItem("img2img", id="img2img", elem_id="img2img_img2img_tab") as tab_img2img: init_img = ForgeCanvas(elem_id="img2img_image", height=512, no_scribbles=True) - add_copy_image_controls('img2img', init_img) + add_copy_image_controls("img2img", init_img) - with gr.TabItem('Sketch', id='img2img_sketch', elem_id="img2img_img2img_sketch_tab") as tab_sketch: + with gr.TabItem("Sketch", id="img2img_sketch", elem_id="img2img_img2img_sketch_tab") as tab_sketch: sketch = ForgeCanvas(elem_id="img2img_sketch", height=512, scribble_color=opts.img2img_sketch_default_brush_color) - add_copy_image_controls('sketch', sketch) + add_copy_image_controls("sketch", sketch) - with gr.TabItem('Inpaint', id='inpaint', elem_id="img2img_inpaint_tab") as tab_inpaint: + with gr.TabItem("Inpaint", id="inpaint", elem_id="img2img_inpaint_tab") as tab_inpaint: init_img_with_mask = ForgeCanvas(elem_id="img2maskimg", height=512, contrast_scribbles=opts.img2img_inpaint_mask_high_contrast, scribble_color=opts.img2img_inpaint_mask_brush_color, scribble_color_fixed=True, scribble_alpha=opts.img2img_inpaint_mask_scribble_alpha, scribble_alpha_fixed=True, scribble_softness_fixed=True) - add_copy_image_controls('inpaint', init_img_with_mask) + add_copy_image_controls("inpaint", init_img_with_mask) - with gr.TabItem('Inpaint sketch', id='inpaint_sketch', elem_id="img2img_inpaint_sketch_tab") as tab_inpaint_color: + with gr.TabItem("Inpaint sketch", id="inpaint_sketch", elem_id="img2img_inpaint_sketch_tab") as tab_inpaint_color: inpaint_color_sketch = ForgeCanvas(elem_id="inpaint_sketch", height=512, scribble_color=opts.img2img_inpaint_sketch_default_brush_color) - add_copy_image_controls('inpaint_sketch', inpaint_color_sketch) + add_copy_image_controls("inpaint_sketch", inpaint_color_sketch) - with gr.TabItem('Inpaint upload', id='inpaint_upload', elem_id="img2img_inpaint_upload_tab") as tab_inpaint_upload: + with gr.TabItem("Inpaint upload", id="inpaint_upload", elem_id="img2img_inpaint_upload_tab") as tab_inpaint_upload: init_img_inpaint = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil", elem_id="img_inpaint_base") init_mask_inpaint = gr.Image(label="Mask", source="upload", interactive=True, type="pil", image_mode="RGBA", elem_id="img_inpaint_mask") - with gr.TabItem('Batch', id='batch', elem_id="img2img_batch_tab") as tab_batch: + with gr.TabItem("Batch", id="batch", elem_id="img2img_batch_tab") as tab_batch: with gr.Tabs(elem_id="img2img_batch_source"): img2img_batch_source_type = gr.Textbox(visible=False, value="upload") - with gr.TabItem('Upload', id='batch_upload', elem_id="img2img_batch_upload_tab") as tab_batch_upload: + with gr.TabItem("Upload", id="batch_upload", elem_id="img2img_batch_upload_tab") as tab_batch_upload: img2img_batch_upload = gr.Files(label="Files", interactive=True, elem_id="img2img_batch_upload") - with gr.TabItem('From directory', id='batch_from_dir', elem_id="img2img_batch_from_dir_tab") as tab_batch_from_dir: - hidden = '
Disabled when launched with --hide-ui-dir-config.' if shared.cmd_opts.hide_ui_dir_config else '' - gr.HTML( - "

Process images in a directory on the same machine where the server is running." + - "
Use an empty output directory to save pictures normally instead of writing to the output directory." + - f"
Add inpaint batch mask directory to enable inpaint batch processing." - f"{hidden}

" - ) + with gr.TabItem("From directory", id="batch_from_dir", elem_id="img2img_batch_from_dir_tab") as tab_batch_from_dir: + hidden = "
Disabled when launched with --hide-ui-dir-config." if shared.cmd_opts.hide_ui_dir_config else "" + gr.HTML("

Process images in a directory on the same machine where the server is running." + "
Use an empty output directory to save pictures normally instead of writing to the output directory." + f"
Add inpaint batch mask directory to enable inpaint batch processing." f"{hidden}

") img2img_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs, elem_id="img2img_batch_input_dir") img2img_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs, elem_id="img2img_batch_output_dir") img2img_batch_inpaint_mask_dir = gr.Textbox(label="Inpaint batch mask directory (required for inpaint batch processing only)", **shared.hide_dirs, elem_id="img2img_batch_inpaint_mask_dir") - tab_batch_upload.select(fn=lambda: "upload", inputs=[], outputs=[img2img_batch_source_type]) - tab_batch_from_dir.select(fn=lambda: "from dir", inputs=[], outputs=[img2img_batch_source_type]) + tab_batch_upload.select(fn=lambda: "upload", outputs=[img2img_batch_source_type]) + tab_batch_from_dir.select(fn=lambda: "from dir", outputs=[img2img_batch_source_type]) with gr.Accordion("PNG info", open=False): img2img_batch_use_png_info = gr.Checkbox(label="Append png info to prompts", elem_id="img2img_batch_use_png_info") img2img_batch_png_info_dir = gr.Textbox(label="PNG info directory", **shared.hide_dirs, placeholder="Leave empty to use input directory", elem_id="img2img_batch_png_info_dir") @@ -606,10 +578,10 @@ def create_ui(): img2img_tabs = [tab_img2img, tab_sketch, tab_inpaint, tab_inpaint_color, tab_inpaint_upload, tab_batch] for i, tab in enumerate(img2img_tabs): - tab.select(fn=lambda tabnum=i: tabnum, inputs=[], outputs=[img2img_selected_tab]) + tab.select(fn=lambda tabnum=i: tabnum, outputs=[img2img_selected_tab]) - def copyCanvas_img2img (background, foreground, source): - if source == 1 or source == 3: # 1 is sketch, 3 is Inpaint sketch + def copyCanvas_img2img(background, foreground, source): + if source == 1 or source == 3: # 1 is sketch; 3 is Inpaint sketch bg = Image.alpha_composite(background, foreground) return bg, None return background, None @@ -623,8 +595,6 @@ def create_ui(): button.click( fn=None, _js=f"switch_to_{name.replace(' ', '_')}", - inputs=[], - outputs=[], ) with FormRow(): @@ -664,7 +634,7 @@ def create_ui(): scale_by.change(**on_change_args) button_update_resize_to.click(**on_change_args) - def updateWH (img, w, h): + def updateWH(img, w, h): if img and shared.opts.img2img_autosize == True: return img.size[0], img.size[1] else: @@ -672,32 +642,28 @@ def create_ui(): img_sources = [init_img.background, sketch.background, init_img_with_mask.background, inpaint_color_sketch.background, init_img_inpaint] for i in img_sources: - i.change(fn=updateWH, inputs=[i, width, height], outputs=[width, height], show_progress='hidden') + i.change(fn=updateWH, inputs=[i, width, height], outputs=[width, height], show_progress="hidden") i.change(**on_change_args) - tab_scale_to.select(fn=lambda: 0, inputs=[], outputs=[selected_scale_tab]) - tab_scale_by.select(fn=lambda: 1, inputs=[], outputs=[selected_scale_tab]) + tab_scale_to.select(fn=lambda: 0, outputs=[selected_scale_tab]) + tab_scale_by.select(fn=lambda: 1, outputs=[selected_scale_tab]) if opts.dimensions_and_batch_together: with gr.Column(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") + 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") elif category == "denoising": - denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.75, elem_id="img2img_denoising_strength") + denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label="Denoising strength", value=0.75, elem_id="img2img_denoising_strength") elif category == "cfg": with gr.Row(): - distilled_cfg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='Distilled CFG Scale', value=3.5, elem_id="img2img_distilled_cfg_scale", scale=4) - cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='CFG Scale', value=7.0, elem_id="img2img_cfg_scale", scale=4) - image_cfg_scale = gr.Slider(minimum=0, maximum=3.0, step=0.05, label='Image CFG Scale', value=1.5, elem_id="img2img_image_cfg_scale", visible=False) + distilled_cfg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label="Distilled CFG Scale", value=3.5, elem_id="img2img_distilled_cfg_scale", scale=4) + cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label="CFG Scale", value=7.0, elem_id="img2img_cfg_scale", scale=4) + image_cfg_scale = gr.Slider(minimum=0, maximum=3.0, step=0.05, label="Image CFG Scale", value=1.5, elem_id="img2img_image_cfg_scale", visible=False) cfg_scale.change(lambda x: gr.update(interactive=(x != 1)), inputs=[cfg_scale], outputs=[toprow.negative_prompt], queue=False, show_progress=False) scripts.scripts_img2img.setup_ui_for_section(category) - # elif category == "checkboxes": - # with FormRow(elem_classes="checkboxes-row", variant="compact"): - # pass - elif category == "accordions": with gr.Row(elem_id="img2img_accordions", elem_classes="accordions"): scripts.scripts_img2img.setup_ui_for_section(category) @@ -705,12 +671,12 @@ def create_ui(): elif category == "batch": if not opts.dimensions_and_batch_together: 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") + 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") elif category == "override_settings": with FormRow(elem_id="img2img_override_settings_row") as row: - override_settings = create_override_settings_dropdown('img2img', row) + override_settings = create_override_settings_dropdown("img2img", row) elif category == "scripts": with FormGroup(elem_id="img2img_script_container"): @@ -719,32 +685,34 @@ def create_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_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") + 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") + 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") + 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") if category not in {"accordions", "cfg"}: scripts.scripts_img2img.setup_ui_for_section(category) def select_img2img_tab(tab): - return gr.update(visible=tab in [2, 3, 4]), gr.update(visible=tab == 3), + 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], ) @@ -833,38 +801,26 @@ def create_ui(): show_progress=False, ) - steps = scripts.scripts_img2img.script('Sampler').steps + steps = scripts.scripts_img2img.script("Sampler").steps toprow.ui_styles.dropdown.change(fn=wrap_queued_call(update_token_counter), inputs=[toprow.prompt, steps, toprow.ui_styles.dropdown], outputs=[toprow.token_counter]) toprow.ui_styles.dropdown.change(fn=wrap_queued_call(update_negative_prompt_token_counter), inputs=[toprow.negative_prompt, steps, toprow.ui_styles.dropdown], outputs=[toprow.negative_token_counter]) toprow.token_button.click(fn=update_token_counter, inputs=[toprow.prompt, steps, toprow.ui_styles.dropdown], outputs=[toprow.token_counter]) toprow.negative_token_button.click(fn=wrap_queued_call(update_negative_prompt_token_counter), inputs=[toprow.negative_prompt, steps, toprow.ui_styles.dropdown], outputs=[toprow.negative_token_counter]) - img2img_paste_fields = [ - (toprow.prompt, "Prompt"), - (toprow.negative_prompt, "Negative prompt"), - (cfg_scale, "CFG scale"), - (distilled_cfg_scale, "Distilled CFG Scale"), - (image_cfg_scale, "Image CFG scale"), - (width, "Size-1"), - (height, "Size-2"), - (batch_size, "Batch size"), - (toprow.ui_styles.dropdown, lambda d: d["Styles array"] if isinstance(d.get("Styles array"), list) else gr.update()), - (denoising_strength, "Denoising strength"), - (mask_blur, "Mask blur"), - (inpainting_mask_invert, 'Mask mode'), - (inpainting_fill, 'Masked content'), - (inpaint_full_res, 'Inpaint area'), - (inpaint_full_res_padding, 'Masked area padding'), - *scripts.scripts_img2img.infotext_fields - ] + img2img_paste_fields = [(toprow.prompt, "Prompt"), (toprow.negative_prompt, "Negative prompt"), (cfg_scale, "CFG scale"), (distilled_cfg_scale, "Distilled CFG Scale"), (image_cfg_scale, "Image CFG scale"), (width, "Size-1"), (height, "Size-2"), (batch_size, "Batch size"), (toprow.ui_styles.dropdown, lambda d: d["Styles array"] if isinstance(d.get("Styles array"), list) else gr.update()), (denoising_strength, "Denoising strength"), (mask_blur, "Mask blur"), (inpainting_mask_invert, "Mask mode"), (inpainting_fill, "Masked content"), (inpaint_full_res, "Inpaint area"), (inpaint_full_res_padding, "Masked area padding"), *scripts.scripts_img2img.infotext_fields] parameters_copypaste.add_paste_fields("img2img", init_img.background, img2img_paste_fields, override_settings) parameters_copypaste.add_paste_fields("inpaint", init_img_with_mask.background, img2img_paste_fields, override_settings) - parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding( - paste_button=toprow.paste, tabname="img2img", source_text_component=toprow.prompt, source_image_component=None, - )) + parameters_copypaste.register_paste_params_button( + parameters_copypaste.ParamBinding( + paste_button=toprow.paste, + tabname="img2img", + source_text_component=toprow.prompt, + source_image_component=None, + ) + ) - extra_networks_ui_img2img = ui_extra_networks.create_ui(img2img_interface, [img2img_generation_tab], 'img2img') + extra_networks_ui_img2img = ui_extra_networks.create_ui(img2img_interface, [img2img_generation_tab], "img2img") ui_extra_networks.setup_ui(extra_networks_ui_img2img, output_panel.gallery) extra_tabs.__exit__() @@ -879,10 +835,10 @@ def create_ui(): with gr.Blocks(analytics_enabled=False) as pnginfo_interface: with ResizeHandleRow(equal_height=False): - with gr.Column(variant='panel'): + with gr.Column(variant="panel"): image = gr.Image(elem_id="pnginfo_image", label="Source", source="upload", interactive=True, type="pil", height="50vh", image_mode="RGBA") - with gr.Column(variant='panel'): + with gr.Column(variant="panel"): html = gr.HTML() generation_info = gr.Textbox(visible=False, elem_id="pnginfo_generation_info") html2 = gr.HTML() @@ -890,9 +846,14 @@ def create_ui(): buttons = parameters_copypaste.create_buttons(["txt2img", "img2img", "inpaint", "extras"]) for tabname, button in buttons.items(): - parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding( - paste_button=button, tabname=tabname, source_text_component=generation_info, source_image_component=image, - )) + parameters_copypaste.register_paste_params_button( + parameters_copypaste.ParamBinding( + paste_button=button, + tabname=tabname, + source_text_component=generation_info, + source_image_component=image, + ) + ) image.change( fn=wrap_gradio_call_no_job(modules.extras.run_pnginfo), @@ -908,8 +869,8 @@ def create_ui(): settings.create_ui(loadsave, dummy_component) interfaces = [ - (txt2img_interface, "Txt2img", "txt2img"), - (img2img_interface, "Img2img", "img2img"), + (txt2img_interface, "txt2img", "txt2img"), + (img2img_interface, "img2img", "img2img"), (extras_interface, "Extras", "extras"), (pnginfo_interface, "PNG Info", "pnginfo"), (modelmerger_ui.blocks, "Checkpoint Merger", "modelmerger"), @@ -926,7 +887,7 @@ def create_ui(): shared.tab_names.append(label) with gr.Blocks(theme=shared.gradio_theme, analytics_enabled=False, title="Stable Diffusion", head=canvas_head) as demo: - quicksettings_row = settings.add_quicksettings() + settings.add_quicksettings() parameters_copypaste.connect_paste_params_buttons() @@ -957,8 +918,8 @@ def create_ui(): settings.add_functionality(demo) update_image_cfg_scale_visibility = lambda: gr.update(visible=False) - settings.text_settings.change(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale]) - demo.load(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale]) + settings.text_settings.change(fn=update_image_cfg_scale_visibility, outputs=[image_cfg_scale]) + demo.load(fn=update_image_cfg_scale_visibility, outputs=[image_cfg_scale]) modelmerger_ui.setup_ui(dummy_component=dummy_component, sd_model_checkpoint_component=main_entry.ui_checkpoint) @@ -972,10 +933,12 @@ def create_ui(): def versions_html(): - from backend.memory_management import sage_enabled, flash_enabled, xformers_enabled import importlib.metadata + import torch + from backend.memory_management import flash_enabled, sage_enabled, xformers_enabled + python_version = ".".join([str(x) for x in sys.version_info[0:3]]) _versions = [f"torch: {getattr(torch, '__long_version__', torch.__version__)}"] @@ -1021,10 +984,11 @@ def setup_ui_api(app): text = sysinfo.get() filename = f"sysinfo-{datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d-%H-%M')}.json" - return PlainTextResponse(text, headers={'Content-Disposition': f'{"attachment" if attachment else "inline"}; filename="{filename}"'}) + return PlainTextResponse(text, headers={"Content-Disposition": f'{"attachment" if attachment else "inline"}; filename="{filename}"'}) app.add_api_route("/internal/sysinfo", download_sysinfo, methods=["GET"]) app.add_api_route("/internal/sysinfo-download", lambda: download_sysinfo(attachment=True), methods=["GET"]) import fastapi.staticfiles + app.mount("/webui-assets", fastapi.staticfiles.StaticFiles(directory=os.path.join(paths_internal.modules_path, "web")), name="webui-assets")