From 1403efb625a72ecaac23c6c22567357e4e7d9289 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. * Reset Inpaint ImageEditor control with the Mask Layer after generation is complete, as it gets lost if the image was sent to the tab from another tab rather than being uploaded. Also rework queuing and progress rendering along this codepath. This doesn't solve the underlying problem of the Mask Layer being removed, but does get inpaint fully working with the Gradio update. --- apps/stable_diffusion/web/api/sdapi_v1.py | 3 +- apps/stable_diffusion/web/index.py | 104 +++++++++------ .../web/ui/common_ui_events.py | 2 + .../web/ui/css/sd_dark_theme.css | 23 +++- apps/stable_diffusion/web/ui/img2img_ui.py | 19 +-- apps/stable_diffusion/web/ui/inpaint_ui.py | 124 +++++++++++++++--- apps/stable_diffusion/web/ui/lora_train_ui.py | 2 +- apps/stable_diffusion/web/ui/model_manager.py | 1 + apps/stable_diffusion/web/ui/outpaint_ui.py | 14 +- .../web/ui/outputgallery_ui.py | 30 +++-- .../web/ui/txt2img_sdxl_ui.py | 21 +-- apps/stable_diffusion/web/ui/txt2img_ui.py | 24 ++-- apps/stable_diffusion/web/ui/upscaler_ui.py | 16 +-- apps/stable_diffusion/web/ui/utils.py | 22 ++++ dataset/annotation_tool.py | 1 + requirements.txt | 2 +- 16 files changed, 290 insertions(+), 118 deletions(-) diff --git a/apps/stable_diffusion/web/api/sdapi_v1.py b/apps/stable_diffusion/web/api/sdapi_v1.py index 3eebd5c113..f376f0fe9d 100644 --- a/apps/stable_diffusion/web/api/sdapi_v1.py +++ b/apps/stable_diffusion/web/api/sdapi_v1.py @@ -374,7 +374,8 @@ def inpaint_api( res = inpaint_inf( InputData.prompt, InputData.negative_prompt, - {"image": init_image, "mask": mask}, + init_image, + 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..b679586301 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() @@ -86,6 +87,8 @@ from apps.stable_diffusion.web.ui.utils import ( create_custom_models_folders, nodicon_loc, + mask_editor_value_for_gallery_data, + mask_editor_value_for_image_file, ) create_custom_models_folders() @@ -177,10 +180,20 @@ 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: ( + mask_editor_value_for_gallery_data(x), gr.Tabs(selected=selectedid), ), inputs, @@ -196,9 +209,12 @@ def register_modelmanager_button(button, selectedid, inputs, outputs): ), inputs, outputs, + queue=False, ) - def register_outputgallery_button(button, selectedid, inputs, outputs): + def register_outputgallery_sendto_button( + button, selectedid, inputs, outputs + ): button.click( lambda x: ( x, @@ -208,6 +224,18 @@ def register_outputgallery_button(button, selectedid, inputs, outputs): outputs, ) + def register_outputgallery_sendto_editor_button( + button, selectedid, inputs, outputs + ): + button.click( + lambda x: ( + mask_editor_value_for_image_file(x), + gr.Tabs(selected=selectedid), + ), + inputs, + outputs, + ) + dark_theme = resource_path("ui/css/sd_dark_theme.css") with gr.Blocks( @@ -236,19 +264,6 @@ def register_outputgallery_button(button, selectedid, inputs, outputs): if args.output_gallery: with gr.TabItem(label="Output Gallery", id=5) as og_tab: outputgallery_web.render() - - # extra output gallery configuration - outputgallery_tab_select(og_tab.select) - outputgallery_watch( - [ - txt2img_status, - img2img_status, - inpaint_status, - outpaint_status, - upscaler_status, - txt2img_sdxl_status, - ] - ) # with gr.TabItem(label="Model Manager", id=6): # model_web.render() # with gr.TabItem(label="LoRA Training (Experimental)", id=7): @@ -268,6 +283,19 @@ def register_outputgallery_button(button, selectedid, inputs, outputs): with gr.TabItem(label="Text-to-Image (SDXL)", id=13): txt2img_sdxl_web.render() + # extra output gallery configuration + outputgallery_tab_select(og_tab.select) + outputgallery_watch( + [ + txt2img_status, + img2img_status, + inpaint_status, + outpaint_status, + upscaler_status, + txt2img_sdxl_status, + ], + ) + actual_port = app.usable_port() if actual_port != args.server_port: sd_web.load( @@ -278,134 +306,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..a6df246325 100644 --- a/apps/stable_diffusion/web/ui/img2img_ui.py +++ b/apps/stable_diffusion/web/ui/img2img_ui.py @@ -326,14 +326,21 @@ def img2img_inf( value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, - show_download_button=False, ) 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 +387,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 +957,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..4ce4795a82 100644 --- a/apps/stable_diffusion/web/ui/inpaint_ui.py +++ b/apps/stable_diffusion/web/ui/inpaint_ui.py @@ -3,8 +3,15 @@ import time import sys import gradio as gr +import PIL.ImageOps from PIL import Image +from gradio.components.image_editor import ( + Brush, + Eraser, + EditorData, + EditorValue, +) from apps.stable_diffusion.web.ui.utils import ( available_devices, nodlogo_loc, @@ -37,11 +44,53 @@ init_import_mlir = args.import_mlir +def set_image_states(editor_data): + input_mask = editor_data["layers"][0] + + # inpaint_inf wants white mask on black background (?), whilst ImageEditor + # delivers black mask on transparent (0 opacity) background + inference_mask = Image.new( + mode="RGB", size=input_mask.size, color=(255, 255, 255) + ) + inference_mask.paste(input_mask, input_mask) + inference_mask = PIL.ImageOps.invert(inference_mask) + + return ( + # we set the ImageEditor data again, because it likes to clear + # the image layers (which include the mask) if the user hasn't + # used the upload button, and we sent it and image + # TODO: work out what is going wrong in that case so we don't have + # to do this + { + "background": editor_data["background"], + "layers": [input_mask], + "composite": None, + }, + editor_data["background"], + input_mask, + inference_mask, + ) + + +def reload_image_editor(editor_image, editor_mask): + # we set the ImageEditor data again, because it likes to clear + # the image layers (which include the mask) if the user hasn't + # used the upload button, and we sent it the image + # TODO: work out what is going wrong in that case so we don't have + # to do this + return { + "background": editor_image, + "layers": [editor_mask], + "composite": None, + } + + # Exposed to UI. def inpaint_inf( prompt: str, negative_prompt: str, - image_dict, + image, + mask_image, height: int, width: int, inpaint_full_res: bool, @@ -175,8 +224,6 @@ def inpaint_inf( start_time = time.time() global_obj.get_sd_obj().log = "" generated_imgs = [] - image = image_dict["image"] - mask_image = image_dict["mask"] text_output = "" try: seeds = utils.batch_seeds(seed, batch_count, repeatable_seeds) @@ -223,6 +270,9 @@ def inpaint_inf( with gr.Blocks(title="Inpainting") as inpaint_web: + editor_image = gr.State() + editor_mask = gr.State() + inference_mask = gr.State() with gr.Row(elem_id="ui_title"): nod_logo = Image.open(nodlogo_loc) with gr.Row(): @@ -231,14 +281,24 @@ def inpaint_inf( value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, - show_download_button=False, ) with gr.Row(elem_id="ui_body"): with gr.Row(): with gr.Column(scale=1, min_width=600): + inpaint_init_image = gr.Sketchpad( + label="Masked Image", + type="pil", + sources=("clipboard", "upload"), + interactive=True, + brush=Brush( + colors=["#000000"], + color_mode="fixed", + ), + ) with gr.Row(): # janky fix for overflowing text inpaint_model_info = ( @@ -288,14 +348,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 +500,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" @@ -484,7 +538,8 @@ def inpaint_inf( inputs=[ prompt, negative_prompt, - inpaint_init_image, + editor_image, + inference_mask, height, width, inpaint_full_res, @@ -514,18 +569,53 @@ def inpaint_inf( fn=lambda bc, bs: status_label("Inpaint", 0, bc, bs), inputs=[batch_count, batch_size], outputs=inpaint_status, + show_progress="none", + ) + set_image_states_args = dict( + fn=set_image_states, + inputs=[inpaint_init_image], + outputs=[ + inpaint_init_image, + editor_image, + editor_mask, + inference_mask, + ], + show_progress="none", + ) + reload_image_editor_args = dict( + fn=reload_image_editor, + inputs=[editor_image, editor_mask], + outputs=[inpaint_init_image], + show_progress="none", ) - prompt_submit = prompt.submit(**status_kwargs).then(**kwargs) - neg_prompt_submit = negative_prompt.submit(**status_kwargs).then( - **kwargs + # all these trigger generation + prompt_submit = ( + prompt.submit(**set_image_states_args) + .then(**status_kwargs) + .then(**kwargs) + .then(**reload_image_editor_args) ) - generate_click = stable_diffusion.click(**status_kwargs).then(**kwargs) + neg_prompt_submit = ( + negative_prompt.submit(**set_image_states_args) + .then(**status_kwargs) + .then(**kwargs) + .then(**reload_image_editor_args) + ) + generate_click = ( + stable_diffusion.click(**set_image_states_args) + .then(**status_kwargs) + .then(**kwargs) + .then(**reload_image_editor_args) + ) + + # Attempts to cancel generation stop_batch.click( fn=cancel_sd, cancels=[prompt_submit, neg_prompt_submit, generate_click], ) + # Updates LoRA information when one is selected lora_weights.change( fn=lora_changed, inputs=[lora_weights], diff --git a/apps/stable_diffusion/web/ui/lora_train_ui.py b/apps/stable_diffusion/web/ui/lora_train_ui.py index d84728bc26..45c1c3e243 100644 --- a/apps/stable_diffusion/web/ui/lora_train_ui.py +++ b/apps/stable_diffusion/web/ui/lora_train_ui.py @@ -23,10 +23,10 @@ value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, - show_download_button=False, ) with gr.Row(elem_id="ui_body"): with gr.Row(): 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..a515f6c90e 100644 --- a/apps/stable_diffusion/web/ui/outpaint_ui.py +++ b/apps/stable_diffusion/web/ui/outpaint_ui.py @@ -236,14 +236,17 @@ def outpaint_inf( value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, - show_download_button=False, ) 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 +294,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 +469,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..d33e5f5393 100644 --- a/apps/stable_diffusion/web/ui/outputgallery_ui.py +++ b/apps/stable_diffusion/web/ui/outputgallery_ui.py @@ -80,28 +80,28 @@ 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 +109,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 +149,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 +328,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: @@ -450,11 +457,12 @@ def outputgallery_tab_select(select): # We should have been passed a list of components on other tabs that update # when a new image has generated on that tab, so set things up so the user # will see that new image if they are looking at today's subdirectory - def outputgallery_watch(components: gr.Textbox): + def outputgallery_watch(components: gr.Textbox, queued_components=[]): for component in components: component.change( on_new_image, inputs=[subdirectories, subdirectory_paths, component], outputs=[gallery_files, gallery, logo], - queue=False, + queue=component in queued_components, + show_progress="none", ) diff --git a/apps/stable_diffusion/web/ui/txt2img_sdxl_ui.py b/apps/stable_diffusion/web/ui/txt2img_sdxl_ui.py index 85dae66d2e..807c30ad2e 100644 --- a/apps/stable_diffusion/web/ui/txt2img_sdxl_ui.py +++ b/apps/stable_diffusion/web/ui/txt2img_sdxl_ui.py @@ -240,10 +240,10 @@ def txt2img_sdxl_inf( value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, - show_download_button=False, ) with gr.Row(elem_id="ui_body"): with gr.Row(): @@ -264,7 +264,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 +283,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 +478,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..3b6c936cf8 100644 --- a/apps/stable_diffusion/web/ui/txt2img_ui.py +++ b/apps/stable_diffusion/web/ui/txt2img_ui.py @@ -427,16 +427,16 @@ def onload_load_settings(): value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, - show_download_button=False, ) with gr.Row(elem_id="ui_body"): 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 +449,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 +464,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 +688,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..88d0507adb 100644 --- a/apps/stable_diffusion/web/ui/upscaler_ui.py +++ b/apps/stable_diffusion/web/ui/upscaler_ui.py @@ -255,14 +255,19 @@ def upscaler_inf( value=nod_logo, show_label=False, interactive=False, + show_download_button=False, elem_id="top_logo", width=150, height=50, - show_download_button=False, ) 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 +316,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 +469,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/apps/stable_diffusion/web/ui/utils.py b/apps/stable_diffusion/web/ui/utils.py index 9252ecee9f..0572089e84 100644 --- a/apps/stable_diffusion/web/ui/utils.py +++ b/apps/stable_diffusion/web/ui/utils.py @@ -5,11 +5,13 @@ import json import safetensors import gradio as gr +import PIL.Image as Image from pathlib import Path from apps.stable_diffusion.src import args from dataclasses import dataclass from enum import IntEnum +from gradio.components.image_editor import EditorValue from apps.stable_diffusion.src import get_available_devices import apps.stable_diffusion.web.utils.global_obj as global_obj @@ -315,6 +317,25 @@ def default_config_exists(model_ckpt_or_id): return None +def mask_editor_value_for_image_file(filepath): + image = Image.open(filepath) + mask = Image.new(mode="RGBA", size=image.size, color=(0, 0, 0, 0)) + return {"background": image, "layers": [mask], "composite": image} + + +def mask_editor_value_for_gallery_data(gallery_data): + filepath = ( + gallery_data.root[0].image.path + if len(gallery_data.root) != 0 + else None + ) + + if os.path.isfile(filepath): + return mask_editor_value_for_image_file(filepath) + + return EditorValue() + + default_configs = { "stabilityai/sdxl-turbo": [ gr.Textbox(label="", interactive=False, value=None, visible=False), @@ -350,6 +371,7 @@ def default_config_exists(model_ckpt_or_id): ], } + nodlogo_loc = resource_path("logos/nod-logo.png") nodicon_loc = resource_path("logos/nod-icon.png") available_devices = get_available_devices() 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