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