Preset System Overhaul

This commit is contained in:
Haoming 2026-02-09 11:19:38 +08:00 committed by GitHub
parent 3b9fbdeb1a
commit d1617a877e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 384 additions and 217 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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")

View File

@ -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:

View File

@ -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),
]

View File

@ -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(),
},
)
)
)

245
style.css
View File

@ -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);
}
/* <input> 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;