sup-toolbox-app / ui /ui_layout.py
elismasilva's picture
initial commit
7ebbf86
# Copyright 2025 The DEVAIEXP Team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from dataclasses import dataclass, field
from typing import Any, Dict
import gradio as gr
# Custom Component Imports
from gradio_bottombar import BottomBar
from gradio_buttonplus import ButtonPlus
from gradio_creditspanel import CreditsPanel
from gradio_dropdownplus import DropdownPlus
from gradio_folderexplorer import FolderExplorer
from gradio_htmlinjector import HTMLInjector
from gradio_imagemeta import ImageMeta
from gradio_livelog import LiveLog
from gradio_mediagallery import MediaGallery
from gradio_propertysheet import PropertySheet
from gradio_taggrouphelper import TagGroupHelper
from gradio_textboxplus import TextboxPlus
from gradio_tokenizertextbox import TokenizerTextBox
from gradio_topbar import TopBar
from ui.ui_config import (
CREDIT_LIST,
LICENSE_PATHS,
TAG_DATA_NEGATIVE,
TAG_DATA_POSITIVE,
AppSettings,
ControlNetTile_Config,
SUPIR_Config,
SUPIRAdvanced_Config,
)
from ui.ui_data import UIData
@dataclass
class UIComponents:
"""A dataclass to hold all interactive UI components for type safety and Intellisense."""
html_injector: HTMLInjector
flyout_visible: gr.State
active_anchor_id: gr.State
js_data_bridge: gr.Textbox
total_inference_steps: gr.State
run_btn: gr.Button
cancel_btn: gr.Button
preset_name: TextboxPlus
presets: DropdownPlus
save_preset_btn: gr.Button
load_preset_btn: gr.Button
restorer_engine: DropdownPlus
upscaler_engine: DropdownPlus
restorer_model: DropdownPlus
upscaler_model: DropdownPlus
vae_model: gr.Dropdown
restorer_sampler: DropdownPlus
restorer_sampler_ear_btn: ButtonPlus
upscaler_sampler: DropdownPlus
upscaler_sampler_ear_btn: ButtonPlus
flyout_property_sheet_close_btn: gr.Button
flyout_sheet: PropertySheet
main_tabs: gr.Tabs
input_image: ImageMeta
result_slider: gr.ImageSlider
ec_accordion: gr.Accordion
config_tabs: gr.Tabs
restorer_tab: gr.Tab
res_prompt_method: gr.Dropdown
res_prompt: gr.Textbox
res_prompt_generate_btn: ButtonPlus
res_prompt_2: gr.Textbox
res_tokenizer_pos: TokenizerTextBox
res_negative_prompt: gr.Textbox
res_tokenizer_neg: TokenizerTextBox
preview_restoration_mask_chk: gr.Checkbox
restoration_mask_prompt: gr.Textbox
preview_restoration_mask_btn: ButtonPlus
flyout_restoration_image_close_btn: gr.Button
restoration_mask: gr.Image
restorer_sheet: PropertySheet
restorer_sheet_supir_advanced: PropertySheet
upscaler_tab: gr.Tab
ups_prompt_method: gr.Dropdown
ups_prompt: gr.Textbox
ups_prompt_generate_btn: ButtonPlus
ups_prompt_2: gr.Textbox
ups_tokenizer_pos: TokenizerTextBox
ups_negative_prompt: gr.Textbox
ups_tokenizer_neg: TokenizerTextBox
upscaler_sheet: PropertySheet
upscaler_sheet_supir_advanced: PropertySheet
generated_tab: gr.Tab
folder_explorer: FolderExplorer
generated_image_viewer: MediaGallery
settings_tab: gr.Tab
settings_sheet: PropertySheet
reset_settings_btn: gr.Button
save_settings_btn: gr.Button
about_tab: gr.Tab
tag_helper_pos: TagGroupHelper
tag_helper_neg: TagGroupHelper
bottom_bar: BottomBar
livelog_viewer: LiveLog
ALL_UI_COMPONENTS: Dict[str, Any] = field(default_factory=dict)
def _get_ui_inputs_and_outputs(self):
"""Internal helper to reconstruct UI input/output lists when needed."""
ui_inputs = {
"Restorer Sheet": self.restorer_sheet,
"Restorer Sheet SUPIR Advanced": self.restorer_sheet_supir_advanced,
"Upscaler Sheet": self.upscaler_sheet,
"Upscaler Sheet SUPIR Advanced": self.upscaler_sheet_supir_advanced,
"Image Restore Engine": self.restorer_engine,
"Image Upscale Engine": self.upscaler_engine,
"Image Restore Model": self.restorer_model,
"Image Upscale Model": self.upscaler_model,
"VAE Model": self.vae_model,
"Image Restore Sampler": self.restorer_sampler,
"Image Upscale Sampler": self.upscaler_sampler,
"Input Image": self.input_image,
"Image Restore - Prompt method": self.res_prompt_method,
"Image Restore - Prompt 1": self.res_prompt,
"Image Restore - Prompt 2": self.res_prompt_2,
"Image Restore - Negative prompt": self.res_negative_prompt,
"Enable Face Restoration": self.preview_restoration_mask_chk,
"Mask Prompt": self.restoration_mask_prompt,
"Image Upscale - Prompt method": self.ups_prompt_method,
"Image Upscale - Prompt 1": self.ups_prompt,
"Image Upscale - Prompt 2": self.ups_prompt_2,
"Image Upscale - Negative prompt": self.ups_negative_prompt,
}
output_fields = [*ui_inputs.copy().values()]
ui_inputs.pop("Input Image", None)
return ui_inputs, output_fields
def get_initial_supir_advanced_values():
"""Helper to provide initial default values to the UI component."""
initial_supir_advanced_settings = SUPIRAdvanced_Config()
initial_supir_advanced_settings.cross_up_block_0_stage1.sft_active = False
initial_supir_advanced_settings.cross_up_block_1_stage1.sft_active = False
return initial_supir_advanced_settings
def create_ui_components(uidata: UIData) -> UIComponents:
"""
Builds and returns a dictionary of UI components.
This function MUST be called from within a `gr.Blocks()` context.
"""
html_injector = HTMLInjector()
flyout_visible = gr.State(False)
active_anchor_id = gr.State(None)
js_data_bridge = gr.Textbox(visible=False, elem_id="js_data_bridge")
total_inference_steps = gr.State(0)
gr.Markdown(
"""
<div align="center">
# SUP Toolbox App Demo
> **Note:** This is a demonstration version with limited features.
> The **Face Restoration** and **Auto Caption Generation** features are disabled in this online demo
> to ensure stability and reduce resource usage. For access to all features, please run the
> [full application locally](https://github.com/DEVAIEXP/sup-toolbox-app).
</div>
"""
)
with gr.Row():
with TopBar(width="30%", height=80, bring_to_front=True, rounded_borders=True):
with gr.Row():
run_btn = gr.Button(f"{uidata.process_symbol} Run Process", variant="primary", elem_id="run-button")
cancel_btn = gr.Button(
f"{uidata.stop_symbol} Cancel",
variant="stop",
elem_id="cancel-button",
visible=False,
)
with gr.Sidebar(width=360):
with gr.Column(elem_classes=["flyout-context-area"], min_width=250):
gr.Markdown("### Preset Selection")
with gr.Row():
preset_name = TextboxPlus(
elem_id="preset_name",
label="Preset name",
help="Name of the preset to be saved or loaded",
)
presets = DropdownPlus(
elem_id="presets",
label="Presets",
interactive=True,
choices=uidata.PRESETS_LIST,
value=uidata.config.latest_preset,
help="Select a preset to load",
)
with gr.Row():
save_preset_btn = gr.Button(
f"{uidata.save_symbol} Save preset",
variant="primary",
elem_id="save_preset",
)
load_preset_btn = gr.Button(f"{uidata.download_symbol} Load preset", elem_id="load_preset")
with gr.Row():
gr.Markdown("### Engine Selection")
restorer_engine = DropdownPlus(
elem_id="restorer_engine",
label="Image Restore Engine",
choices=uidata.RESTORER_ENGINE_CHOICES,
value="SUPIR",
help="Select the image restoration engine to be used",
)
upscaler_engine = DropdownPlus(
elem_id="upscaler_engine",
label="Image Upscale Engine",
choices=uidata.UPSCALER_ENGINE_CHOICES,
value="None",
help="Select the image upscaling engine to be used",
)
gr.Markdown("### Model Selection")
restorer_model = DropdownPlus(
elem_id="restorer_model",
label="Image Restore Model",
choices=uidata.MODEL_CHOICES,
value=uidata.MODEL_CHOICES[0] if uidata.MODEL_CHOICES else None,
elem_classes=["custom-dropdown"],
help="Select the model to be used for the restoration engine",
)
upscaler_model = DropdownPlus(
elem_id="upscaler_model",
label="Image Upscale Model",
choices=uidata.MODEL_CHOICES,
value=uidata.MODEL_CHOICES[0] if uidata.MODEL_CHOICES else None,
elem_classes=["custom-dropdown"],
help="Select the model to be used for the upscaling engine",
)
vae_model = gr.Dropdown(
elem_id="vae_model",
label="VAE Model (Optional)",
choices=uidata.VAE_CHOICES,
value="Default",
)
gr.Markdown("### Sampler Selection")
with gr.Accordion(open=False, label="Create/Choose Sampler", elem_id="sampler-accordion"):
with gr.Group(elem_classes=["group"]):
with gr.Row(elem_classes=["fake-input-container", "no-border-dropdown"]):
restorer_sampler = DropdownPlus(
elem_id="restorer_sampler",
label="Image Restore Sampler",
choices=uidata.SAMPLER_SUPIR_LIST,
value="Euler",
help="Select the sampler to be used for the restoration engine",
)
restorer_sampler_ear_btn = ButtonPlus(
f"{uidata.engine_symbol}",
elem_id="restorer_sampler_ear_btn",
scale=1,
elem_classes=["integrated-ear-btn"],
help="Click to open advanced settings...",
)
with gr.Row(elem_classes=["fake-input-container", "no-border-dropdown"]):
upscaler_sampler = DropdownPlus(
elem_id="upscaler_sampler",
label="Image Upscale Sampler",
choices=uidata.SAMPLER_OTHERS_LIST,
value="Euler",
help="Select the sampler to be used for the upscaling engine",
)
upscaler_sampler_ear_btn = ButtonPlus(
f"{uidata.engine_symbol}",
elem_id="upscaler_sampler_ear_btn",
scale=1,
elem_classes=["integrated-ear-btn"],
help="Click to open advanced settings...",
)
with gr.Column(elem_id="flyout_property_sheet_panel", elem_classes=["flyout-source-hidden"]):
flyout_property_sheet_close_btn = gr.Button("×", elem_classes=["flyout-close-btn"])
flyout_sheet = PropertySheet(
elem_id="flyout_sheet",
visible=True,
container=False,
label="Settings",
show_group_name_only_one=False,
disable_accordion=True,
)
with gr.Tabs() as main_tabs:
with gr.TabItem(f"{uidata.process_symbol} Process", id="process-tab"):
with gr.Row():
with gr.Column(scale=3):
with gr.Row():
input_image = ImageMeta(
elem_id="input_image",
type="filepath",
label="Input Image",
height=500,
width=600,
popup_metadata_width=600,
popup_metadata_height=500,
only_custom_metadata=False,
)
result_slider = gr.ImageSlider(
elem_id="result_slider",
label="Result Comparison",
show_label=True,
height=500,
)
with gr.Accordion("Engine Configurations", open=True) as ec_accordion:
with gr.Tabs() as config_tabs:
with gr.TabItem("Restoration", id=0, visible=False, elem_id="res-tab") as restorer_tab:
res_prompt_method = gr.Dropdown(
elem_id="restorer_prompt_method",
label="Prompt Method",
choices=uidata.PROMPT_METHODS,
value=uidata.PROMPT_METHODS[1],
info="Method used to generate prompt embedding",
)
with gr.Group(elem_classes=["group"]):
with gr.Row(
elem_classes=[
"fake-input-container",
"no-border-dropdown",
"row-form-size-2",
]
):
res_prompt = gr.Textbox(
elem_id="restorer_prompt_1",
label="Prompt",
lines=3,
info="Your positive prompt",
value="Direct flash photography. Three (30-year-old men:1.1), (all black hair:1.2). Left man: (black t-shirt:1.1) with white text 'Road Kill Cafe' and in his right forearm has distinct (dark tribal tattoo:1.2).Their hands has clearly defined fingers and distinct outlines. A (plaster interior wall: 1.1) on the left.",
)
res_prompt_generate_btn = ButtonPlus(
value=f"{uidata.caption_symbol}",
elem_id="res_prompt_generate_btn",
elem_classes=["integrated-ear-btn"],
help="Click to auto generate the initial caption...",
visible=False
)
res_prompt_2 = gr.Textbox(
elem_id="restorer_prompt_2",
label="Prompt 2",
lines=2,
info="Your positive prompt complement",
value="Extremely detailed faces, flawless natural skin texture, skin pore detailing, 4k, 8k, clean image, no noise, shot on Fujifilm Superia 400, sharp focus, faithful colors.",
)
res_tokenizer_pos = TokenizerTextBox(
elem_id="restorer_tokenizer_prompt",
label="Positive Tokenizer",
hide_input=True,
model="Xenova/clip-vit-large-patch14",
)
res_negative_prompt = gr.Textbox(
elem_id="restorer_negative_prompt",
label="Negative Prompt",
lines=3,
info="Specify what you doesn't want to see",
value="low-res, disfigured, analog artifacts, smudged, animate, (out of focus:1.2), catchlights, over-smooth, extra eyes, worst quality, unreal engine, art, aberrations, surreal, pastel drawing, (tattoo patterns on walls:1.4), tatto patterns on skin, text on walls, green wall, grainy wall texture, harsh lighting, (tribal patterns on clothing text:1.3), tattoo on chest, dead eyes, deformed fingers, undistinct fingers outlines",
)
res_tokenizer_neg = TokenizerTextBox(
elem_id="restorer_tokenizer_negative_prompt",
label="Negative Tokenizer",
hide_input=True,
model="Xenova/clip-vit-large-patch14",
)
with gr.Accordion("Face Restoration", open=False, visible=False):
preview_restoration_mask_chk = gr.Checkbox(
elem_id="use_restoration_mask",
label="Enable Face Restoration",
value=False,
)
with gr.Row(
elem_classes=[
"fake-input-container",
"no-border-dropdown",
"row-form-size",
]
):
restoration_mask_prompt = gr.Textbox(
elem_id="restoration_mask_prompt",
label="Mask prompt",
placeholder="head",
value="head",
interactive=False,
)
preview_restoration_mask_btn = ButtonPlus(
value=f"{uidata.preview_symbol}",
elem_id="preview_restoration_mask_btn",
elem_classes=["integrated-ear-btn"],
interactive=False,
help="Click to open preview restoration mask...",
)
with gr.Column(
elem_id="flyout_restoration_mask_panel",
elem_classes=["flyout-source-hidden"],
):
flyout_restoration_image_close_btn = gr.Button("×", elem_classes=["flyout-close-btn"])
restoration_mask = gr.Image(
elem_id="flyout_restoration_mask",
label="Masking preview",
type="pil",
interactive=False,
show_download_button=False,
show_share_button=False,
height=300,
)
restorer_sheet = PropertySheet(
elem_id="restorer_settings",
label="Restoration Settings",
value=SUPIR_Config(),
)
restorer_sheet_supir_advanced = PropertySheet(
elem_id="restorer_supir_advanced_settings",
label="SFT Injection Settings (Experimental parameters for advanced users)",
open=False,
value=get_initial_supir_advanced_values(),
)
with gr.TabItem("Upscaling", id=1, visible=False, elem_id="ups-tab") as upscaler_tab:
ups_prompt_method = gr.Dropdown(
elem_id="upscaler_prompt_method",
label="Prompt Method",
choices=uidata.PROMPT_METHODS,
value=uidata.PROMPT_METHODS[1],
info="Method used to generate prompt embedding",
)
with gr.Group(elem_classes=["group"]):
with gr.Row(
elem_classes=[
"fake-input-container",
"no-border-dropdown",
"row-form-size-2",
]
):
ups_prompt = gr.Textbox(
elem_id="upscaler_prompt_1",
label="Prompt",
lines=3,
info="Your positive prompt",
)
ups_prompt_generate_btn = ButtonPlus(
value=f"{uidata.caption_symbol}",
elem_id="ups_prompt_generate_btn",
elem_classes=["integrated-ear-btn"],
help="Click to auto generate the initial caption...",
visible=False
)
ups_prompt_2 = gr.Textbox(
elem_id="upscaler_prompt_2",
label="Prompt 2",
lines=2,
info="Your positive prompt complement",
)
ups_tokenizer_pos = TokenizerTextBox(
elem_id="upscaler_tokenizer_prompt",
label="Positive Tokenizer",
hide_input=True,
model="Xenova/clip-vit-large-patch14",
)
ups_negative_prompt = gr.Textbox(
elem_id="upscaler_negative_prompt",
label="Negative Prompt",
lines=3,
info="Specify what you doesn't want to see",
)
ups_tokenizer_neg = TokenizerTextBox(
elem_id="upscaler_tokenizer_negative_prompt",
label="Negative Tokenizer",
hide_input=True,
model="Xenova/clip-vit-large-patch14",
)
upscaler_sheet = PropertySheet(
elem_id="upscaler_settings",
label="Upscaling Settings",
value=ControlNetTile_Config(),
)
upscaler_sheet_supir_advanced = PropertySheet(
elem_id="upscaler_supir_advanced_settings",
label="SFT Injection Settings (Experimental parameters for advanced users)",
open=False,
value=get_initial_supir_advanced_values(),
)
with gr.TabItem(f"{uidata.folder_symbol} Generated") as generated_tab:
with gr.Row(equal_height=True, elem_classes="media-gallery-row"):
with gr.Column(scale=0, min_width=300):
folder_explorer = FolderExplorer(
label="Select a Folder",
root_dir=uidata.config.output_dir,
value=uidata.config.output_dir,
)
with gr.Column(scale=2):
generated_image_viewer = MediaGallery(
label="Media in Folder",
columns=4,
height="auto",
preview=False,
show_download_button=False,
only_custom_metadata=False,
popup_metadata_width="40%",
)
with gr.Tab(f"{uidata.settings_symbol} Settings", interactive=False) as settings_tab:
settings_sheet = PropertySheet(elem_id="settings_sheet", label="General Setting", value=AppSettings())
with gr.Row(elem_id="settings-buttons-row"):
reset_settings_btn = gr.Button(
value=f"{uidata.refresh_symbol} Load defaults and restart",
elem_id="reset_settings_button",
)
save_settings_btn = gr.Button(
value=f"{uidata.save_symbol} Save and restart",
elem_id="save_settings_button",
)
with gr.Tab(f"{uidata.about_symbol} About") as about_tab:
CreditsPanel(
elem_classes="credit-panel",
height="auto",
credits=CREDIT_LIST,
licenses=LICENSE_PATHS,
effect="scroll",
speed=60.0,
base_font_size=1.5,
intro_title="SUP Toolbox",
intro_subtitle="Scaling-UP Application",
sidebar_position="right",
logo_path=None,
show_logo=True,
show_licenses=True,
show_credits=True,
logo_position="center",
logo_sizing="resize",
logo_width="200px",
logo_height="100px",
scroll_background_color="#000000",
scroll_title_color="#FFFFFF",
scroll_name_color="#FFFFFF",
scroll_section_title_color="#FFFFFF",
layout_style="two-column",
title_uppercase=True,
name_uppercase=True,
section_title_uppercase=True,
swap_font_sizes_on_two_column=True,
scroll_logo_path="assets/devaixp_logo-white.png",
scroll_logo_height="200px",
)
with gr.Sidebar(position="right", width=360):
gr.Markdown("### Helpers")
tag_helper_pos = TagGroupHelper(
elem_id="tag_helper_pos",
label="Positive Keywords",
value=dict(TAG_DATA_POSITIVE),
target_textbox_id="upscaler_prompt_1",
separator=", ",
width=290,
font_size_scale=90,
interactive=True,
open=False,
)
tag_helper_neg = TagGroupHelper(
elem_id="tag_helper_neg",
label="Negative Keywords",
value=dict(TAG_DATA_NEGATIVE),
target_textbox_id="upscaler_negative_prompt",
separator=", ",
width=290,
font_size_scale=90,
interactive=True,
open=False,
)
with BottomBar("Status", bring_to_front=False, height=340, open=False, rounded_borders=True) as bottom_bar:
livelog_viewer = LiveLog(label="Process output", height=250, autoscroll=True, line_numbers=False)
all_ui_components_for_presets = {
restorer_engine.elem_id: restorer_engine,
upscaler_engine.elem_id: upscaler_engine,
restorer_model.elem_id: restorer_model,
upscaler_model.elem_id: upscaler_model,
vae_model.elem_id: vae_model,
restorer_sampler.elem_id: restorer_sampler,
upscaler_sampler.elem_id: upscaler_sampler,
res_prompt_method.elem_id: res_prompt_method,
res_prompt.elem_id: res_prompt,
res_prompt_2.elem_id: res_prompt_2,
res_negative_prompt.elem_id: res_negative_prompt,
preview_restoration_mask_chk.elem_id: preview_restoration_mask_chk,
restoration_mask_prompt.elem_id: restoration_mask_prompt,
restorer_sheet.elem_id: restorer_sheet,
restorer_sheet_supir_advanced.elem_id: restorer_sheet_supir_advanced,
ups_prompt_method.elem_id: ups_prompt_method,
ups_prompt.elem_id: ups_prompt,
ups_prompt_2.elem_id: ups_prompt_2,
ups_negative_prompt.elem_id: ups_negative_prompt,
upscaler_sheet.elem_id: upscaler_sheet,
upscaler_sheet_supir_advanced.elem_id: upscaler_sheet_supir_advanced,
}
components_dict = {
"html_injector": html_injector,
"flyout_visible": flyout_visible,
"active_anchor_id": active_anchor_id,
"js_data_bridge": js_data_bridge,
"total_inference_steps": total_inference_steps,
"run_btn": run_btn,
"cancel_btn": cancel_btn,
"preset_name": preset_name,
"presets": presets,
"save_preset_btn": save_preset_btn,
"load_preset_btn": load_preset_btn,
"restorer_engine": restorer_engine,
"upscaler_engine": upscaler_engine,
"restorer_model": restorer_model,
"upscaler_model": upscaler_model,
"vae_model": vae_model,
"restorer_sampler": restorer_sampler,
"restorer_sampler_ear_btn": restorer_sampler_ear_btn,
"upscaler_sampler": upscaler_sampler,
"upscaler_sampler_ear_btn": upscaler_sampler_ear_btn,
"flyout_property_sheet_close_btn": flyout_property_sheet_close_btn,
"flyout_sheet": flyout_sheet,
"main_tabs": main_tabs,
"input_image": input_image,
"result_slider": result_slider,
"ec_accordion": ec_accordion,
"config_tabs": config_tabs,
"restorer_tab": restorer_tab,
"res_prompt_method": res_prompt_method,
"res_prompt": res_prompt,
"res_prompt_generate_btn": res_prompt_generate_btn,
"res_prompt_2": res_prompt_2,
"res_tokenizer_pos": res_tokenizer_pos,
"res_negative_prompt": res_negative_prompt,
"res_tokenizer_neg": res_tokenizer_neg,
"preview_restoration_mask_chk": preview_restoration_mask_chk,
"restoration_mask_prompt": restoration_mask_prompt,
"preview_restoration_mask_btn": preview_restoration_mask_btn,
"flyout_restoration_image_close_btn": flyout_restoration_image_close_btn,
"restoration_mask": restoration_mask,
"restorer_sheet": restorer_sheet,
"restorer_sheet_supir_advanced": restorer_sheet_supir_advanced,
"upscaler_tab": upscaler_tab,
"ups_prompt_method": ups_prompt_method,
"ups_prompt": ups_prompt,
"ups_prompt_generate_btn": ups_prompt_generate_btn,
"ups_prompt_2": ups_prompt_2,
"ups_tokenizer_pos": ups_tokenizer_pos,
"ups_negative_prompt": ups_negative_prompt,
"ups_tokenizer_neg": ups_tokenizer_neg,
"upscaler_sheet": upscaler_sheet,
"upscaler_sheet_supir_advanced": upscaler_sheet_supir_advanced,
"generated_tab": generated_tab,
"folder_explorer": folder_explorer,
"generated_image_viewer": generated_image_viewer,
"settings_tab": settings_tab,
"settings_sheet": settings_sheet,
"reset_settings_btn": reset_settings_btn,
"save_settings_btn": save_settings_btn,
"about_tab": about_tab,
"tag_helper_pos": tag_helper_pos,
"tag_helper_neg": tag_helper_neg,
"bottom_bar": bottom_bar,
"livelog_viewer": livelog_viewer,
"ALL_UI_COMPONENTS": all_ui_components_for_presets,
}
return components_dict