From c9a29b91c1b18ec6b50db3e0757f044f0ac917ee Mon Sep 17 00:00:00 2001 From: one-lithe-rune Date: Wed, 6 Dec 2023 20:27:03 +0000 Subject: [PATCH] UI: Fixes for Gradio 4.7.1/4.8.0 update * Upgrade Gradio pin from 4.7.1 to 4.80. * Make Nod AI logos visible again. * Remove image toolbars from png import boxes. * Set Input Images on img2img, outpaint and upscaler tabs to be upload only. * Change Image control to an ImageEditor control for masking on the inpaint tab. Remove previous height restriction as this hides the editing controls. * Move Input Image/Masked Image on img2img, inpaint, outpaint and upscaler tabs to be the first control on their tabs. * Remove download buttons from all galleries as they download some html rather the image (gradio issue #6595) * Remove add new row and column from Output Gallery parameters dataframe. * Add partial workaround for not being able to select text in the Output Gallery Gallery parameters dataframe (gradio issue #6086 ) * Fix uglified formatting of subdirectory selection dropown, refresh button, and open folder buttons on the Output Gallery tab. * Force Output Gallery to use the full width of the Gallery control for the preview overlay when an image is selected, rather than an overlay the width of the selected image. * Fix sendto buttons. --- apps/stable_diffusion/web/api/sdapi_v1.py | 2 +- apps/stable_diffusion/web/index.py | 85 +++++++++++++------ .../web/ui/common_ui_events.py | 2 + .../web/ui/css/sd_dark_theme.css | 23 ++++- apps/stable_diffusion/web/ui/img2img_ui.py | 18 ++-- apps/stable_diffusion/web/ui/inpaint_ui.py | 25 +++--- apps/stable_diffusion/web/ui/lora_train_ui.py | 1 + apps/stable_diffusion/web/ui/model_manager.py | 1 + apps/stable_diffusion/web/ui/outpaint_ui.py | 13 ++- .../web/ui/outputgallery_ui.py | 24 ++++-- .../web/ui/txt2img_sdxl_ui.py | 20 +++-- apps/stable_diffusion/web/ui/txt2img_ui.py | 23 ++--- apps/stable_diffusion/web/ui/upscaler_ui.py | 15 ++-- dataset/annotation_tool.py | 1 + requirements.txt | 2 +- 15 files changed, 165 insertions(+), 90 deletions(-) diff --git a/apps/stable_diffusion/web/api/sdapi_v1.py b/apps/stable_diffusion/web/api/sdapi_v1.py index 3eebd5c113..3ef1f20126 100644 --- a/apps/stable_diffusion/web/api/sdapi_v1.py +++ b/apps/stable_diffusion/web/api/sdapi_v1.py @@ -374,7 +374,7 @@ def inpaint_api( res = inpaint_inf( InputData.prompt, InputData.negative_prompt, - {"image": init_image, "mask": mask}, + {"background": init_image, "layers": [mask]}, InputData.height, InputData.width, InputData.is_full_res, diff --git a/apps/stable_diffusion/web/index.py b/apps/stable_diffusion/web/index.py index f301d6d246..3cd67e201e 100644 --- a/apps/stable_diffusion/web/index.py +++ b/apps/stable_diffusion/web/index.py @@ -77,6 +77,7 @@ # It has to be in this order or gradio ignores what we've set up. from apps.stable_diffusion.web.utils.tmp_configs import ( config_tmp, + shark_tmp, ) config_tmp() @@ -177,10 +178,26 @@ def resource_path(relative_path): # init global sd pipeline and config global_obj._init() - def register_button_click(button, selectedid, inputs, outputs): + def register_sendto_click(button, selectedid, inputs, outputs): button.click( lambda x: ( - x[0]["name"] if len(x) != 0 else None, + x.root[0].image.path if len(x.root) != 0 else None, + gr.Tabs(selected=selectedid), + ), + inputs, + outputs, + ) + + def register_sendto_editor_click(button, selectedid, inputs, outputs): + button.click( + lambda x: ( + { + "background": x.root[0].image.path + if len(x.root) != 0 + else None, + "layers": [], + "composite": None, + }, gr.Tabs(selected=selectedid), ), inputs, @@ -198,7 +215,9 @@ def register_modelmanager_button(button, selectedid, inputs, outputs): outputs, ) - def register_outputgallery_button(button, selectedid, inputs, outputs): + def register_outputgallery_sendto_button( + button, selectedid, inputs, outputs + ): button.click( lambda x: ( x, @@ -208,6 +227,22 @@ def register_outputgallery_button(button, selectedid, inputs, outputs): outputs, ) + def register_outputgallery_sendto_editor_button( + button, selectedid, inputs, outputs + ): + button.click( + lambda x: ( + { + "background": x, + "layers": [], + "composite": None, + }, + gr.Tabs(selected=selectedid), + ), + inputs, + outputs, + ) + dark_theme = resource_path("ui/css/sd_dark_theme.css") with gr.Blocks( @@ -278,134 +313,134 @@ def register_outputgallery_button(button, selectedid, inputs, outputs): ) # send to buttons - register_button_click( + register_sendto_click( txt2img_sendto_img2img, 1, [txt2img_gallery], [img2img_init_image, tabs], ) - register_button_click( + register_sendto_editor_click( txt2img_sendto_inpaint, 2, [txt2img_gallery], [inpaint_init_image, tabs], ) - register_button_click( + register_sendto_click( txt2img_sendto_outpaint, 3, [txt2img_gallery], [outpaint_init_image, tabs], ) - register_button_click( + register_sendto_click( txt2img_sendto_upscaler, 4, [txt2img_gallery], [upscaler_init_image, tabs], ) - register_button_click( + register_sendto_editor_click( img2img_sendto_inpaint, 2, [img2img_gallery], [inpaint_init_image, tabs], ) - register_button_click( + register_sendto_click( img2img_sendto_outpaint, 3, [img2img_gallery], [outpaint_init_image, tabs], ) - register_button_click( + register_sendto_click( img2img_sendto_upscaler, 4, [img2img_gallery], [upscaler_init_image, tabs], ) - register_button_click( + register_sendto_click( inpaint_sendto_img2img, 1, [inpaint_gallery], [img2img_init_image, tabs], ) - register_button_click( + register_sendto_click( inpaint_sendto_outpaint, 3, [inpaint_gallery], [outpaint_init_image, tabs], ) - register_button_click( + register_sendto_click( inpaint_sendto_upscaler, 4, [inpaint_gallery], [upscaler_init_image, tabs], ) - register_button_click( + register_sendto_click( outpaint_sendto_img2img, 1, [outpaint_gallery], [img2img_init_image, tabs], ) - register_button_click( + register_sendto_editor_click( outpaint_sendto_inpaint, 2, [outpaint_gallery], [inpaint_init_image, tabs], ) - register_button_click( + register_sendto_click( outpaint_sendto_upscaler, 4, [outpaint_gallery], [upscaler_init_image, tabs], ) - register_button_click( + register_sendto_click( upscaler_sendto_img2img, 1, [upscaler_gallery], [img2img_init_image, tabs], ) - register_button_click( + register_sendto_editor_click( upscaler_sendto_inpaint, 2, [upscaler_gallery], [inpaint_init_image, tabs], ) - register_button_click( + register_sendto_click( upscaler_sendto_outpaint, 3, [upscaler_gallery], [outpaint_init_image, tabs], ) if args.output_gallery: - register_outputgallery_button( + register_outputgallery_sendto_button( outputgallery_sendto_txt2img, 0, [outputgallery_filename], [txt2img_png_info_img, tabs], ) - register_outputgallery_button( + register_outputgallery_sendto_button( outputgallery_sendto_img2img, 1, [outputgallery_filename], [img2img_init_image, tabs], ) - register_outputgallery_button( + register_outputgallery_sendto_editor_button( outputgallery_sendto_inpaint, 2, [outputgallery_filename], [inpaint_init_image, tabs], ) - register_outputgallery_button( + register_outputgallery_sendto_button( outputgallery_sendto_outpaint, 3, [outputgallery_filename], [outpaint_init_image, tabs], ) - register_outputgallery_button( + register_outputgallery_sendto_button( outputgallery_sendto_upscaler, 4, [outputgallery_filename], [upscaler_init_image, tabs], ) - register_outputgallery_button( + register_outputgallery_sendto_button( outputgallery_sendto_txt2img_sdxl, 0, [outputgallery_filename], diff --git a/apps/stable_diffusion/web/ui/common_ui_events.py b/apps/stable_diffusion/web/ui/common_ui_events.py index 230619b61d..f467f6b0ed 100644 --- a/apps/stable_diffusion/web/ui/common_ui_events.py +++ b/apps/stable_diffusion/web/ui/common_ui_events.py @@ -1,3 +1,5 @@ +import gradio as gr + from apps.stable_diffusion.web.ui.utils import ( HSLHue, hsl_color, diff --git a/apps/stable_diffusion/web/ui/css/sd_dark_theme.css b/apps/stable_diffusion/web/ui/css/sd_dark_theme.css index 5686f0868c..fa8d50adf2 100644 --- a/apps/stable_diffusion/web/ui/css/sd_dark_theme.css +++ b/apps/stable_diffusion/web/ui/css/sd_dark_theme.css @@ -239,8 +239,9 @@ footer { padding: 0 !important; } -#output_subdir_container :first-child { - border: none; +#output_subdir_container { + background-color: var(--block-background-fill); + padding-right: 8px; } /* reduced animation load when generating */ @@ -279,10 +280,19 @@ footer { /* output gallery tab */ .output_parameters_dataframe table.table { - /* works around a gradio bug that always shows scrollbars */ +/* works around a gradio bug that always shows scrollbars */ overflow: clip auto; } +.output_parameters_dataframe .cell-wrap span { + /* inadequate workaround for gradio issue #6086 */ + user-select:text !important; + -moz-user-select:text !important; + -webkit-user-select:text !important; + -o-user-select:text !important; + -ms-user-select:text !important; +} + .output_parameters_dataframe tbody td { font-size: small; line-height: var(--line-xs); @@ -291,7 +301,7 @@ footer { .output_icon_button { max-width: 30px; align-self: end; - padding-bottom: 8px; + padding-bottom: 16px !important; } .outputgallery_sendto { @@ -308,6 +318,11 @@ footer { object-fit: contain !important; } +/* use the whole gallery area for previeews */ +#outputgallery_gallery .preview { + width: inherit; +} + /* centered logo for when there are no images */ #top_logo.logo_centered { height: 100%; diff --git a/apps/stable_diffusion/web/ui/img2img_ui.py b/apps/stable_diffusion/web/ui/img2img_ui.py index f3522656e4..70c804ad8e 100644 --- a/apps/stable_diffusion/web/ui/img2img_ui.py +++ b/apps/stable_diffusion/web/ui/img2img_ui.py @@ -326,6 +326,7 @@ def img2img_inf( value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, @@ -334,6 +335,13 @@ def img2img_inf( with gr.Row(elem_id="ui_body"): with gr.Row(): with gr.Column(scale=1, min_width=600): + # TODO: make this import image prompt info if it exists + img2img_init_image = gr.Image( + label="Input Image", + type="pil", + interactive=True, + sources=["upload"], + ) with gr.Row(): # janky fix for overflowing text i2i_model_info = ( @@ -380,14 +388,6 @@ def img2img_inf( lines=2, elem_id="negative_prompt_box", ) - # TODO: make this import image prompt info if it exists - img2img_init_image = gr.Image( - label="Input Image", - type="pil", - height=300, - interactive=True, - ) - with gr.Accordion(label="Multistencil Options", open=False): choices = [ "None", @@ -958,6 +958,8 @@ def update_cn_input( elem_id="gallery", columns=2, object_fit="contain", + # TODO: Re-enable download when fixed in Gradio + show_download_button=False, ) std_output = gr.Textbox( value=f"{i2i_model_info}\n" diff --git a/apps/stable_diffusion/web/ui/inpaint_ui.py b/apps/stable_diffusion/web/ui/inpaint_ui.py index 8cd56f452b..1f85570eb9 100644 --- a/apps/stable_diffusion/web/ui/inpaint_ui.py +++ b/apps/stable_diffusion/web/ui/inpaint_ui.py @@ -175,8 +175,8 @@ def inpaint_inf( start_time = time.time() global_obj.get_sd_obj().log = "" generated_imgs = [] - image = image_dict["image"] - mask_image = image_dict["mask"] + image = image_dict["background"] + mask_image = image_dict["layers"][0] text_output = "" try: seeds = utils.batch_seeds(seed, batch_count, repeatable_seeds) @@ -231,6 +231,7 @@ def inpaint_inf( value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, @@ -239,6 +240,12 @@ def inpaint_inf( with gr.Row(elem_id="ui_body"): with gr.Row(): with gr.Column(scale=1, min_width=600): + inpaint_init_image = gr.ImageMask( + label="Masked Image", + sources="upload", + type="pil", + image_mode="L", + ) with gr.Row(): # janky fix for overflowing text inpaint_model_info = ( @@ -288,14 +295,6 @@ def inpaint_inf( lines=2, elem_id="negative_prompt_box", ) - - inpaint_init_image = gr.Image( - label="Masked Image", - sources="upload", - type="pil", - height=350, - ) - with gr.Accordion(label="LoRA Options", open=False): with gr.Row(): # janky fix for overflowing text @@ -448,6 +447,8 @@ def inpaint_inf( elem_id="gallery", columns=[2], object_fit="contain", + # TODO: Re-enable download when fixed in Gradio + show_download_button=False, ) std_output = gr.Textbox( value=f"{inpaint_model_info}\n" @@ -520,7 +521,9 @@ def inpaint_inf( neg_prompt_submit = negative_prompt.submit(**status_kwargs).then( **kwargs ) - generate_click = stable_diffusion.click(**status_kwargs).then(**kwargs) + # generate_click = stable_diffusion.click(**status_kwargs).then(**kwargs) + generate_click = stable_diffusion.click(**kwargs) + stop_batch.click( fn=cancel_sd, cancels=[prompt_submit, neg_prompt_submit, generate_click], diff --git a/apps/stable_diffusion/web/ui/lora_train_ui.py b/apps/stable_diffusion/web/ui/lora_train_ui.py index d84728bc26..d6d2261c52 100644 --- a/apps/stable_diffusion/web/ui/lora_train_ui.py +++ b/apps/stable_diffusion/web/ui/lora_train_ui.py @@ -23,6 +23,7 @@ value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, diff --git a/apps/stable_diffusion/web/ui/model_manager.py b/apps/stable_diffusion/web/ui/model_manager.py index 11e01fe873..21c0939f5e 100644 --- a/apps/stable_diffusion/web/ui/model_manager.py +++ b/apps/stable_diffusion/web/ui/model_manager.py @@ -105,6 +105,7 @@ def get_image_from_model(model_json): label="Civitai Model Gallery", value=None, visible=False, + show_download_button=False, ) with gr.Row(visible=False) as sendto_btns: diff --git a/apps/stable_diffusion/web/ui/outpaint_ui.py b/apps/stable_diffusion/web/ui/outpaint_ui.py index 2a4c0039e7..38aacfe977 100644 --- a/apps/stable_diffusion/web/ui/outpaint_ui.py +++ b/apps/stable_diffusion/web/ui/outpaint_ui.py @@ -236,6 +236,7 @@ def outpaint_inf( value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, @@ -244,6 +245,9 @@ def outpaint_inf( with gr.Row(elem_id="ui_body"): with gr.Row(): with gr.Column(scale=1, min_width=600): + outpaint_init_image = gr.Image( + label="Input Image", type="pil", sources=["upload"] + ) with gr.Row(): outpaint_model_info = ( f"Custom Model Path: {str(get_custom_model_path())}" @@ -291,13 +295,6 @@ def outpaint_inf( lines=2, elem_id="negative_prompt_box", ) - - outpaint_init_image = gr.Image( - label="Input Image", - type="pil", - height=300, - ) - with gr.Accordion(label="LoRA Options", open=False): with gr.Row(): # janky fix for overflowing text @@ -473,6 +470,8 @@ def outpaint_inf( elem_id="gallery", columns=[2], object_fit="contain", + # TODO: Re-enable download when fixed in Gradio + show_download_button=False, ) std_output = gr.Textbox( value=f"{outpaint_model_info}\n" diff --git a/apps/stable_diffusion/web/ui/outputgallery_ui.py b/apps/stable_diffusion/web/ui/outputgallery_ui.py index 35ef80736f..46a5bf6b8b 100644 --- a/apps/stable_diffusion/web/ui/outputgallery_ui.py +++ b/apps/stable_diffusion/web/ui/outputgallery_ui.py @@ -80,28 +80,29 @@ def output_subdirs() -> list[str]: label="Getting subdirectories...", value=nod_logo, interactive=False, + show_download_button=False, visible=True, show_label=True, elem_id="top_logo", elem_classes="logo_centered", show_download_button=False, ) - gallery = gr.Gallery( label="", value=gallery_files.value, visible=False, show_label=True, columns=4, + # TODO: Re-enable download when fixed in Gradio + show_download_button=False, ) with gr.Column(scale=4): with gr.Group(): - with gr.Row(): + with gr.Row(elem_id="output_subdir_container"): with gr.Column( scale=15, min_width=160, - elem_id="output_subdir_container", ): subdirectories = gr.Dropdown( label=f"Subdirectories of {output_dir}", @@ -109,7 +110,7 @@ def output_subdirs() -> list[str]: choices=subdirectory_paths.value, value="", interactive=True, - elem_classes="dropdown_no_container", + # elem_classes="dropdown_no_container", allow_custom_value=True, ) with gr.Column( @@ -149,11 +150,12 @@ def output_subdirs() -> list[str]: ) as parameters_accordian: image_parameters = gr.DataFrame( headers=["Parameter", "Value"], - col_count=2, + col_count=(2, "fixed"), + row_count=(1, "fixed"), wrap=True, elem_classes="output_parameters_dataframe", value=[["Status", "No image selected"]], - interactive=True, + interactive=False, ) with gr.Accordion(label="Send To", open=True): @@ -327,12 +329,18 @@ def on_select_image(images: list[str], evt: gr.SelectData) -> list: else: return [ filename, - list(map(list, params["parameters"].items())), + gr.DataFrame( + value=list(map(list, params["parameters"].items())), + row_count=(len(params["parameters"]), "fixed"), + ), ] return [ filename, - [["Status", "No parameters found"]], + gr.DataFrame( + value=[["Status", "No parameters found"]], + row_count=(1, "fixed"), + ), ] def on_outputgallery_filename_change(filename: str) -> list: diff --git a/apps/stable_diffusion/web/ui/txt2img_sdxl_ui.py b/apps/stable_diffusion/web/ui/txt2img_sdxl_ui.py index 85dae66d2e..f6835e6dea 100644 --- a/apps/stable_diffusion/web/ui/txt2img_sdxl_ui.py +++ b/apps/stable_diffusion/web/ui/txt2img_sdxl_ui.py @@ -240,6 +240,7 @@ def txt2img_sdxl_inf( value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, @@ -264,7 +265,7 @@ def txt2img_sdxl_inf( custom_checkpoint_type="sdxl" ), allow_custom_value=True, - scale=2, + scale=11, ) t2i_sdxl_vae_info = ( str(get_custom_model_path("vae")) @@ -283,15 +284,16 @@ def txt2img_sdxl_inf( ] + get_custom_model_files("vae"), allow_custom_value=True, + scale=4, + ) + txt2img_sdxl_png_info_img = gr.Image( scale=1, + label="Import PNG info", + elem_id="txt2img_prompt_image", + type="pil", + visible=True, + sources=["upload"], ) - with gr.Column(scale=1, min_width=170): - txt2img_sdxl_png_info_img = gr.Image( - label="Import PNG info", - elem_id="txt2img_prompt_image", - type="pil", - visible=True, - ) with gr.Group(elem_id="prompt_box_outer"): txt2img_sdxl_autogen = gr.Checkbox( @@ -477,6 +479,8 @@ def txt2img_sdxl_inf( elem_id="gallery", columns=[2], object_fit="scale_down", + # TODO: Re-enable download when fixed in Gradio + show_download_button=False, ) std_output = gr.Textbox( value=f"{t2i_sdxl_model_info}\n" diff --git a/apps/stable_diffusion/web/ui/txt2img_ui.py b/apps/stable_diffusion/web/ui/txt2img_ui.py index 9df392a90a..d6d36646df 100644 --- a/apps/stable_diffusion/web/ui/txt2img_ui.py +++ b/apps/stable_diffusion/web/ui/txt2img_ui.py @@ -427,6 +427,7 @@ def onload_load_settings(): value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, @@ -436,7 +437,7 @@ def onload_load_settings(): with gr.Row(): with gr.Column(scale=1, min_width=600): with gr.Row(): - with gr.Column(scale=10): + with gr.Column(): with gr.Row(): t2i_model_info = f"Custom Model Path: {str(get_custom_model_path())}" txt2img_custom_model = gr.Dropdown( @@ -449,7 +450,7 @@ def onload_load_settings(): choices=get_custom_model_files() + predefined_models, allow_custom_value=True, - scale=2, + scale=11, ) # janky fix for overflowing text t2i_vae_info = ( @@ -464,16 +465,16 @@ def onload_load_settings(): choices=["None"] + get_custom_model_files("vae"), allow_custom_value=True, + scale=4, + ) + txt2img_png_info_img = gr.Image( + label="Import PNG info", + elem_id="txt2img_prompt_image", + type="pil", + visible=True, + sources=["upload"], scale=1, ) - with gr.Column(scale=1, min_width=170): - txt2img_png_info_img = gr.Image( - label="Import PNG info", - elem_id="txt2img_prompt_image", - type="pil", - visible=True, - ) - with gr.Group(elem_id="prompt_box_outer"): prompt = gr.Textbox( label="Prompt", @@ -688,6 +689,8 @@ def onload_load_settings(): elem_id="gallery", columns=[2], object_fit="contain", + # TODO: Re-enable download when fixed in Gradio + show_download_button=False, ) std_output = gr.Textbox( value=f"{t2i_model_info}\n" diff --git a/apps/stable_diffusion/web/ui/upscaler_ui.py b/apps/stable_diffusion/web/ui/upscaler_ui.py index 42157dbd98..be5f33b218 100644 --- a/apps/stable_diffusion/web/ui/upscaler_ui.py +++ b/apps/stable_diffusion/web/ui/upscaler_ui.py @@ -255,6 +255,7 @@ def upscaler_inf( value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, @@ -263,6 +264,11 @@ def upscaler_inf( with gr.Row(elem_id="ui_body"): with gr.Row(): with gr.Column(scale=1, min_width=600): + upscaler_init_image = gr.Image( + label="Input Image", + type="pil", + sources=["upload"], + ) with gr.Row(): upscaler_model_info = ( f"Custom Model Path: {str(get_custom_model_path())}" @@ -311,13 +317,6 @@ def upscaler_inf( lines=2, elem_id="negative_prompt_box", ) - - upscaler_init_image = gr.Image( - label="Input Image", - type="pil", - height=300, - ) - with gr.Accordion(label="LoRA Options", open=False): with gr.Row(): # janky fix for overflowing text @@ -471,6 +470,8 @@ def upscaler_inf( elem_id="gallery", columns=[2], object_fit="contain", + # TODO: Re-enable download when fixed in Gradio + show_download_button=False, ) std_output = gr.Textbox( value=f"{upscaler_model_info}\n" diff --git a/dataset/annotation_tool.py b/dataset/annotation_tool.py index edd088229f..8c8c85cdfd 100644 --- a/dataset/annotation_tool.py +++ b/dataset/annotation_tool.py @@ -23,6 +23,7 @@ value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=100, diff --git a/requirements.txt b/requirements.txt index a97baa83a3..ff649a4468 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,7 +26,7 @@ diffusers accelerate scipy ftfy -gradio==4.7.1 +gradio==4.8.0 altair omegaconf # 0.3.2 doesn't have binaries for arm64