diff --git a/modules/options.py b/modules/options.py index 23ccaf0b..b0b56614 100644 --- a/modules/options.py +++ b/modules/options.py @@ -1,4 +1,3 @@ -import os import json import sys from dataclasses import dataclass @@ -6,8 +5,9 @@ from dataclasses import dataclass import gradio as gr from modules import errors -from modules.shared_cmd_options import cmd_opts from modules.paths_internal import script_path +from modules.shared_cmd_options import cmd_opts +from modules.ui_components import FormRow class OptionInfo: @@ -72,6 +72,13 @@ class OptionDiv(OptionInfo): self.do_not_save = True +class OptionRow(OptionInfo): + def __init__(self): + super().__init__("", label="", component=FormRow) + + self.do_not_save = True + + def options_section(section_identifier, options_dict): for v in options_dict.values(): if len(section_identifier) == 2: diff --git a/modules/shared_options.py b/modules/shared_options.py index d760a31c..a090732f 100644 --- a/modules/shared_options.py +++ b/modules/shared_options.py @@ -594,4 +594,4 @@ options_templates.update( ) forge_shared_options.register(options_templates, options_section, OptionInfo) -forge_presets.register(options_templates, options_section, OptionInfo) +forge_presets.register(options_templates) diff --git a/modules/ui.py b/modules/ui.py index 6e1c1ed5..bf516706 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -231,8 +231,8 @@ def create_ui(): elif category == "dimensions": with FormRow(): with gr.Column(elem_id="txt2img_column_size", scale=4): - width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512, elem_id="txt2img_width") - height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512, elem_id="txt2img_height") + width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=1024, elem_id="txt2img_width") + height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=1024, elem_id="txt2img_height") with gr.Column(elem_id="txt2img_dimensions_row", scale=1, elem_classes="dimensions-tools"): res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn", tooltip="Switch width/height") @@ -591,8 +591,8 @@ def create_ui(): with gr.Tab(label="Resize to", id="to", elem_id="img2img_tab_resize_to") as tab_scale_to: with FormRow(): with gr.Column(elem_id="img2img_column_size", scale=4): - width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512, elem_id="img2img_width") - height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512, elem_id="img2img_height") + width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=1024, elem_id="img2img_width") + height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=1024, elem_id="img2img_height") with gr.Column(elem_id="img2img_dimensions_row", scale=1, elem_classes="dimensions-tools"): res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn", tooltip="Switch width/height") detect_image_size_btn = ToolButton(value=detect_image_size_symbol, elem_id="img2img_detect_image_size_btn", tooltip="Auto detect size from img2img") diff --git a/modules/ui_settings.py b/modules/ui_settings.py index d8393fb9..fa3bf52f 100644 --- a/modules/ui_settings.py +++ b/modules/ui_settings.py @@ -11,6 +11,8 @@ from modules.ui_components import FormRow from modules.ui_gradio_extensions import reload_javascript from modules_forge import main_entry +CURRENT_ROW: gr.Row = None + def get_value_for_setting(key): value = getattr(opts, key) @@ -46,6 +48,17 @@ def create_setting_component(key, is_quicksettings=False): if comp == gr.State: return gr.State(fun()) + elif comp == FormRow: + global CURRENT_ROW + + if CURRENT_ROW is None: + CURRENT_ROW = FormRow() + CURRENT_ROW.__enter__() + else: + CURRENT_ROW.__exit__() + CURRENT_ROW = None + + return gr.State(None) if info.refresh is not None: if is_quicksettings: diff --git a/modules_forge/main_entry.py b/modules_forge/main_entry.py index 094981f2..23da1e0b 100644 --- a/modules_forge/main_entry.py +++ b/modules_forge/main_entry.py @@ -10,6 +10,7 @@ from backend import memory_management from backend.args import dynamic_args from backend.logging import setup_logger from modules import infotext_utils, launch_utils, paths, processing, sd_models, shared, shared_items, ui_common +from modules_forge.presets import PresetArch, use_distill, use_shift logger = logging.getLogger("ui_models") setup_logger(logger) @@ -66,26 +67,21 @@ def make_checkpoint_manager_ui(): if len(sd_models.checkpoints_list) > 0: shared.opts.set("sd_model_checkpoint", next(iter(sd_models.checkpoints_list.values())).name) - ui_forge_preset = gr.Radio(label="UI Preset", value=lambda: shared.opts.forge_preset, choices=("sd", "xl", "flux", "qwen", "lumina", "wan"), elem_id="forge_ui_preset") + ui_forge_preset = gr.Dropdown(label="UI Preset", value=lambda: shared.opts.forge_preset, choices=PresetArch.choices(), elem_id="forge_ui_preset") ui_checkpoint = gr.Dropdown(label="Checkpoint", value=None, choices=None, elem_id="setting_sd_model_checkpoint", elem_classes=["model_selection"]) - ui_vae = gr.Dropdown(label="VAE / Text Encoder", value=None, choices=None, multiselect=True) + ui_vae = gr.Dropdown(label="VAE / Text Encoder", value=None, choices=None, multiselect=True, elem_id="setting_sd_vae", elem_classes=["model_selection"]) def refresh_model_list(): ckpt_list, vae_list = refresh_models() - return gr.update(choices=ckpt_list), gr.update(choices=vae_list) + return [gr.update(choices=ckpt_list), gr.update(choices=vae_list)] refresh_button = ui_common.ToolButton(value=ui_common.refresh_symbol, elem_id="forge_refresh_checkpoint", tooltip="Refresh") refresh_button.click(fn=refresh_model_list, outputs=[ui_checkpoint, ui_vae], queue=False) + Context.root_block.load(fn=refresh_model_list, outputs=[ui_checkpoint, ui_vae], queue=False) - def model_on_load(): - ckpt_list, vae_list = refresh_models() - return [gr.update(value=shared.opts.sd_model_checkpoint, choices=ckpt_list), gr.update(value=[os.path.basename(x) for x in shared.opts.forge_additional_modules], choices=vae_list)] - - Context.root_block.load(fn=model_on_load, outputs=[ui_checkpoint, ui_vae], show_progress=False, queue=False) - - ui_forge_unet_dtype = gr.Dropdown(label="Diffusion in Low Bits", value=lambda: shared.opts.forge_unet_storage_dtype, choices=list(forge_unet_storage_dtype_options.keys())) + ui_forge_unet_dtype = gr.Dropdown(label="Diffusion in Low Bits", value=lambda: shared.opts.forge_unet_storage_dtype, choices=list(forge_unet_storage_dtype_options.keys()), elem_id="forge_ui_dtype") bind_to_opts(ui_forge_unet_dtype, "forge_unet_storage_dtype", save=True, callback=refresh_model_loading_parameters) ui_checkpoint.input(checkpoint_change, inputs=[ui_checkpoint, ui_forge_preset], queue=False, show_progress=False) @@ -159,7 +155,7 @@ def refresh_model_loading_parameters(*, refresh: bool = True): def checkpoint_change(ckpt_name: str, preset: str, save=True, refresh=True) -> bool: """`ckpt_name` accepts valid aliases; returns `True` if checkpoint changed""" new_ckpt_info = sd_models.get_closet_checkpoint_match(ckpt_name) - current_ckpt_info = sd_models.get_closet_checkpoint_match(shared.opts.data.get("sd_model_checkpoint", "")) + current_ckpt_info = sd_models.get_closet_checkpoint_match(getattr(shared.opts, "sd_model_checkpoint", "")) if new_ckpt_info == current_ckpt_info: return False @@ -177,13 +173,13 @@ def modules_change(module_values: list, preset: str, save=True, refresh=True) -> """`module_values` accepts file paths or just the module names; returns `True` if modules changed""" modules = [] for v in module_values: - module_name = os.path.basename(v) # If the input is a filepath, extract the file name + module_name = os.path.basename(v) # If the input is a filepath, extract the filename if module_name in module_list: modules.append(module_list[module_name]) modules.sort() # skip further processing if value unchanged - if modules == shared.opts.data.get("forge_additional_modules", []): + if modules == getattr(shared.opts, "forge_additional_modules", []): return False shared.opts.set("forge_additional_modules", modules) @@ -206,22 +202,27 @@ def get_a1111_ui_component(tab: str, label: str) -> gr.components.Component: def forge_main_entry(): shared.opts.set("VERSION_UID", launch_utils.VERSION_UID) - ui_txt2img_width = get_a1111_ui_component("txt2img", "Size-1") - ui_txt2img_height = get_a1111_ui_component("txt2img", "Size-2") - ui_txt2img_cfg = get_a1111_ui_component("txt2img", "CFG scale") - ui_txt2img_distilled_cfg = get_a1111_ui_component("txt2img", "Distilled CFG Scale") - ui_txt2img_sampler = get_a1111_ui_component("txt2img", "sampler_name") - ui_txt2img_scheduler = get_a1111_ui_component("txt2img", "scheduler") + ui_txt2img_steps = get_a1111_ui_component("txt2img", "Steps") + ui_txt2img_hr_steps = get_a1111_ui_component("txt2img", "Hires steps") + ui_img2img_steps = get_a1111_ui_component("img2img", "Steps") - ui_img2img_width = get_a1111_ui_component("img2img", "Size-1") - ui_img2img_height = get_a1111_ui_component("img2img", "Size-2") - ui_img2img_cfg = get_a1111_ui_component("img2img", "CFG scale") - ui_img2img_distilled_cfg = get_a1111_ui_component("img2img", "Distilled CFG Scale") + ui_txt2img_sampler = get_a1111_ui_component("txt2img", "sampler_name") ui_img2img_sampler = get_a1111_ui_component("img2img", "sampler_name") + ui_txt2img_scheduler = get_a1111_ui_component("txt2img", "scheduler") ui_img2img_scheduler = get_a1111_ui_component("img2img", "scheduler") + ui_txt2img_width = get_a1111_ui_component("txt2img", "Size-1") + ui_img2img_width = get_a1111_ui_component("img2img", "Size-1") + ui_txt2img_height = get_a1111_ui_component("txt2img", "Size-2") + ui_img2img_height = get_a1111_ui_component("img2img", "Size-2") + + ui_txt2img_cfg = get_a1111_ui_component("txt2img", "CFG scale") ui_txt2img_hr_cfg = get_a1111_ui_component("txt2img", "Hires CFG Scale") + ui_img2img_cfg = get_a1111_ui_component("img2img", "CFG scale") + + ui_txt2img_distilled_cfg = get_a1111_ui_component("txt2img", "Distilled CFG Scale") ui_txt2img_hr_distilled_cfg = get_a1111_ui_component("txt2img", "Hires Distilled CFG Scale") + ui_img2img_distilled_cfg = get_a1111_ui_component("img2img", "Distilled CFG Scale") ui_txt2img_batch_size = get_a1111_ui_component("txt2img", "Batch size") ui_img2img_batch_size = get_a1111_ui_component("img2img", "Batch size") @@ -230,20 +231,23 @@ def forge_main_entry(): ui_checkpoint, ui_vae, ui_forge_unet_dtype, + ui_txt2img_steps, + ui_txt2img_hr_steps, + ui_img2img_steps, + ui_txt2img_sampler, + ui_img2img_sampler, + ui_txt2img_scheduler, + ui_img2img_scheduler, ui_txt2img_width, ui_img2img_width, ui_txt2img_height, ui_img2img_height, ui_txt2img_cfg, + ui_txt2img_hr_cfg, ui_img2img_cfg, ui_txt2img_distilled_cfg, - ui_img2img_distilled_cfg, - ui_txt2img_sampler, - ui_img2img_sampler, - ui_txt2img_scheduler, - ui_img2img_scheduler, - ui_txt2img_hr_cfg, ui_txt2img_hr_distilled_cfg, + ui_img2img_distilled_cfg, ui_txt2img_batch_size, ui_img2img_batch_size, ] @@ -269,30 +273,43 @@ def on_preset_change(preset: str): shared.opts.set("forge_preset", preset) shared.opts.save(shared.config_filename) - additional_modules = [os.path.basename(x) for x in getattr(shared.opts, f"forge_additional_modules_{preset}", [])] + if use_shift(preset): + d_args = {"visible": True, "label": "Shift"} + elif use_distill(preset): + d_args = {"visible": True, "label": "Distilled CFG Scale"} + else: + d_args = {"visible": False} - extra_slider = preset in ("flux", "lumina", "wan") - distill_label = "Distilled CFG Scale" if preset == "flux" else "Shift" - batch_args = {"minimum": 1, "maximum": 97, "step": 16, "label": "Frames", "value": 1} if preset == "wan" else {"minimum": 1, "maximum": 8, "step": 1, "label": "Batch Size", "value": 1} + batch_args = {"minimum": 1, "maximum": 241, "step": 16, "label": "Frames", "value": 1} if preset == "wan" else {"minimum": 1, "maximum": 8, "step": 1, "label": "Batch Size", "value": 1} return [ - gr.update(value=getattr(shared.opts, f"forge_checkpoint_{preset}", shared.opts.sd_model_checkpoint)), # ui_checkpoint - gr.update(value=additional_modules), # ui_vae - gr.update(value=getattr(shared.opts, "forge_unet_storage_dtype", "Automatic")), # ui_forge_unet_dtype - gr.update(value=getattr(shared.opts, f"{preset}_t2i_width", 768)), # ui_txt2img_width - gr.update(value=getattr(shared.opts, f"{preset}_i2i_width", 768)), # ui_img2img_width - gr.update(value=getattr(shared.opts, f"{preset}_t2i_height", 768)), # ui_txt2img_height - gr.update(value=getattr(shared.opts, f"{preset}_i2i_height", 768)), # ui_img2img_height - gr.update(value=getattr(shared.opts, f"{preset}_t2i_cfg", 1.0)), # ui_txt2img_cfg - gr.update(value=getattr(shared.opts, f"{preset}_i2i_cfg", 1.0)), # ui_img2img_cfg - gr.update(visible=extra_slider, label=distill_label, value=getattr(shared.opts, f"{preset}_t2i_d_cfg", 3.0)), # ui_txt2img_distilled_cfg - gr.update(visible=extra_slider, label=distill_label, value=getattr(shared.opts, f"{preset}_i2i_d_cfg", 3.0)), # ui_img2img_distilled_cfg - gr.update(value=getattr(shared.opts, f"{preset}_t2i_sampler", "Euler")), # ui_txt2img_sampler - gr.update(value=getattr(shared.opts, f"{preset}_i2i_sampler", "Euler")), # ui_img2img_sampler - gr.update(value=getattr(shared.opts, f"{preset}_t2i_scheduler", "Simple")), # ui_txt2img_scheduler - gr.update(value=getattr(shared.opts, f"{preset}_i2i_scheduler", "Simple")), # ui_img2img_scheduler - gr.update(value=getattr(shared.opts, f"{preset}_t2i_hr_cfg", 1.0)), # ui_txt2img_hr_cfg - gr.update(visible=extra_slider, label=distill_label, value=getattr(shared.opts, f"{preset}_t2i_hr_d_cfg", 3.0)), # ui_txt2img_hr_distilled_cfg - gr.update(**batch_args), # ui_txt2img_batch_size - gr.update(**batch_args), # ui_img2img_batch_size + # ui_checkpoint, ui_vae, ui_forge_unet_dtype + gr.update(value=getattr(shared.opts, f"forge_checkpoint_{preset}", shared.opts.sd_model_checkpoint)), + gr.update(value=[os.path.basename(m) for m in getattr(shared.opts, f"forge_additional_modules_{preset}", [])]), + gr.update(value=getattr(shared.opts, "forge_unet_storage_dtype", "Automatic")), + # ui_txt2img_steps, ui_txt2img_hr_steps, ui_img2img_steps + gr.update(value=v) if (v := getattr(shared.opts, f"{preset}_t2i_step", 20)) > 0 else gr.skip(), + gr.update(value=v) if (v := getattr(shared.opts, f"{preset}_t2i_hr_step", 20)) > 0 else gr.skip(), + gr.update(value=v) if (v := getattr(shared.opts, f"{preset}_i2i_step", 20)) > 0 else gr.skip(), + # ui_txt2img_sampler, ui_img2img_sampler, ui_txt2img_scheduler, ui_img2img_scheduler + gr.update(value=getattr(shared.opts, f"{preset}_t2i_sampler", "Euler")), + gr.update(value=getattr(shared.opts, f"{preset}_i2i_sampler", "Euler")), + gr.update(value=getattr(shared.opts, f"{preset}_t2i_scheduler", "Simple")), + gr.update(value=getattr(shared.opts, f"{preset}_i2i_scheduler", "Simple")), + # ui_txt2img_width, ui_img2img_width, ui_txt2img_height, ui_img2img_height + gr.update(value=v) if (v := getattr(shared.opts, f"{preset}_t2i_width", 1024)) > 0 else gr.skip(), + gr.update(value=v) if (v := getattr(shared.opts, f"{preset}_i2i_width", 1024)) > 0 else gr.skip(), + gr.update(value=v) if (v := getattr(shared.opts, f"{preset}_t2i_height", 1024)) > 0 else gr.skip(), + gr.update(value=v) if (v := getattr(shared.opts, f"{preset}_i2i_height", 1024)) > 0 else gr.skip(), + # ui_txt2img_cfg, ui_txt2img_hr_cfg, ui_img2img_cfg + gr.update(value=v) if (v := getattr(shared.opts, f"{preset}_t2i_cfg", 1.0)) > 0 else gr.skip(), + gr.update(value=v) if (v := getattr(shared.opts, f"{preset}_t2i_hr_cfg", 1.0)) > 0 else gr.skip(), + gr.update(value=v) if (v := getattr(shared.opts, f"{preset}_i2i_cfg", 1.0)) > 0 else gr.skip(), + # ui_txt2img_distilled_cfg, ui_img2img_distilled_cfg, ui_txt2img_hr_distilled_cfg + gr.update(value=getattr(shared.opts, f"{preset}_t2i_dcfg", 3.0), **d_args), + gr.update(value=getattr(shared.opts, f"{preset}_t2i_hr_dcfg", 3.0), **d_args), + gr.update(value=getattr(shared.opts, f"{preset}_i2i_dcfg", 3.0), **d_args), + # ui_txt2img_batch_size, ui_img2img_batch_size + gr.update(**batch_args), + gr.update(**batch_args), ] diff --git a/modules_forge/presets.py b/modules_forge/presets.py index 1c224a8d..b9de8277 100644 --- a/modules_forge/presets.py +++ b/modules_forge/presets.py @@ -1,71 +1,90 @@ -from typing import TYPE_CHECKING, Callable - -if TYPE_CHECKING: - from modules.options import OptionInfo - from enum import Enum -import gradio as gr - -from modules.shared_items import list_samplers, list_schedulers - class PresetArch(Enum): - sd = 1 - xl = 2 - flux = 3 - qwen = 4 - lumina = 5 - wan = 6 + sd = 1 # SD1 + xl = 2 # SDXL + flux = 3 # Flux.1 + klein = 4 # Flux.2 + qwen = 5 # Qwen-Image + lumina = 6 # Lumina-Image-2.0 + zit = 7 # Z-Image-Turbo + wan = 8 # Wan2.2 + + @staticmethod + def choices() -> list[str]: + return [preset.name for preset in PresetArch] SAMPLERS = { PresetArch.sd: "Euler a", - PresetArch.xl: "DPM++ 2M SDE", + PresetArch.xl: "Euler a", PresetArch.flux: "Euler", + PresetArch.klein: "Euler", PresetArch.qwen: "LCM", PresetArch.lumina: "Res Multistep", + PresetArch.zit: "Euler", PresetArch.wan: "Euler", } SCHEDULERS = { PresetArch.sd: "Automatic", - PresetArch.xl: "Karras", + PresetArch.xl: "Automatic", PresetArch.flux: "Beta", + PresetArch.klein: "Beta", PresetArch.qwen: "Normal", - PresetArch.lumina: "Linear Quadratic", + PresetArch.lumina: "Simple", + PresetArch.zit: "Beta", PresetArch.wan: "Simple", } -WIDTH = { - PresetArch.sd: 512, - PresetArch.xl: 896, - PresetArch.flux: 896, - PresetArch.qwen: 896, - PresetArch.lumina: 1024, - PresetArch.wan: 1152, -} - -HEIGHT = { - PresetArch.sd: 512, - PresetArch.xl: 1152, - PresetArch.flux: 1152, - PresetArch.qwen: 1152, - PresetArch.lumina: 1024, - PresetArch.wan: 896, +STEPS = { + PresetArch.sd: 32, + PresetArch.xl: 24, + PresetArch.flux: 20, + PresetArch.klein: 4, + PresetArch.qwen: 8, + PresetArch.lumina: 32, + PresetArch.zit: 9, + PresetArch.wan: 4, } CFG = { PresetArch.sd: 6.0, - PresetArch.xl: 4.0, + PresetArch.xl: 4.5, PresetArch.flux: 1.0, + PresetArch.klein: 1.0, PresetArch.qwen: 1.0, - PresetArch.lumina: 4.5, + PresetArch.lumina: 4.0, + PresetArch.zit: 1.0, PresetArch.wan: 1.0, } +DISTILL = { + PresetArch.flux: 3.0, +} + +SHIFT = { + PresetArch.lumina: 6.0, + PresetArch.zit: 9.0, + PresetArch.wan: 5.0, +} + + +def use_distill(arch: str) -> bool: + return arch in [preset.name for preset in DISTILL.keys()] + + +def use_shift(arch: str) -> bool: + return arch in [preset.name for preset in SHIFT.keys()] + + +def register(options_templates: dict): + from gradio import Dropdown, Slider + + from modules.options import OptionInfo, OptionRow, options_section + from modules.shared_items import list_samplers, list_schedulers -def register(options_templates: dict, options_section: Callable, OptionInfo: "OptionInfo"): for arch in PresetArch: name = arch.name @@ -85,60 +104,88 @@ def register(options_templates: dict, options_section: Callable, OptionInfo: "Op options_section( (f"ui_{name}", name.upper(), "presets"), { - f"{name}_t2i_sampler": OptionInfo(sampler, "txt2img sampler", gr.Dropdown, lambda: {"choices": [x.name for x in list_samplers()]}), - f"{name}_t2i_scheduler": OptionInfo(scheduler, "txt2img scheduler", gr.Dropdown, lambda: {"choices": list_schedulers()}), - f"{name}_i2i_sampler": OptionInfo(sampler, "img2img sampler", gr.Dropdown, lambda: {"choices": [x.name for x in list_samplers()]}), - f"{name}_i2i_scheduler": OptionInfo(scheduler, "img2img scheduler", gr.Dropdown, lambda: {"choices": list_schedulers()}), + f"{name}_t2i_ss1": OptionRow(), + f"{name}_t2i_sampler": OptionInfo(sampler, "txt2img sampler", Dropdown, lambda: {"choices": [x.name for x in list_samplers()]}), + f"{name}_t2i_scheduler": OptionInfo(scheduler, "txt2img scheduler", Dropdown, lambda: {"choices": list_schedulers()}), + f"{name}_t2i_ss0": OptionRow(), + f"{name}_i2i_ss1": OptionRow(), + f"{name}_i2i_sampler": OptionInfo(sampler, "img2img sampler", Dropdown, lambda: {"choices": [x.name for x in list_samplers()]}), + f"{name}_i2i_scheduler": OptionInfo(scheduler, "img2img scheduler", Dropdown, lambda: {"choices": list_schedulers()}), + f"{name}_i2i_ss0": OptionRow(), }, ) ) - w, h, cfg = WIDTH[arch], HEIGHT[arch], CFG[arch] + step = STEPS[arch] options_templates.update( options_section( (f"ui_{name}", name.upper(), "presets"), { - f"{name}_t2i_width": OptionInfo(w, "txt2img Width", gr.Slider, {"minimum": 64, "maximum": 2048, "step": 8}), - f"{name}_t2i_height": OptionInfo(h, "txt2img Height", gr.Slider, {"minimum": 64, "maximum": 2048, "step": 8}), - f"{name}_t2i_cfg": OptionInfo(cfg, "txt2img CFG", gr.Slider, {"minimum": 1, "maximum": 30, "step": 0.1}), - f"{name}_t2i_hr_cfg": OptionInfo(cfg, "txt2img Hires. CFG", gr.Slider, {"minimum": 1, "maximum": 30, "step": 0.1}), - f"{name}_i2i_width": OptionInfo(w, "img2img Width", gr.Slider, {"minimum": 64, "maximum": 2048, "step": 8}), - f"{name}_i2i_height": OptionInfo(h, "img2img Height", gr.Slider, {"minimum": 64, "maximum": 2048, "step": 8}), - f"{name}_i2i_cfg": OptionInfo(cfg, "img2img CFG", gr.Slider, {"minimum": 1, "maximum": 30, "step": 0.1}), + f"{name}_steps1": OptionRow(), + f"{name}_t2i_step": OptionInfo(step, "txt2img Steps", Slider, {"minimum": 0, "maximum": 150, "step": 1}), + f"{name}_t2i_hr_step": OptionInfo(step, "txt2img Hires. Steps", Slider, {"minimum": 0, "maximum": 150, "step": 1}), + f"{name}_i2i_step": OptionInfo(step, "img2img Steps", Slider, {"minimum": 0, "maximum": 150, "step": 1}), + f"{name}_steps0": OptionRow(), }, ) ) - options_templates.update( - options_section( - ("ui_flux", "FLUX", "presets"), - { - "flux_t2i_d_cfg": OptionInfo(3.0, "txt2img Distilled CFG", gr.Slider, {"minimum": 1, "maximum": 10, "step": 0.1}), - "flux_t2i_hr_d_cfg": OptionInfo(3.0, "txt2img Distilled Hires. CFG", gr.Slider, {"minimum": 1, "maximum": 10, "step": 0.1}), - "flux_i2i_d_cfg": OptionInfo(3.0, "img2img Distilled CFG", gr.Slider, {"minimum": 1, "maximum": 10, "step": 0.1}), - }, - ) - ) + cfg = CFG[arch] - options_templates.update( - options_section( - ("ui_lumina", "LUMINA", "presets"), - { - "lumina_t2i_d_cfg": OptionInfo(6.0, "txt2img Shift", gr.Slider, {"minimum": 1, "maximum": 10, "step": 0.1}), - "lumina_t2i_hr_d_cfg": OptionInfo(6.0, "txt2img Hires. Shift", gr.Slider, {"minimum": 1, "maximum": 10, "step": 0.1}), - "lumina_i2i_d_cfg": OptionInfo(6.0, "img2img Shift", gr.Slider, {"minimum": 1, "maximum": 10, "step": 0.1}), - }, + options_templates.update( + options_section( + (f"ui_{name}", name.upper(), "presets"), + { + f"{name}_cfg1": OptionRow(), + f"{name}_t2i_cfg": OptionInfo(cfg, "txt2img CFG", Slider, {"minimum": 0, "maximum": 24, "step": 0.5}), + f"{name}_t2i_hr_cfg": OptionInfo(cfg, "txt2img Hires. CFG", Slider, {"minimum": 0, "maximum": 24, "step": 0.5}), + f"{name}_i2i_cfg": OptionInfo(cfg, "img2img CFG", Slider, {"minimum": 0, "maximum": 24, "step": 0.5}), + f"{name}_cfg0": OptionRow(), + }, + ) ) - ) - options_templates.update( - options_section( - ("ui_wan", "WAN", "presets"), - { - "wan_t2i_d_cfg": OptionInfo(8.0, "txt2img Shift", gr.Slider, {"minimum": 1, "maximum": 10, "step": 0.1}), - "wan_t2i_hr_d_cfg": OptionInfo(8.0, "txt2img Hires. Shift", gr.Slider, {"minimum": 1, "maximum": 10, "step": 0.1}), - "wan_i2i_d_cfg": OptionInfo(8.0, "img2img Shift", gr.Slider, {"minimum": 1, "maximum": 10, "step": 0.1}), - }, + if (distill := DISTILL.get(arch, None)) is not None: + options_templates.update( + options_section( + (f"ui_{name}", name.upper(), "presets"), + { + f"{name}_dcfg1": OptionRow(), + f"{name}_t2i_dcfg": OptionInfo(distill, "txt2img Distilled CFG", Slider, {"minimum": 1, "maximum": 24, "step": 0.5}), + f"{name}_t2i_hr_dcfg": OptionInfo(distill, "txt2img Hires. Distilled CFG", Slider, {"minimum": 1, "maximum": 24, "step": 0.5}), + f"{name}_i2i_dcfg": OptionInfo(distill, "img2img Distilled CFG", Slider, {"minimum": 1, "maximum": 24, "step": 0.5}), + f"{name}_dcfg0": OptionRow(), + }, + ) + ) + + if (shift := SHIFT.get(arch, None)) is not None: + options_templates.update( + options_section( + (f"ui_{name}", name.upper(), "presets"), + { + f"{name}_dcfg1": OptionRow(), + f"{name}_t2i_dcfg": OptionInfo(shift, "txt2img Shift", Slider, {"minimum": 1, "maximum": 24, "step": 0.5}), + f"{name}_t2i_hr_dcfg": OptionInfo(shift, "txt2img Hires. Shift", Slider, {"minimum": 1, "maximum": 24, "step": 0.5}), + f"{name}_i2i_dcfg": OptionInfo(shift, "img2img Shift", Slider, {"minimum": 1, "maximum": 24, "step": 0.5}), + f"{name}_dcfg0": OptionRow(), + }, + ) + ) + + options_templates.update( + options_section( + (f"ui_{name}", name.upper(), "presets"), + { + f"{name}_t2i_dim1": OptionRow(), + f"{name}_t2i_width": OptionInfo(0, "txt2img Width", Slider, {"minimum": 0, "maximum": 2048, "step": 64}), + f"{name}_i2i_width": OptionInfo(0, "img2img Width", Slider, {"minimum": 0, "maximum": 2048, "step": 64}), + f"{name}_t2i_dim0": OptionRow(), + f"{name}_i2i_dim1": OptionRow(), + f"{name}_t2i_height": OptionInfo(0, "txt2img Height", Slider, {"minimum": 0, "maximum": 2048, "step": 64}), + f"{name}_i2i_height": OptionInfo(0, "img2img Height", Slider, {"minimum": 0, "maximum": 2048, "step": 64}), + f"{name}_i2i_dim0": OptionRow(), + }, + ) ) - ) diff --git a/style.css b/style.css index 52dca48c..d746bc9d 100644 --- a/style.css +++ b/style.css @@ -1,10 +1,11 @@ /* temporary fix to load default gradio font in frontend instead of backend */ -@import url('webui-assets/css/sourcesanspro.css'); +@import url("webui-assets/css/sourcesanspro.css"); /* general gradio fixes */ -:root, .dark { +:root, +.dark { --checkbox-label-gap: 0.25em 0.1em; --section-header-text-size: 12pt; --block-background-fill: transparent; @@ -47,7 +48,8 @@ div.form { box-shadow: none !important; } -div.gradio-group, div.styler { +div.gradio-group, +div.styler { border-width: 0 !important; background: none; } @@ -74,7 +76,7 @@ div.compact { white-space: nowrap; } -@media (pointer:fine) { +@media (pointer: fine) { .gradio-dropdown ul.options li.item { padding: 0.05em 0; } @@ -133,7 +135,8 @@ div.gradio-html.min { width: 100%; } -.gradio-container .prose a, .gradio-container .prose a:visited { +.gradio-container .prose a, +.gradio-container .prose a:visited { color: unset; text-decoration: none; } @@ -153,7 +156,10 @@ a { } /* gradio 3.39 puts a lot of overflow: hidden all over the place for an unknown reason. */ -div.gradio-container, .block.gradio-textbox, div.gradio-group, div.gradio-dropdown { +div.gradio-container, +.block.gradio-textbox, +div.gradio-group, +div.gradio-dropdown { overflow: visible !important; } @@ -162,7 +168,6 @@ div.gradio-container, .block.gradio-textbox, div.gradio-group, div.gradio-dropdo align-content: flex-start; } - /* general styled components */ .gradio-button.tool { @@ -179,8 +184,11 @@ div.gradio-container, .block.gradio-textbox, div.gradio-group, div.gradio-dropdo color: var(--button-secondary-text-color); } -.gradio-button.secondary-down, .gradio-button.secondary-down:hover { - box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.25) inset, 0px 0px 3px rgba(0, 0, 0, 0.15) inset; +.gradio-button.secondary-down, +.gradio-button.secondary-down:hover { + box-shadow: + 1px 1px 1px rgba(0, 0, 0, 0.25) inset, + 0px 0px 3px rgba(0, 0, 0, 0.15) inset; } .gradio-button.secondary-down:hover { @@ -216,7 +224,6 @@ input[type="checkbox"].input-accordion-checkbox { margin-right: 0.5em; } - /* txt2img/img2img specific */ .block.token-counter { @@ -235,13 +242,17 @@ input[type="checkbox"].input-accordion-checkbox { .block.token-counter span { background: var(--input-background-fill) !important; - box-shadow: 0 0 0.0 0.3em rgba(192, 192, 192, 0.15), inset 0 0 0.6em rgba(192, 192, 192, 0.075); + box-shadow: + 0 0 0 0.3em rgba(192, 192, 192, 0.15), + inset 0 0 0.6em rgba(192, 192, 192, 0.075); border: 2px solid rgba(192, 192, 192, 0.4) !important; border-radius: 0.4em; } .block.token-counter.error span { - box-shadow: 0 0 0.0 0.3em rgba(255, 0, 0, 0.15), inset 0 0 0.6em rgba(255, 0, 0, 0.075); + box-shadow: + 0 0 0 0.3em rgba(255, 0, 0, 0.15), + inset 0 0 0.6em rgba(255, 0, 0, 0.075); border: 2px solid rgba(255, 0, 0, 0.4) !important; } @@ -253,18 +264,18 @@ input[type="checkbox"].input-accordion-checkbox { padding: 0.1em 0.75em; } -[id$=_subseed_show] { +[id$="_subseed_show"] { min-width: auto !important; flex-grow: 0 !important; display: flex; } -[id$=_subseed_show] label { +[id$="_subseed_show"] label { margin-bottom: 0.65em; align-self: end; } -[id$=_seed_extras]>div { +[id$="_seed_extras"]>div { gap: 0.5em; } @@ -286,7 +297,11 @@ input[type="checkbox"].input-accordion-checkbox { display: inline-block; } -.html-log .performance p.time, .performance p.vram, .performance p.profile, .performance p.time abbr, .performance p.vram abbr { +.html-log .performance p.time, +.performance p.vram, +.performance p.profile, +.performance p.time abbr, +.performance p.vram abbr { margin-bottom: 0; color: var(--block-title-text-color); } @@ -304,20 +319,25 @@ input[type="checkbox"].input-accordion-checkbox { font-weight: bold; } -#txt2img_generate, #img2img_generate { +#txt2img_generate, +#img2img_generate { min-height: 4.5em; } -#txt2img_generate, #img2img_generate { +#txt2img_generate, +#img2img_generate { min-height: 4.5em; } -.generate-box-compact #txt2img_generate, .generate-box-compact #img2img_generate { +.generate-box-compact #txt2img_generate, +.generate-box-compact #img2img_generate { min-height: 3em; } @media screen and (min-width: 2500px) { - #txt2img_gallery, #img2img_gallery { + + #txt2img_gallery, + #img2img_gallery { min-height: 768px; } } @@ -326,20 +346,23 @@ input[type="checkbox"].input-accordion-checkbox { object-fit: scale-down !important; } -#txt2img_actions_column, #img2img_actions_column { +#txt2img_actions_column, +#img2img_actions_column { gap: 0.5em; } -#txt2img_tools, #img2img_tools { +#txt2img_tools, +#img2img_tools { gap: 0.4em; } - .generate-box { position: relative; } -.gradio-button.generate-box-skip, .gradio-button.generate-box-interrupt, .gradio-button.generate-box-interrupting { +.gradio-button.generate-box-skip, +.gradio-button.generate-box-interrupt, +.gradio-button.generate-box-interrupting { position: absolute; width: 50%; height: 100%; @@ -347,11 +370,14 @@ input[type="checkbox"].input-accordion-checkbox { background: #b4c0cc; } -.gradio-button.generate-box-skip:hover, .gradio-button.generate-box-interrupt:hover, .gradio-button.generate-box-interrupting:hover { +.gradio-button.generate-box-skip:hover, +.gradio-button.generate-box-interrupt:hover, +.gradio-button.generate-box-interrupting:hover { background: #c2cfdb; } -.gradio-button.generate-box-interrupt, .gradio-button.generate-box-interrupting { +.gradio-button.generate-box-interrupt, +.gradio-button.generate-box-interrupting { left: 0; border-radius: 0.5rem 0 0 0.5rem; } @@ -366,11 +392,13 @@ input[type="checkbox"].input-accordion-checkbox { align-items: end; } -#txtimg_hr_finalres .resolution, #img2img_scale_resolution_preview .resolution { +#txtimg_hr_finalres .resolution, +#img2img_scale_resolution_preview .resolution { font-weight: bold; } -#txtimg_hr_finalres div.pending, #img2img_scale_resolution_preview div.pending { +#txtimg_hr_finalres div.pending, +#img2img_scale_resolution_preview div.pending { opacity: 1; transition: opacity 0s; } @@ -379,7 +407,7 @@ input[type="checkbox"].input-accordion-checkbox { opacity: 0.5; } -[id$=_column_batch] { +[id$="_column_batch"] { min-width: min(13.5em, 100%) !important; } @@ -425,11 +453,15 @@ div.toprow-compact-tools { /* settings */ #quicksettings { - --checkbox-label-padding: 6px 6px; + --checkbox-label-padding: 0.5em; align-items: flex-start; } -#quicksettings>div, #quicksettings>fieldset { +#quicksettings>* { + min-width: unset !important; +} + +#quicksettings>div { width: fit-content; flex: 0 1 fit-content; padding: 0; @@ -438,39 +470,93 @@ div.toprow-compact-tools { background: none; } -#quicksettings>div.model_selection { - min-width: 20em !important; +#quicksettings>button { + margin: auto 0; + margin-top: 1.5em; } -#quicksettings>div.model_selection input { - margin-left: 2% !important; - /* override the margin set for subdued */ - width: 100%; +#quicksettings div span[data-testid="block-info"] { + margin-bottom: 0.25em !important; } #quicksettings .icon-wrap { - margin-right: -4% !important; - background-color: var(--background-fill-secondary); + margin-right: -1em !important; + background: none; +} + +#quicksettings>div.gradio-dropdown input { + cursor: pointer; + padding-right: 1em; +} + +#quicksettings>div.model_selection ul { + border: var(--input-border-width) solid var(--input-border-color); + border-radius: var(--input-radius); + padding: 0 0.5em; } #quicksettings>div.model_selection li { overflow-x: visible !important; width: 100% !important; - /* Set size to max element */ + border-radius: 0 !important; } -#quicksettings .subdued { - display: block; +#quicksettings .gradio-slider { + min-width: 10em !important; + margin-top: 1em; +} + +#quicksettings .gradio-slider span { + margin-right: 1em; +} + +#quicksettings .gradio-slider input[type="range"] { + width: 100%; +} + +#quicksettings .gradio-checkbox { + margin-top: 2em; +} + +#forge_ui_preset input { + width: 4em; +} + +#setting_sd_model_checkpoint input { + width: 20em; +} + +#setting_sd_vae input { + width: 2em; + height: 18px !important; margin-left: auto; - width: 30px; } -#quicksettings div span[data-testid="block-info"] { - margin-bottom: unset !important; +#setting_sd_vae .icon-wrap { + position: absolute; + top: 50%; + transform: translateY(-50%); + right: var(--size-5); + color: var(--body-text-color); + width: var(--size-5); + pointer-events: none; } -#quicksettings>button { - margin: auto 0px; +#setting_sd_vae div.wrap-inner { + min-width: 20em; + height: 40px !important; + cursor: pointer; + padding: 0em 2em 0em 0.5em; +} + +#setting_sd_vae div.token { + height: 32px; + border-radius: 4px; + margin: auto; +} + +#forge_ui_dtype input { + width: 12em; } #settings { @@ -544,12 +630,17 @@ table.popup-table .link { color: var(--body-text-color); } -#settings .gradio-textbox, #settings .gradio-slider, #settings .gradio-number, #settings .gradio-dropdown, #settings .gradio-checkboxgroup, #settings .gradio-radio { +#settings .gradio-textbox, +#settings .gradio-slider, +#settings .gradio-number, +#settings .gradio-dropdown, +#settings .gradio-checkboxgroup, +#settings .gradio-radio { margin-top: 0.75em; } #settings span .settings-comment { - display: inline + display: inline; } .settings-comment a { @@ -602,7 +693,7 @@ table.popup-table .link { position: relative; } -[id$=_results].mobile { +[id$="_results"].mobile { margin-top: 28px; } @@ -740,7 +831,8 @@ table.popup-table .link { width: 1em; } -.modalControls span:hover, .modalControls span:focus { +.modalControls span:hover, +.modalControls span:focus { color: #999; text-decoration: none; } @@ -843,7 +935,6 @@ table.popup-table .link { background: var(--primary-700); } - /* extensions */ #tab_extensions table { @@ -852,7 +943,8 @@ table.popup-table .link { display: block; } -#tab_extensions table td, #tab_extensions table th { +#tab_extensions table td, +#tab_extensions table th { border: 1px solid #ccc; padding: 0.25em 0.5em; } @@ -883,7 +975,7 @@ table.popup-table .link { margin: 0.5em 0; display: flex; margin-top: auto; - opacity: 0.80; + opacity: 0.8; font-size: 90%; } @@ -957,7 +1049,7 @@ footer { margin-left: auto; } -.extra-networks>div>[id *='_extra_'] { +.extra-networks>div>[id*="_extra_"] { margin: 0.3em; } @@ -978,7 +1070,8 @@ footer { max-width: 12em; } -#txt2img_extra_view, #img2img_extra_view { +#txt2img_extra_view, +#img2img_extra_view { width: auto; } @@ -1053,7 +1146,8 @@ footer { height: 100%; } -.extra-network-pane .card, .standalone-card-preview.card { +.extra-network-pane .card, +.standalone-card-preview.card { display: inline-block; margin: 0.5rem; width: 16rem; @@ -1067,7 +1161,7 @@ footer { overflow: hidden; cursor: pointer; - background-image: url('./file=html/card-no-preview.jpg') + background-image: url("./file=html/card-no-preview.jpg"); } .extra-network-pane .card:hover { @@ -1153,7 +1247,8 @@ footer { text-align: left; } -.edit-user-metadata .file-metadata th, .edit-user-metadata .file-metadata td { +.edit-user-metadata .file-metadata th, +.edit-user-metadata .file-metadata td { padding: 0.3em 1em; overflow-wrap: anywhere; word-break: break-word; @@ -1200,10 +1295,11 @@ div.accordions>div.input-accordion.input-accordion-open { flex-flow: column; } - /* sticky right hand columns */ -#img2img_results, #txt2img_results, #extras_results { +#img2img_results, +#txt2img_results, +#extras_results { position: sticky; top: 0.5em; } @@ -1230,7 +1326,7 @@ body.resizing .resize-handle { } .resize-handle::after { - content: ''; + content: ""; position: absolute; top: 0; bottom: 0; @@ -1299,7 +1395,6 @@ body.resizing .resize-handle { overflow: hidden; } - .extra-network-pane .extra-network-cards::-webkit-scrollbar, .extra-network-pane .extra-network-tree::-webkit-scrollbar { background-color: transparent; @@ -1353,7 +1448,8 @@ body.resizing .resize-handle { .extra-network-tree .tree-list--subgroup { margin: 0 !important; padding: 0 !important; - box-shadow: 0.5rem 0 0 var(--body-background-fill) inset, + box-shadow: + 0.5rem 0 0 var(--body-background-fill) inset, 0.7rem 0 0 var(--neutral-800) inset; } @@ -1489,12 +1585,10 @@ body.resizing .resize-handle { line-height: 1rem; } - .extra-network-control .extra-network-control--search .extra-network-control--search-text::placeholder { color: var(--input-placeholder-color); } - /* clear button (x on right side) styling */ .extra-network-control .extra-network-control--search .extra-network-control--search-text::-webkit-search-cancel-button { -webkit-appearance: none; @@ -1653,7 +1747,6 @@ body.resizing .resize-handle { align-items: right; } - /* Icon for button when it is before label. */ .extra-network-tree .tree-list-item-visual--leading { grid-area: leading-visual; @@ -1703,24 +1796,14 @@ body.resizing .resize-handle { opacity: 0.25 !important; } -#quicksettings .gradio-slider span { - padding-right: 8px; -} - -#quicksettings .gradio-slider>div.wrap { - width: 200px; -} - -#quicksettings .gradio-slider input[type="range"] { - width: 200px; -} - -#txt2img_enable_mahiro, #img2img_enable_mahiro { +#txt2img_enable_mahiro, +#img2img_enable_mahiro { min-width: 0 !important; margin: auto 2em; } -#txt2img_prompt_container.prompt-container-scroll, #img2img_prompt_container.prompt-container-scroll { +#txt2img_prompt_container.prompt-container-scroll, +#img2img_prompt_container.prompt-container-scroll { display: flex; flex-direction: row; overflow: auto;