mirror of
https://github.com/vladmandic/sdnext.git
synced 2026-10-12 11:39:52 +00:00
659 lines
46 KiB
Python
659 lines
46 KiB
Python
import threading
|
|
import gradio as gr
|
|
from modules import shared, modelloader, ui_symbols, ui_common, sd_samplers
|
|
from modules.logger import log
|
|
from modules.ui_components import ToolButton
|
|
from modules.caption import caption
|
|
|
|
|
|
_save_timer = None
|
|
_save_lock = threading.Lock()
|
|
|
|
|
|
def create_toprow(
|
|
is_img2img: bool = False,
|
|
id_part: str | None = None,
|
|
generate_visible: bool = True,
|
|
negative_visible: bool = True,
|
|
reprocess_visible: bool = True,
|
|
schedule_visible: bool = True,
|
|
):
|
|
|
|
def apply_styles(prompt, prompt_neg, styles):
|
|
prompt = shared.prompt_styles.apply_styles_to_prompt(prompt, styles, wildcards=not shared.opts.extra_networks_apply_unparsed)
|
|
prompt_neg = shared.prompt_styles.apply_negative_styles_to_prompt(prompt_neg, styles, wildcards=not shared.opts.extra_networks_apply_unparsed)
|
|
return [gr.Textbox.update(value=prompt), gr.Textbox.update(value=prompt_neg), gr.Dropdown.update(value=[])]
|
|
|
|
def parse_style(styles):
|
|
if isinstance(styles, str):
|
|
styles = [x.strip() for x in styles.split('|') if x.strip() != '']
|
|
elif isinstance(styles, list):
|
|
styles = [x.strip() for x in styles if x.strip() != '']
|
|
else:
|
|
styles = None
|
|
return styles
|
|
|
|
if id_part is None:
|
|
id_part = "img2img" if is_img2img else "txt2img"
|
|
with gr.Row(elem_id=f"{id_part}_toprow", variant="compact"):
|
|
with gr.Column(elem_id=f"{id_part}_prompt_container", scale=4):
|
|
with gr.Row():
|
|
with gr.Column(scale=80):
|
|
with gr.Row(elem_id=f"{id_part}_prompt_row"):
|
|
prompt = gr.Textbox(elem_id=f"{id_part}_prompt", label="Prompt", show_label=False, lines=3 if negative_visible else 5, placeholder="Prompt", elem_classes=["prompt", "main-prompts"])
|
|
with gr.Row():
|
|
with gr.Column(scale=80):
|
|
with gr.Row(elem_id=f"{id_part}_negative_row"):
|
|
negative_prompt = gr.Textbox(elem_id=f"{id_part}_neg_prompt", label="Negative prompt", show_label=False, lines=3, placeholder="Negative prompt", elem_classes=["prompt", "main-prompts"], visible=negative_visible)
|
|
with gr.Column(scale=1, elem_id=f"{id_part}_actions_column"):
|
|
with gr.Row(elem_id=f"{id_part}_generate_box"):
|
|
reprocess = []
|
|
submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary', visible=generate_visible)
|
|
schedule = gr.Button('Schedule', elem_id=f"{id_part}_schedule", variant='primary', visible=schedule_visible)
|
|
if reprocess_visible:
|
|
reprocess.append(gr.Button('Reprocess', elem_id=f"{id_part}_reprocess", variant='primary', visible=True))
|
|
reprocess.append(gr.Button('Reprocess decode', elem_id=f"{id_part}_reprocess_decode", variant='primary', visible=False))
|
|
reprocess.append(gr.Button('Reprocess refine', elem_id=f"{id_part}_reprocess_refine", variant='primary', visible=False))
|
|
reprocess.append(gr.Button('Reprocess face', elem_id=f"{id_part}_reprocess_detail", variant='primary', visible=False))
|
|
with gr.Row(elem_id=f"{id_part}_generate_line2"):
|
|
interrupt = gr.Button('Stop', elem_id=f"{id_part}_interrupt")
|
|
interrupt.click(fn=lambda: shared.state.interrupt(), _js="requestInterrupt", inputs=[], outputs=[])
|
|
skip = gr.Button('Skip', elem_id=f"{id_part}_skip")
|
|
skip.click(fn=lambda: shared.state.skip(), inputs=[], outputs=[])
|
|
pause = gr.Button('Pause', elem_id=f"{id_part}_pause")
|
|
pause.click(fn=lambda: shared.state.pause(), _js='checkPaused', inputs=[], outputs=[])
|
|
with gr.Row(elem_id=f"{id_part}_tools"):
|
|
button_paste = gr.Button(value='Restore', variant='secondary', elem_id=f"{id_part}_paste") # symbols.paste
|
|
button_clear = gr.Button(value='Clear', variant='secondary', elem_id=f"{id_part}_clear_prompt_btn") # symbols.clear
|
|
button_extra = gr.Button(value='Networks', variant='secondary', elem_id=f"{id_part}_extra_networks_btn") # symbols.networks
|
|
button_clear.click(fn=lambda *x: ['', ''], inputs=[prompt, negative_prompt], outputs=[prompt, negative_prompt], show_progress='hidden')
|
|
with gr.Row(elem_id=f"{id_part}_counters"):
|
|
token_counter = gr.HTML(value="<span>0/75</span>", elem_id=f"{id_part}_token_counter", elem_classes=["token-counter"], visible=False)
|
|
token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button")
|
|
negative_token_counter = gr.HTML(value="<span>0/75</span>", elem_id=f"{id_part}_negative_token_counter", elem_classes=["token-counter"], visible=False)
|
|
negative_token_button = gr.Button(visible=False, elem_id=f"{id_part}_negative_token_button")
|
|
with gr.Row(elem_id=f"{id_part}_styles_row"):
|
|
styles = gr.Dropdown(label="Styles", elem_id=f"{id_part}_styles", choices=[style.name for style in shared.prompt_styles.styles.values()], value=[], multiselect=True)
|
|
_styles_btn_refresh = ui_common.create_refresh_button(styles, shared.prompt_styles.reload, lambda: {"choices": [style.name for style in shared.prompt_styles.styles.values()]}, f"{id_part}_styles_refresh")
|
|
styles_btn_select = ToolButton('Select', elem_id=f"{id_part}_styles_select", visible=False)
|
|
styles_btn_apply = ToolButton(ui_symbols.style_apply, elem_id=f"{id_part}_styles_apply", visible=True)
|
|
styles_btn_save = ToolButton(ui_symbols.style_save, elem_id=f"{id_part}_styles_save", visible=True)
|
|
styles_btn_select.click(_js="applyStyles", fn=parse_style, inputs=[styles], outputs=[styles], show_progress='hidden')
|
|
styles_btn_apply.click(fn=apply_styles, inputs=[prompt, negative_prompt, styles], outputs=[prompt, negative_prompt, styles], show_progress='hidden')
|
|
styles_btn_save.click(fn=lambda: None, _js='() => quickSaveStyle()', inputs=[], outputs=[], show_progress='hidden')
|
|
return prompt, styles, negative_prompt, submit, reprocess, button_paste, button_extra, token_counter, token_button, negative_token_counter, negative_token_button, schedule
|
|
|
|
|
|
def create_resolution_inputs(tab, default_width=1024, default_height=1024, step=8):
|
|
width = gr.Slider(minimum=64, maximum=4096, step=step, label="Width", value=default_width, elem_id=f"{tab}_width")
|
|
height = gr.Slider(minimum=64, maximum=4096, step=step, label="Height", value=default_height, elem_id=f"{tab}_height")
|
|
ar_list = ['AR'] + [x.strip() for x in shared.opts.aspect_ratios.split(',') if x.strip() != '']
|
|
gr.Dropdown(show_label=False, interactive=True, choices=ar_list, value=ar_list[0], elem_id=f"{tab}_ar", elem_classes=["ar-dropdown"]) # aspect-ratio linking wired client-side in ui/resolutionLock.ts
|
|
res_switch_btn = ToolButton(value=ui_symbols.switch, elem_id=f"{tab}_res_btn_swap")
|
|
res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress='hidden')
|
|
return width, height
|
|
|
|
|
|
def create_caption_button(tab: str, inputs: list | None = None, outputs: str | None = None, what: str = ''):
|
|
button_caption = gr.Button(ui_symbols.caption, elem_id=f"{tab}_caption_{what}", elem_classes=['caption', 'image-fit'])
|
|
if inputs is not None and outputs is not None:
|
|
button_caption.click(fn=caption.caption, inputs=inputs, outputs=[outputs])
|
|
return button_caption
|
|
|
|
|
|
def create_batch_inputs(tab, accordion=True):
|
|
with gr.Accordion(open=False, label="Batch", elem_id=f"{tab}_batch", elem_classes=["small-accordion"]) if accordion else gr.Group():
|
|
with gr.Row(elem_id=f"{tab}_row_batch"):
|
|
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id=f"{tab}_batch_count", scale=5)
|
|
batch_size = gr.Slider(minimum=1, maximum=32, step=1, label='Batch size', value=1, elem_id=f"{tab}_batch_size", scale=5)
|
|
return batch_count, batch_size
|
|
|
|
|
|
def create_seed_inputs(tab, reuse_visible=True, accordion=True, subseed_visible=True, seed_resize_visible=False):
|
|
with gr.Accordion(open=False, label="Seed", elem_id=f"{tab}_seed_group", elem_classes=["small-accordion"]) if accordion else gr.Group():
|
|
with gr.Row(elem_id=f"{tab}_seed_row", variant="compact"):
|
|
seed = gr.Number(label='Initial seed', value=-1, elem_id=f"{tab}_seed", container=True)
|
|
random_seed = ToolButton(ui_symbols.random, elem_id=f"{tab}_seed_random")
|
|
reuse_seed = ToolButton(ui_symbols.reuse, elem_id=f"{tab}_seed_reuse", visible=reuse_visible)
|
|
with gr.Row(elem_id=f"{tab}_subseed_row", variant="compact", visible=subseed_visible):
|
|
subseed = gr.Number(label='Variation', value=-1, elem_id=f"{tab}_subseed", container=True)
|
|
random_subseed = ToolButton(ui_symbols.random, elem_id=f"{tab}_subseed_random")
|
|
reuse_subseed = ToolButton(ui_symbols.reuse, elem_id=f"{tab}_subseed_reuse", visible=reuse_visible)
|
|
subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01, elem_id=f"{tab}_subseed_strength", elem_classes=["subseed-strength"])
|
|
with gr.Row(visible=seed_resize_visible):
|
|
seed_resize_from_w = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from width", value=0, elem_id=f"{tab}_seed_resize_from_w")
|
|
seed_resize_from_h = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from height", value=0, elem_id=f"{tab}_seed_resize_from_h")
|
|
random_seed.click(fn=lambda: -1, show_progress='hidden', inputs=[], outputs=[seed])
|
|
random_subseed.click(fn=lambda: -1, show_progress='hidden', inputs=[], outputs=[subseed])
|
|
return seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w
|
|
|
|
|
|
def create_video_inputs(tab:str, show_always:bool=False):
|
|
def video_type_change(video_type):
|
|
return [
|
|
gr.update(visible=video_type != 'None' or show_always),
|
|
gr.update(visible=video_type in ['GIF', 'PNG'] or show_always),
|
|
gr.update(visible=video_type not in ['None', 'GIF', 'PNG'] or show_always),
|
|
gr.update(visible=video_type not in ['None', 'GIF', 'PNG'] or show_always),
|
|
]
|
|
with gr.Row():
|
|
video_codecs = ['None', 'GIF', 'PNG', 'MP4/MP4V', 'MP4/AVC1', 'MP4/JVT3', 'MKV/H264', 'AVI/DIVX', 'AVI/RGBA', 'MJPEG/MJPG', 'MPG/MPG1', 'AVR/AVR1']
|
|
video_type = gr.Dropdown(label='Video format', choices=video_codecs, value='MP4/MP4V', elem_id=f"{tab}_video_type")
|
|
with gr.Row():
|
|
video_duration = gr.Slider(label='Video duration', minimum=0.25, maximum=300, step=0.25, value=2, visible=show_always, elem_id=f"{tab}_video_duration")
|
|
video_loop = gr.Checkbox(label='Loop video', value=True, visible=show_always, elem_id=f"{tab}_video_loop")
|
|
with gr.Row():
|
|
video_pad = gr.Slider(label='Pad frames', minimum=0, maximum=24, step=1, value=1, visible=show_always, elem_id=f"{tab}_video_pad")
|
|
video_interpolate = gr.Slider(label='Interpolate frames', minimum=0, maximum=24, step=1, value=0, visible=show_always, elem_id=f"{tab}_video_interpolate")
|
|
video_type.change(fn=video_type_change, inputs=[video_type], outputs=[video_duration, video_loop, video_pad, video_interpolate])
|
|
return video_type, video_duration, video_loop, video_pad, video_interpolate
|
|
|
|
|
|
def create_advanced_inputs(tab):
|
|
with gr.Accordion(open=False, label="Advanced", elem_id=f"{tab}_advanced", elem_classes=["small-accordion"]):
|
|
with gr.Group():
|
|
with gr.Row():
|
|
clip_skip = gr.Slider(label='CLiP skip', value=1, minimum=0, maximum=12, step=0.1, elem_id=f"{tab}_clip_skip", interactive=shared.opts.clip_skip_enabled)
|
|
with gr.Row(elem_id=f"{tab}_vae_options"):
|
|
vae_type = gr.Dropdown(label='VAE type', choices=['Full', 'Tiny', 'Remote'], value='Full', elem_id=f"{tab}_vae_type")
|
|
with gr.Row(elem_id=f"{tab}_advanced_options"):
|
|
tiling = gr.Checkbox(label='Texture tiling', value=False, elem_id=f"{tab}_tiling")
|
|
hidiffusion = gr.Checkbox(label='HiDiffusion', value=False, elem_id=f"{tab}_hidiffusion")
|
|
return vae_type, tiling, hidiffusion, clip_skip
|
|
|
|
|
|
def create_latent_inputs(tab):
|
|
# Latent Corrections (during diffusion)
|
|
with gr.Accordion(open=False, label="Latent Corrections", elem_id=f"{tab}_latent_corrections", elem_classes=["small-accordion"]):
|
|
with gr.Group():
|
|
with gr.Row(elem_id=f"{tab}_hdr_mode_row"):
|
|
hdr_mode = gr.Dropdown(label="Correction mode", choices=["Relative values", "Absolute values"], type="index", value="Relative values", elem_id=f"{tab}_hdr_mode", show_label=False)
|
|
hdr_apply_hires = gr.Checkbox(label="Apply to hires", value=True, elem_id=f"{tab}_hdr_apply_hires")
|
|
with gr.Row(elem_id=f"{tab}_correction_row"):
|
|
hdr_brightness = gr.Slider(minimum=-4.0, maximum=4.0, step=0.05, value=0, label="Latent brightness", elem_id=f"{tab}_hdr_brightness")
|
|
hdr_sharpen = gr.Slider(minimum=-4.0, maximum=4.0, step=0.05, value=0, label="Latent sharpen", elem_id=f"{tab}_hdr_sharpen")
|
|
hdr_color = gr.Slider(minimum=0.0, maximum=16.0, step=0.1, value=0.0, label="Latent color", elem_id=f"{tab}_hdr_color")
|
|
with gr.Row(elem_id=f"{tab}_hdr_clamp_row"):
|
|
hdr_clamp = gr.Checkbox(label="Latent clamp", value=False, elem_id=f"{tab}_hdr_clamp")
|
|
hdr_boundary = gr.Slider(minimum=0.0, maximum=10.0, step=0.1, value=4.0, label="Latent range", elem_id=f"{tab}_hdr_boundary")
|
|
hdr_threshold = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, value=0.95, label="Latent threshold", elem_id=f"{tab}_hdr_threshold")
|
|
with gr.Row(elem_id=f"{tab}_hdr_max_row"):
|
|
hdr_maximize = gr.Checkbox(label="Latent maximize", value=False, elem_id=f"{tab}_hdr_maximize")
|
|
hdr_max_center = gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=0.6, label="Latent center", elem_id=f"{tab}_hdr_max_center")
|
|
hdr_max_boundary = gr.Slider(minimum=0.5, maximum=2.0, step=0.1, value=1.0, label="Latent max range", elem_id=f"{tab}_hdr_max_boundary")
|
|
with gr.Row(elem_id=f"{tab}_hdr_color_row"):
|
|
hdr_color_picker = gr.ColorPicker(label="Latent tint", show_label=True, container=False, value=None, elem_id=f"{tab}_hdr_color_picker")
|
|
hdr_tint_ratio = gr.Slider(label="Tint strength", minimum=-4.0, maximum=4.0, step=0.05, value=0.0, elem_id=f"{tab}_hdr_tint_ratio")
|
|
return hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires
|
|
|
|
|
|
def create_color_inputs(tab):
|
|
# Color Grading (post-generation pixel-space)
|
|
with gr.Accordion(open=False, label="Color Grading", elem_id=f"{tab}_color_grading", elem_classes=["small-accordion"]):
|
|
with gr.Group():
|
|
with gr.Row(elem_id=f"{tab}_grading_basic_row"):
|
|
grading_brightness = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, value=0, label='Brightness', elem_id=f"{tab}_grading_brightness")
|
|
grading_contrast = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, value=0, label='Contrast', elem_id=f"{tab}_grading_contrast")
|
|
grading_saturation = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, value=0, label='Saturation', elem_id=f"{tab}_grading_saturation")
|
|
with gr.Row(elem_id=f"{tab}_grading_basic2_row"):
|
|
grading_hue = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, value=0, label='Hue', elem_id=f"{tab}_grading_hue")
|
|
grading_gamma = gr.Slider(minimum=0.1, maximum=10.0, step=0.1, value=1.0, label='Gamma', elem_id=f"{tab}_grading_gamma")
|
|
grading_sharpness = gr.Slider(minimum=0.0, maximum=2.0, step=0.05, value=0, label='Sharpness', elem_id=f"{tab}_grading_sharpness")
|
|
grading_color_temp = gr.Slider(minimum=2000, maximum=12000, step=100, value=6500, label='Color temp', elem_id=f"{tab}_grading_color_temp")
|
|
with gr.Group():
|
|
gr.HTML('<h3>Tone</h3>')
|
|
with gr.Row(elem_id=f"{tab}_grading_tone_row"):
|
|
grading_shadows = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, value=0, label='Shadows', elem_id=f"{tab}_grading_shadows")
|
|
grading_midtones = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, value=0, label='Midtones', elem_id=f"{tab}_grading_midtones")
|
|
grading_highlights = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, value=0, label='Highlights', elem_id=f"{tab}_grading_highlights")
|
|
with gr.Row(elem_id=f"{tab}_grading_clahe_row"):
|
|
grading_clahe_clip = gr.Slider(minimum=0.0, maximum=5.0, step=0.25, value=0, label='CLAHE clip', elem_id=f"{tab}_grading_clahe_clip")
|
|
grading_clahe_grid = gr.Slider(minimum=2, maximum=16, step=1, value=8, label='CLAHE grid', elem_id=f"{tab}_grading_clahe_grid")
|
|
with gr.Group():
|
|
with gr.Row(elem_id=f"{tab}_grading_split_row"):
|
|
grading_shadows_tint = gr.ColorPicker(label="Shadows tint", value="#000000", elem_id=f"{tab}_grading_shadows_tint")
|
|
grading_highlights_tint = gr.ColorPicker(label="Highlights tint", value="#ffffff", elem_id=f"{tab}_grading_highlights_tint")
|
|
grading_split_tone_balance = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, value=0.5, label='Split tone balance', elem_id=f"{tab}_grading_split_tone_balance")
|
|
with gr.Group():
|
|
gr.HTML('<h3>Effects</h3>')
|
|
with gr.Row(elem_id=f"{tab}_grading_effects_row"):
|
|
grading_vignette = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, value=0, label='Vignette', elem_id=f"{tab}_grading_vignette")
|
|
grading_grain = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, value=0, label='Grain', elem_id=f"{tab}_grading_grain")
|
|
with gr.Group():
|
|
gr.HTML('<h3>LUT</h3>')
|
|
with gr.Row(elem_id=f"{tab}_grading_lut_row"):
|
|
grading_lut_cube_file = gr.File(label='LUT .cube file', file_types=['.cube'], elem_id=f"{tab}_grading_lut_file")
|
|
grading_lut_strength = gr.Slider(minimum=0.0, maximum=2.0, step=0.05, value=1.0, label='LUT strength', elem_id=f"{tab}_grading_lut_strength")
|
|
return grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, grading_shadows, grading_midtones, grading_highlights, grading_clahe_clip, grading_clahe_grid, grading_shadows_tint, grading_highlights_tint, grading_split_tone_balance, grading_vignette, grading_grain, grading_lut_cube_file, grading_lut_strength
|
|
|
|
|
|
def sampler_choices(choices=None, selected='Default', same_as_primary=False):
|
|
"""Build display-only sampler choices without changing the sampler catalog."""
|
|
if choices is None:
|
|
sd_samplers.set_samplers()
|
|
choices = [sampler for sampler in sd_samplers.samplers if sampler.name != 'Same as primary']
|
|
names = [choice.name if hasattr(choice, 'name') else choice for choice in choices]
|
|
visible, filtered = ui_common.filter_ui_choices(names, shared.opts.show_samplers, selected)
|
|
if same_as_primary:
|
|
visible.insert(0, 'Same as primary')
|
|
value = selected if selected in visible else visible[0]
|
|
return visible, value, filtered
|
|
|
|
|
|
def upscaler_choices(choices, selected=None):
|
|
"""Build display-only upscaler choices without changing available upscalers."""
|
|
return ui_common.filter_ui_choices(choices, shared.opts.show_upscalers, selected)
|
|
|
|
|
|
def create_filter_indicator(tabname, kind, filtered):
|
|
if not filtered:
|
|
return None
|
|
indicator = ToolButton(value=ui_symbols.info, tooltip=f'{kind} list filtered', elem_id=f'{tabname}_{kind.lower()}_filter_indicator', elem_classes=['filter-indicator'])
|
|
indicator.click(fn=None, _js="() => openSettingsSection('ui')", inputs=[], outputs=[], show_progress='hidden')
|
|
return indicator
|
|
|
|
|
|
def create_sampler_and_steps_selection(choices, tabname, default_steps:int=20):
|
|
if choices is None:
|
|
sd_samplers.set_samplers()
|
|
choices = [x for x in sd_samplers.samplers if not x.name == 'Same as primary']
|
|
dropdown_choices, default_value, filtered = sampler_choices(choices)
|
|
with gr.Row(elem_id=f"{tabname}_sampler_row", elem_classes=['flex-break', 'flexbox']):
|
|
steps = gr.Slider(minimum=1, maximum=100, step=1, label="Steps", elem_id=f"{tabname}_steps", value=default_steps)
|
|
sampler_index = gr.Dropdown(label='Sampling method', elem_id=f"{tabname}_sampling", choices=dropdown_choices, value=default_value, type="value")
|
|
create_filter_indicator(tabname, 'Sampler', filtered)
|
|
_sampler_dropdowns[tabname] = sampler_index
|
|
return steps, sampler_index
|
|
|
|
|
|
_sampler_dropdowns = {}
|
|
|
|
|
|
def save_with_debounce(delay=0.5):
|
|
global _save_timer # pylint: disable=global-statement
|
|
with _save_lock:
|
|
try:
|
|
if _save_timer is not None and _save_timer.is_alive():
|
|
_save_timer.cancel()
|
|
except Exception as e:
|
|
log.error(f'Sampler: save debounce cancel error: {e}')
|
|
def _do_save():
|
|
try:
|
|
shared.opts.save(silent=True)
|
|
except Exception as e:
|
|
log.error(f'Sampler: save execution error: {e}')
|
|
|
|
_save_timer = threading.Timer(delay, _do_save)
|
|
_save_timer.start()
|
|
|
|
|
|
def sampler_ui_defaults(name):
|
|
from modules import sd_samplers_diffusers
|
|
|
|
sampler = next((item for item in sd_samplers_diffusers.samplers_data_diffusers if item.name == name), None)
|
|
if sampler is None or name == 'Default' or sampler.constructor is None:
|
|
return None
|
|
|
|
option_keys = {
|
|
'schedulers_sigma',
|
|
'schedulers_timestep_spacing',
|
|
'schedulers_beta_schedule',
|
|
'schedulers_prediction_type',
|
|
'schedulers_timesteps',
|
|
'schedulers_sigma_adjust',
|
|
'schedulers_sigma_adjust_min',
|
|
'schedulers_sigma_adjust_max',
|
|
'schedulers_solver_order',
|
|
'schedulers_shift',
|
|
'schedulers_base_shift',
|
|
'schedulers_max_shift',
|
|
'schedulers_base_image_seq_len',
|
|
'schedulers_max_image_seq_len',
|
|
'schedulers_use_loworder',
|
|
'schedulers_use_thresholding',
|
|
'schedulers_dynamic_shift',
|
|
'schedulers_rescale_betas',
|
|
}
|
|
values = {key: shared.opts.get_default(key) for key in option_keys}
|
|
model = shared.sd_model if shared.sd_loaded else None
|
|
scheduler = getattr(model, 'default_scheduler', None) if model is not None else None
|
|
scheduler = scheduler or (getattr(model, 'scheduler', None) if model is not None else None)
|
|
model_config = getattr(scheduler, 'config', None)
|
|
model_defaults = dict(model_config.items()) if model_config is not None and hasattr(model_config, 'items') else {}
|
|
|
|
defaults = dict(sd_samplers_diffusers.config.get('All', {}))
|
|
defaults.update(model_defaults)
|
|
defaults.update(sd_samplers_diffusers.config.get(name, {}))
|
|
defaults.update(sampler.options)
|
|
if 'num_train_timesteps' in defaults:
|
|
values['schedulers_timesteps'] = str(defaults['num_train_timesteps'])
|
|
if 'prediction_type' in defaults and 'Flow' in name and name not in sd_samplers_diffusers.flow_exclude:
|
|
defaults['prediction_type'] = 'flow_prediction'
|
|
if 'SGM' in name:
|
|
defaults['timestep_spacing'] = 'trailing'
|
|
|
|
prediction = defaults.get('prediction_type')
|
|
values['schedulers_prediction_type'] = {
|
|
'v-prediction': 'v_prediction',
|
|
}.get(prediction, prediction if prediction in {'epsilon', 'sample', 'v_prediction', 'flow_prediction'} else 'default')
|
|
spacing = defaults.get('timestep_spacing')
|
|
if spacing in {'linspace', 'leading', 'trailing'}:
|
|
values['schedulers_timestep_spacing'] = spacing
|
|
values['schedulers_beta_schedule'] = {
|
|
'linear': 'linear',
|
|
'scaled_linear': 'scaled',
|
|
'squaredcos_cap_v2': 'cosine',
|
|
'sigmoid': 'sigmoid',
|
|
}.get(defaults.get('beta_schedule'), 'default')
|
|
sigma = defaults.get('sigma_schedule')
|
|
if sigma not in {'karras', 'betas', 'exponential', 'lambdas', 'flowmatch'}:
|
|
sigma = next((value for key, value in (
|
|
('use_karras_sigmas', 'karras'),
|
|
('use_beta_sigmas', 'betas'),
|
|
('use_exponential_sigmas', 'exponential'),
|
|
('use_lu_lambdas', 'lambdas'),
|
|
('use_flow_sigmas', 'flowmatch'),
|
|
) if defaults.get(key)), 'default')
|
|
values['schedulers_sigma'] = sigma
|
|
|
|
mapping = {
|
|
'solver_order': 'schedulers_solver_order',
|
|
'lower_order_final': 'schedulers_use_loworder',
|
|
'thresholding': 'schedulers_use_thresholding',
|
|
'rescale_betas_zero_snr': 'schedulers_rescale_betas',
|
|
'use_dynamic_shifting': 'schedulers_dynamic_shift',
|
|
'base_image_seq_len': 'schedulers_base_image_seq_len',
|
|
'max_image_seq_len': 'schedulers_max_image_seq_len',
|
|
'sigma_adjust': 'schedulers_sigma_adjust',
|
|
'sigma_adjust_min': 'schedulers_sigma_adjust_min',
|
|
'sigma_adjust_max': 'schedulers_sigma_adjust_max',
|
|
'base_shift': 'schedulers_base_shift',
|
|
'max_shift': 'schedulers_max_shift',
|
|
}
|
|
for config_key, option_key in mapping.items():
|
|
if config_key in defaults:
|
|
values[option_key] = defaults[config_key]
|
|
for config_key in ('flow_shift', 'shift'):
|
|
if config_key in defaults:
|
|
values['schedulers_shift'] = defaults[config_key]
|
|
break
|
|
return values
|
|
|
|
|
|
def create_sampler_options(tabname):
|
|
saved_defaults = shared.opts.data.copy()
|
|
sampler_dropdown = _sampler_dropdowns.get(tabname)
|
|
selected_sampler = getattr(sampler_dropdown, 'value', 'Default')
|
|
sampler_defaults = sampler_ui_defaults(selected_sampler)
|
|
if selected_sampler == 'Default':
|
|
timesteps_value = saved_defaults.get('schedulers_timesteps', shared.opts.get_default('schedulers_timesteps'))
|
|
else:
|
|
timesteps_value = sampler_defaults['schedulers_timesteps'] if sampler_defaults is not None else shared.opts.get_default('schedulers_timesteps')
|
|
|
|
def set_sampler_options(sampler_options):
|
|
shared.opts.data['schedulers_dynamic_shift'] = 'dynamic' in sampler_options
|
|
shared.opts.data['schedulers_use_thresholding'] = 'thresholding' in sampler_options
|
|
shared.opts.data['schedulers_use_loworder'] = 'low order' in sampler_options
|
|
shared.opts.data['schedulers_rescale_betas'] = 'rescale' in sampler_options
|
|
log.debug(f'Sampler set options: {sampler_options}')
|
|
save_with_debounce()
|
|
|
|
def set_sampler_fallback(fallback):
|
|
log.debug(f'Sampler set options: fallback={fallback}')
|
|
shared.opts.schedulers_fallback = fallback
|
|
save_with_debounce()
|
|
|
|
def set_sampler_timesteps(timesteps):
|
|
log.debug(f'Sampler set options: timesteps={timesteps}')
|
|
shared.opts.schedulers_timesteps = timesteps
|
|
save_with_debounce()
|
|
|
|
def set_sampler_spacing(spacing):
|
|
log.debug(f'Sampler set options: spacing={spacing}')
|
|
shared.opts.schedulers_timestep_spacing = spacing
|
|
save_with_debounce()
|
|
|
|
def set_sampler_sigma(sampler_sigma):
|
|
log.debug(f'Sampler set options: sigma={sampler_sigma}')
|
|
shared.opts.schedulers_sigma = sampler_sigma
|
|
save_with_debounce()
|
|
|
|
def set_sampler_order(sampler_order):
|
|
log.debug(f'Sampler set options: order={sampler_order}')
|
|
shared.opts.schedulers_solver_order = sampler_order
|
|
save_with_debounce()
|
|
|
|
def set_sampler_prediction(sampler_prediction):
|
|
log.debug(f'Sampler set options: prediction={sampler_prediction}')
|
|
shared.opts.schedulers_prediction_type = sampler_prediction
|
|
save_with_debounce()
|
|
|
|
def set_sampler_shift(sampler_shift, sampler_base_shift, sampler_max_shift):
|
|
log.debug(f'Sampler set options: shift={sampler_shift} base={sampler_base_shift} max={sampler_max_shift}')
|
|
shared.opts.schedulers_shift = sampler_shift
|
|
shared.opts.schedulers_base_shift = sampler_base_shift
|
|
shared.opts.schedulers_max_shift = sampler_max_shift
|
|
save_with_debounce()
|
|
|
|
def set_sampler_seq_lens(base_image_seq_len, max_image_seq_len):
|
|
log.debug(f'Sampler set options: base_image_seq_len={base_image_seq_len} max_image_seq_len={max_image_seq_len}')
|
|
shared.opts.schedulers_base_image_seq_len = base_image_seq_len
|
|
shared.opts.schedulers_max_image_seq_len = max_image_seq_len
|
|
save_with_debounce()
|
|
|
|
def set_sigma_adjust(val, start, end):
|
|
log.debug(f'Sampler set options: sigma={val} min={start} max={end}')
|
|
shared.opts.schedulers_sigma_adjust = val
|
|
shared.opts.schedulers_sigma_adjust_min = start
|
|
shared.opts.schedulers_sigma_adjust_max = end
|
|
save_with_debounce()
|
|
|
|
# 'linear', 'scaled_linear', 'squaredcos_cap_v2'
|
|
def set_sampler_preset(preset):
|
|
if preset == 'AYS SD15':
|
|
timesteps = '999,850,736,645,545,455,343,233,124,24'
|
|
elif preset == 'AYS SDXL':
|
|
timesteps = '999,845,730,587,443,310,193,116,53,13'
|
|
else:
|
|
timesteps = ''
|
|
shared.opts.schedulers_timesteps = timesteps
|
|
save_with_debounce()
|
|
return timesteps
|
|
|
|
with gr.Row(elem_classes=['flex-break']):
|
|
sampler_sigma = gr.Dropdown(label='Sigma method', elem_id=f"{tabname}_sampler_sigma", choices=['default', 'karras', 'betas', 'exponential', 'lambdas', 'flowmatch'], value=shared.opts.schedulers_sigma, type='value')
|
|
sampler_spacing = gr.Dropdown(label='Timestep spacing', elem_id=f"{tabname}_sampler_spacing", choices=['default', 'linspace', 'leading', 'trailing'], value=shared.opts.schedulers_timestep_spacing, type='value')
|
|
with gr.Row(elem_classes=['flex-break']):
|
|
sampler_beta = gr.Dropdown(label='Beta schedule', elem_id=f"{tabname}_sampler_beta", choices=['default', 'linear', 'scaled', 'cosine', 'sigmoid'], value=shared.opts.schedulers_beta_schedule, type='value')
|
|
sampler_prediction = gr.Dropdown(label='Prediction method', elem_id=f"{tabname}_sampler_prediction", choices=['default', 'epsilon', 'sample', 'v_prediction', 'flow_prediction'], value=shared.opts.schedulers_prediction_type, type='value')
|
|
with gr.Row(elem_classes=['flex-break']):
|
|
sampler_presets = gr.Dropdown(label='Timesteps presets', elem_id=f"{tabname}_sampler_presets", choices=['None', 'AYS SD15', 'AYS SDXL'], value='None', type='value')
|
|
sampler_timesteps = gr.Textbox(label='Timesteps override', elem_id=f"{tabname}_sampler_timesteps", value=timesteps_value)
|
|
with gr.Row(elem_classes=['flex-break']):
|
|
sampler_sigma_adjust_val = gr.Slider(minimum=0.5, maximum=1.5, step=0.01, label='Sigma adjust', value=shared.opts.schedulers_sigma_adjust, elem_id=f"{tabname}_sampler_sigma_adjust")
|
|
sampler_sigma_adjust_min = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Adjust start', value=shared.opts.schedulers_sigma_adjust_min, elem_id=f"{tabname}_sampler_sigma_adjust_min")
|
|
sampler_sigma_adjust_max = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Adjust end', value=shared.opts.schedulers_sigma_adjust_max, elem_id=f"{tabname}_sampler_sigma_adjust_max")
|
|
with gr.Row(elem_classes=['flex-break']):
|
|
sampler_order = gr.Slider(minimum=0, maximum=5, step=1, label="Sampler order", value=shared.opts.schedulers_solver_order, elem_id=f"{tabname}_sampler_order")
|
|
with gr.Row(elem_classes=['flex-break']):
|
|
sampler_shift = gr.Slider(minimum=0, maximum=10, step=0.1, label="Flow shift", value=shared.opts.schedulers_shift, elem_id=f"{tabname}_sampler_shift")
|
|
sampler_base_shift = gr.Slider(minimum=0, maximum=10, step=0.01, label="Base shift", value=shared.opts.schedulers_base_shift, elem_id=f"{tabname}_sampler_base_shift")
|
|
sampler_max_shift = gr.Slider(minimum=0, maximum=10, step=0.01, label="Max shift", value=shared.opts.schedulers_max_shift, elem_id=f"{tabname}_sampler_max_shift")
|
|
with gr.Row(elem_classes=['flex-break']):
|
|
sampler_base_image_seq_len = gr.Slider(minimum=0, maximum=1024, step=16, label='Sampler base seq', value=shared.opts.schedulers_base_image_seq_len, elem_id=f"{tabname}_sampler_base_image_seq_len")
|
|
sampler_max_image_seq_len = gr.Slider(minimum=0, maximum=16284, step=16, label='Sampler max seq', value=shared.opts.schedulers_max_image_seq_len, elem_id=f"{tabname}_sampler_max_image_seq_len")
|
|
with gr.Row(elem_classes=['flex-break']):
|
|
options = ['low order', 'thresholding', 'dynamic', 'rescale']
|
|
values = []
|
|
values += ['low order'] if shared.opts.data.get('schedulers_use_loworder', True) else []
|
|
values += ['thresholding'] if shared.opts.data.get('schedulers_use_thresholding', False) else []
|
|
values += ['dynamic'] if shared.opts.data.get('schedulers_dynamic_shift', False) else []
|
|
values += ['rescale'] if shared.opts.data.get('schedulers_rescale_betas', False) else []
|
|
sampler_options = gr.CheckboxGroup(label='Options', elem_id=f"{tabname}_sampler_options", choices=options, value=values, type='value')
|
|
with gr.Row(elem_classes=['flex-break']):
|
|
sampler_fallback = gr.Checkbox(label='Fallback on invalid', value=shared.opts.schedulers_fallback, elem_id=f"{tabname}_sampler_fallback")
|
|
|
|
ui_fields = [
|
|
('schedulers_sigma', sampler_sigma),
|
|
('schedulers_timestep_spacing', sampler_spacing),
|
|
('schedulers_beta_schedule', sampler_beta),
|
|
('schedulers_prediction_type', sampler_prediction),
|
|
('sampler_presets', sampler_presets),
|
|
('schedulers_timesteps', sampler_timesteps),
|
|
('schedulers_sigma_adjust', sampler_sigma_adjust_val),
|
|
('schedulers_sigma_adjust_min', sampler_sigma_adjust_min),
|
|
('schedulers_sigma_adjust_max', sampler_sigma_adjust_max),
|
|
('schedulers_solver_order', sampler_order),
|
|
('schedulers_shift', sampler_shift),
|
|
('schedulers_base_shift', sampler_base_shift),
|
|
('schedulers_max_shift', sampler_max_shift),
|
|
('schedulers_base_image_seq_len', sampler_base_image_seq_len),
|
|
('schedulers_max_image_seq_len', sampler_max_image_seq_len),
|
|
('sampler_options', sampler_options),
|
|
]
|
|
|
|
def set_sampler_defaults(name):
|
|
if name == 'Default':
|
|
values = {
|
|
field[0]: saved_defaults.get(field[0], shared.opts.get_default(field[0]))
|
|
for field in ui_fields
|
|
if field[0] not in {'sampler_presets', 'sampler_options'}
|
|
}
|
|
values.update({
|
|
key: saved_defaults.get(key, shared.opts.get_default(key))
|
|
for key in (
|
|
'schedulers_use_loworder',
|
|
'schedulers_use_thresholding',
|
|
'schedulers_dynamic_shift',
|
|
'schedulers_rescale_betas',
|
|
)
|
|
})
|
|
shared.opts.schedulers_beta_schedule = values['schedulers_beta_schedule']
|
|
else:
|
|
values = sampler_ui_defaults(name)
|
|
if values is None:
|
|
return [gr.update() for _ in ui_fields]
|
|
values['schedulers_sigma'] = 'default'
|
|
shared.opts.schedulers_beta_schedule = 'default'
|
|
values['sampler_presets'] = 'None'
|
|
values['sampler_options'] = [
|
|
label for key, label in (
|
|
('schedulers_use_loworder', 'low order'),
|
|
('schedulers_use_thresholding', 'thresholding'),
|
|
('schedulers_dynamic_shift', 'dynamic'),
|
|
('schedulers_rescale_betas', 'rescale'),
|
|
) if values[key]
|
|
]
|
|
return [gr.update(value=values[field[0]]) for field in ui_fields]
|
|
|
|
sampler_dropdown = _sampler_dropdowns.get(tabname)
|
|
if sampler_dropdown is not None:
|
|
sampler_dropdown.change(fn=set_sampler_defaults, inputs=[sampler_dropdown], outputs=[field[1] for field in ui_fields])
|
|
|
|
sampler_sigma.input(fn=set_sampler_sigma, inputs=[sampler_sigma], outputs=[])
|
|
sampler_spacing.input(fn=set_sampler_spacing, inputs=[sampler_spacing], outputs=[])
|
|
sampler_presets.input(fn=set_sampler_preset, inputs=[sampler_presets], outputs=[sampler_timesteps])
|
|
sampler_timesteps.input(fn=set_sampler_timesteps, inputs=[sampler_timesteps], outputs=[])
|
|
sampler_prediction.input(fn=set_sampler_prediction, inputs=[sampler_prediction], outputs=[])
|
|
sampler_order.input(fn=set_sampler_order, inputs=[sampler_order], outputs=[])
|
|
sampler_shift.input(fn=set_sampler_shift, inputs=[sampler_shift, sampler_base_shift, sampler_max_shift], outputs=[])
|
|
sampler_base_shift.input(fn=set_sampler_shift, inputs=[sampler_shift, sampler_base_shift, sampler_max_shift], outputs=[])
|
|
sampler_max_shift.input(fn=set_sampler_shift, inputs=[sampler_shift, sampler_base_shift, sampler_max_shift], outputs=[])
|
|
sampler_options.input(fn=set_sampler_options, inputs=[sampler_options], outputs=[])
|
|
sampler_fallback.input(fn=set_sampler_fallback, inputs=[sampler_fallback], outputs=[])
|
|
sampler_sigma_adjust_val.input(fn=set_sigma_adjust, inputs=[sampler_sigma_adjust_val, sampler_sigma_adjust_min, sampler_sigma_adjust_max], outputs=[])
|
|
sampler_sigma_adjust_min.input(fn=set_sigma_adjust, inputs=[sampler_sigma_adjust_val, sampler_sigma_adjust_min, sampler_sigma_adjust_max], outputs=[])
|
|
sampler_sigma_adjust_max.input(fn=set_sigma_adjust, inputs=[sampler_sigma_adjust_val, sampler_sigma_adjust_min, sampler_sigma_adjust_max], outputs=[])
|
|
sampler_base_image_seq_len.input(fn=set_sampler_seq_lens, inputs=[sampler_base_image_seq_len, sampler_max_image_seq_len], outputs=[])
|
|
sampler_max_image_seq_len.input(fn=set_sampler_seq_lens, inputs=[sampler_base_image_seq_len, sampler_max_image_seq_len], outputs=[])
|
|
|
|
|
|
def create_hires_inputs(tab):
|
|
with gr.Accordion(open=False, label="Refine", elem_id=f"{tab}_refine_accordion", elem_classes=["small-accordion"]):
|
|
with gr.Row(elem_id=f"{tab}_hires_row1"):
|
|
enable_hr = gr.Checkbox(label='Enable refine pass', value=False, elem_id=f"{tab}_enable_hr")
|
|
hr_resize_mode, hr_upscaler, hr_resize_context, hr_resize_x, hr_resize_y, hr_scale, _selected_scale_tab = create_resize_inputs(tab, None, accordion=False, latent=True, non_zero=False)
|
|
with gr.Row(elem_id=f"{tab}_hires_fix_row2"):
|
|
hr_force = gr.Checkbox(label='Force HiRes', value=False, elem_id=f"{tab}_hr_force")
|
|
with gr.Row(elem_id=f"{tab}_hires_fix_row2"):
|
|
dropdown_choices, _default_value, filtered = sampler_choices(selected='Same as primary', same_as_primary=True)
|
|
hr_sampler_index = gr.Dropdown(label='Refine sampler', elem_id=f"{tab}_sampling_alt", choices=dropdown_choices, value='Same as primary', type="value")
|
|
create_filter_indicator(tab, 'Sampler', filtered)
|
|
with gr.Row(elem_id=f"{tab}_hires_row2"):
|
|
hr_second_pass_steps = gr.Slider(minimum=0, maximum=99, step=1, label='HiRes steps', elem_id=f"{tab}_steps_alt", value=20)
|
|
denoising_strength = gr.Slider(minimum=0.0, maximum=0.99, step=0.01, label='Strength', value=0.3, elem_id=f"{tab}_denoising_strength")
|
|
with gr.Row(elem_id=f"{tab}_refiner_row1"):
|
|
refiner_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Refiner start', value=0.0, elem_id=f"{tab}_refiner_start")
|
|
refiner_steps = gr.Slider(minimum=0, maximum=99, step=1, label="Refiner steps", elem_id=f"{tab}_refiner_steps", value=20)
|
|
refiner_prompt = gr.Textbox(value='', lines=2, label='Refine prompt', elem_id=f"{tab}_refiner_prompt", elem_classes=["prompt"], placeholder="refine prompt or leave empty to use main prompt")
|
|
refiner_negative = gr.Textbox(value='', lines=2, label='Refine negative prompt', elem_id=f"{tab}_refiner_neg_prompt", elem_classes=["prompt"], placeholder="refine negative prompt or leave empty to use main prompt")
|
|
return enable_hr, hr_sampler_index, denoising_strength, hr_resize_mode, hr_resize_context, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative
|
|
|
|
|
|
def create_resize_inputs(tab, images, accordion=True, latent=False, non_zero=True, prefix=''):
|
|
dummy_component = gr.Number(visible=False, value=0)
|
|
if len(prefix) > 0 and not prefix.startswith(' '):
|
|
prefix = f' {prefix}' if prefix != 'before' else ''
|
|
with gr.Accordion(open=False, label="Resize", elem_classes=["small-accordion"], elem_id=f"{tab}_resize_group") if accordion else gr.Group():
|
|
with gr.Row():
|
|
available_upscalers = [x.name for x in shared.sd_upscalers]
|
|
if len(available_upscalers) == 0:
|
|
available_upscalers = ['None']
|
|
if not latent:
|
|
available_upscalers = [x for x in available_upscalers if not x.lower().startswith('latent')]
|
|
available_upscalers, filtered = upscaler_choices(available_upscalers, available_upscalers[0])
|
|
resize_mode = gr.Dropdown(label=f"Mode{prefix}" if non_zero else "Resize mode", elem_id=f"{tab}_resize_mode", choices=shared.resize_modes, type="index", value='Fixed')
|
|
resize_name = gr.Dropdown(label=f"Method{prefix}" if non_zero else "Resize method", elem_id=f"{tab}_resize_name", choices=available_upscalers, value=available_upscalers[0], visible=True)
|
|
create_filter_indicator(tab, 'Upscaler', filtered)
|
|
resize_context_choices = ["Add with forward", "Remove with forward", "Add with backward", "Remove with backward"]
|
|
resize_context = gr.Dropdown(label=f"Context{prefix}", elem_id=f"{tab}_resize_context", choices=resize_context_choices, value=resize_context_choices[0], visible=False)
|
|
|
|
def refresh_upscaler_choices(selected):
|
|
modelloader.load_upscalers()
|
|
refreshed = [upscaler.name for upscaler in shared.sd_upscalers]
|
|
if not latent:
|
|
refreshed = [name for name in refreshed if not name.lower().startswith('latent')]
|
|
refreshed, _ = upscaler_choices(refreshed, selected)
|
|
value = selected if selected in refreshed else refreshed[0]
|
|
return gr.update(choices=refreshed, value=value)
|
|
|
|
resize_refresh_btn = ToolButton(value=ui_symbols.refresh, elem_id=f'{tab}_upscalers_refresh')
|
|
resize_refresh_btn.click(fn=refresh_upscaler_choices, inputs=[resize_name], outputs=[resize_name], show_progress='hidden')
|
|
|
|
def resize_mode_change(mode):
|
|
if mode is None or mode == 0:
|
|
return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
|
|
return gr.update(visible=mode != 5), gr.update(visible=mode == 5), gr.update(visible=mode != 5)
|
|
resize_mode.change(fn=resize_mode_change, inputs=[resize_mode], outputs=[resize_name, resize_context, resize_refresh_btn])
|
|
|
|
with gr.Row(visible=True) as _resize_group:
|
|
with gr.Column(elem_id=f"{tab}_column_size"):
|
|
selected_scale_tab = gr.State(value=0 if tab != 'img2img' else 1) # pylint: disable=abstract-class-instantiated
|
|
with gr.Tabs(elem_id=f"{tab}_scale_tabs", selected=0 if non_zero else 1):
|
|
with gr.Tab(label="Fixed", id=0, elem_id=f"{tab}_scale_tab_fixed") as tab_scale_to:
|
|
with gr.Row(elem_id=f"{tab}_resize_row_fixed"):
|
|
with gr.Column(elem_id=f"{tab}_column_fixed1", scale=6):
|
|
suffix = '_resize' if tab != 'img2img' else ''
|
|
width = gr.Slider(minimum=64 if non_zero else 0, maximum=8192, step=8, label=f"Width{prefix}" if non_zero else "Resize width", value=1024 if non_zero else 0, elem_id=f"{tab}{suffix}_width")
|
|
height = gr.Slider(minimum=64 if non_zero else 0, maximum=8192, step=8, label=f"Height{prefix}" if non_zero else "Resize height", value=1024 if non_zero else 0, elem_id=f"{tab}{suffix}_height")
|
|
with gr.Column(elem_id=f"{tab}_column_fixed2", scale=1):
|
|
ar_list = ['AR'] + [x.strip() for x in shared.opts.aspect_ratios.split(',') if x.strip() != '']
|
|
gr.Dropdown(show_label=False, interactive=True, choices=ar_list, value=ar_list[0], elem_id=f"{tab}_resize_ar", elem_classes=["ar-dropdown"]) # aspect-ratio linking wired client-side in ui/resolutionLock.ts
|
|
res_switch_btn = ToolButton(value=ui_symbols.switch, elem_id=f"{tab}_resize_size_swap")
|
|
res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress='hidden')
|
|
detect_image_size_btn = ToolButton(value=ui_symbols.detect, elem_id=f"{tab}_resize_detect_size")
|
|
el = tab.split('_')[0]
|
|
detect_image_size_btn.click(fn=lambda w, h, _: (w or gr.update(), h or gr.update()), _js=f'currentImageResolution{el}', inputs=[dummy_component, dummy_component, dummy_component], outputs=[width, height], show_progress='hidden')
|
|
# keep the kanvas stage synced to the resize sliders; .change fires on user and programmatic updates (detect, paste, swap) and writes nothing back
|
|
width.change(fn=None, _js='notifyKanvasResize', inputs=[width, height], outputs=[], show_progress='hidden')
|
|
height.change(fn=None, _js='notifyKanvasResize', inputs=[width, height], outputs=[], show_progress='hidden')
|
|
with gr.Tab(label="Scale", id=1, elem_id=f"{tab}_scale_tab_scale") as tab_scale_by:
|
|
scale_by = gr.Slider(minimum=0.05, maximum=8.0, step=0.05, label=f"Scale{prefix}" if non_zero else "Resize scale", value=1.0, elem_id=f"{tab}_scale")
|
|
if images is not None:
|
|
for component in images:
|
|
component.change(fn=lambda: None, _js="updateImg2imgResizeToTextAfterChangingImage", inputs=[], outputs=[], show_progress='hidden')
|
|
tab_scale_to.select(fn=lambda: 0, inputs=[], outputs=[selected_scale_tab])
|
|
tab_scale_by.select(fn=lambda: 1, inputs=[], outputs=[selected_scale_tab])
|
|
# resize_mode.change(fn=lambda x: gr.update(visible=x != 0), inputs=[resize_mode], outputs=[_resize_group])
|
|
return resize_mode, resize_name, resize_context, width, height, scale_by, selected_scale_tab
|