mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 09:14:35 +02:00
refactor(video): per-engine self-contained tab layout
Each engine tab (Generic, FramePack, LTX) now owns its own size, seed, frame count, and init imagery. The previously shared Size and Inputs subtabs are removed; persistent encoding settings move to a single Output subtab constructed first so engine tabs can consume its widgets. FramePack drops its local fps/interpolate sliders and consumes the shared Output widgets; LTX drops the redundant shared init_image parameter and keeps only its own ltx_init_image, with run_ltx's condition_image fallback removed in turn.
This commit is contained in:
@@ -12,7 +12,7 @@ def change_sections(duration, mp4_fps, mp4_interpolate, latent_ws, variant):
|
||||
return gr.update(value=f'Target video: {num_frames} frames in {num_sections} sections'), gr.update(lines=max(2, 2*num_sections//3))
|
||||
|
||||
|
||||
def create_ui(prompt, negative, styles, _overrides, init_image, last_image, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf):
|
||||
def create_ui(prompt, negative, styles, _overrides, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf):
|
||||
with gr.Row():
|
||||
with gr.Column(variant='compact', elem_id="framepack_settings", elem_classes=['settings-column'], scale=1):
|
||||
with gr.Row():
|
||||
@@ -22,11 +22,12 @@ def create_ui(prompt, negative, styles, _overrides, init_image, last_image, mp4_
|
||||
with gr.Row():
|
||||
resolution = gr.Slider(label="FP resolution", minimum=240, maximum=1088, value=640, step=16)
|
||||
duration = gr.Slider(label="FP duration", minimum=1, maximum=120, value=4, step=0.1)
|
||||
mp4_fps = gr.Slider(label="FP target FPS", minimum=1, maximum=60, value=24, step=1)
|
||||
mp4_interpolate = gr.Slider(label="FP interpolation", minimum=0, maximum=10, value=0, step=1)
|
||||
with gr.Row():
|
||||
section_html = gr.HTML(show_label=False, elem_id="framepack_section_html")
|
||||
with gr.Accordion(label="Inputs", open=False):
|
||||
with gr.Row():
|
||||
init_image = gr.Image(label='FP init image', elem_id='framepack_init_image', type='pil', image_mode='RGB', width=256, height=256)
|
||||
last_image = gr.Image(label='FP last image', elem_id='framepack_last_image', type='pil', image_mode='RGB', width=256, height=256)
|
||||
with gr.Row():
|
||||
start_weight = gr.Slider(label="FP init strength", value=1.0, minimum=0.0, maximum=2.0, step=0.05, elem_id="framepack_start_weight")
|
||||
end_weight = gr.Slider(label="FP end strength", value=1.0, minimum=0.0, maximum=2.0, step=0.05, elem_id="framepack_end_weight")
|
||||
|
||||
@@ -122,7 +122,6 @@ def run_ltx(task_id,
|
||||
refine_strength: float,
|
||||
condition_strength: float,
|
||||
ltx_init_image,
|
||||
condition_image,
|
||||
condition_last,
|
||||
condition_files,
|
||||
condition_video,
|
||||
@@ -213,15 +212,13 @@ def run_ltx(task_id,
|
||||
from modules.video_models import models_def, video_overrides
|
||||
selected = next((m for m in models_def.models.get(engine, []) if m.name == model), None)
|
||||
|
||||
effective_init_image = ltx_init_image if ltx_init_image is not None else condition_image
|
||||
|
||||
if caps.is_i2v and caps.repo_cls_name in ('LTXImageToVideoPipeline', 'LTX2ImageToVideoPipeline') and effective_init_image is None:
|
||||
if caps.is_i2v and caps.repo_cls_name in ('LTXImageToVideoPipeline', 'LTX2ImageToVideoPipeline') and ltx_init_image is None:
|
||||
yield from abort('No input image provided. Please upload or select an image.', ok=True)
|
||||
return
|
||||
|
||||
condition_images = []
|
||||
if effective_init_image is not None:
|
||||
condition_images.append(effective_init_image)
|
||||
if ltx_init_image is not None:
|
||||
condition_images.append(ltx_init_image)
|
||||
if condition_last is not None:
|
||||
condition_images.append(condition_last)
|
||||
conditions = []
|
||||
@@ -254,7 +251,7 @@ def run_ltx(task_id,
|
||||
frames=get_frames(frames),
|
||||
cfg_scale=float(guidance_scale) if guidance_scale is not None and guidance_scale > 0 else caps.default_cfg,
|
||||
denoising_strength=float(condition_strength) if condition_strength is not None else 1.0,
|
||||
init_image=effective_init_image,
|
||||
init_image=ltx_init_image,
|
||||
vae_type='Default',
|
||||
vae_tile_frames=16,
|
||||
)
|
||||
@@ -279,9 +276,9 @@ def run_ltx(task_id,
|
||||
if caps.supports_multi_condition and conditions:
|
||||
p.task_args['conditions'] = conditions
|
||||
|
||||
if caps.is_i2v and caps.repo_cls_name in ('LTXImageToVideoPipeline', 'LTX2ImageToVideoPipeline') and effective_init_image is not None:
|
||||
if caps.is_i2v and caps.repo_cls_name in ('LTXImageToVideoPipeline', 'LTX2ImageToVideoPipeline') and ltx_init_image is not None:
|
||||
from modules import images
|
||||
p.task_args['image'] = images.resize_image(resize_mode=2, im=effective_init_image, width=p.width, height=p.height, upscaler_name=None, output_type='pil')
|
||||
p.task_args['image'] = images.resize_image(resize_mode=2, im=ltx_init_image, width=p.width, height=p.height, upscaler_name=None, output_type='pil')
|
||||
|
||||
if caps.family == '2.x' and caps.is_distilled:
|
||||
from diffusers.pipelines.ltx2.utils import DISTILLED_SIGMA_VALUES
|
||||
|
||||
+13
-3
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
import gradio as gr
|
||||
from modules import ui_sections
|
||||
from modules import ui_sections, ui_symbols
|
||||
from modules.ui_components import ToolButton
|
||||
from modules.logger import log
|
||||
from modules.video_models.models_def import models
|
||||
from modules.ltx import ltx_process, ltx_capabilities
|
||||
@@ -48,7 +49,7 @@ def _model_change(model_name: str):
|
||||
)
|
||||
|
||||
|
||||
def create_ui(prompt, negative, styles, overrides, init_image, _init_strength, last_image, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, width, height, frames, seed):
|
||||
def create_ui(prompt, negative, styles, overrides, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf):
|
||||
with gr.Row():
|
||||
with gr.Column(variant='compact', elem_id="ltx_settings", elem_classes=['settings-column'], scale=1):
|
||||
with gr.Row():
|
||||
@@ -56,10 +57,19 @@ def create_ui(prompt, negative, styles, overrides, init_image, _init_strength, l
|
||||
with gr.Row():
|
||||
ltx_models = [m.name for m in models['LTX Video']] if 'LTX Video' in models else ['None']
|
||||
model = gr.Dropdown(label='LTX model', choices=ltx_models, value=ltx_models[0], elem_id="ltx_model")
|
||||
with gr.Accordion(open=False, label='Size', elem_id='ltx_size_accordion'):
|
||||
width, height = ui_sections.create_resolution_inputs('ltx', default_width=832, default_height=480)
|
||||
with gr.Row():
|
||||
frames = gr.Slider(label='Frames', minimum=1, maximum=1024, step=1, value=121, elem_id='ltx_frames')
|
||||
seed = gr.Number(label='Initial seed', value=-1, elem_id='ltx_seed', container=True)
|
||||
random_seed = ToolButton(ui_symbols.random, elem_id='ltx_seed_random')
|
||||
random_seed.click(fn=lambda: -1, show_progress='hidden', inputs=[], outputs=[seed])
|
||||
input_media_accordion = gr.Accordion(open=False, label="Input media", elem_id='ltx_input_media_accordion', visible=False)
|
||||
with input_media_accordion:
|
||||
ltx_init_image = gr.Image(label='Image', elem_id='ltx_init_image', type='pil', image_mode='RGB', width=256, height=256)
|
||||
ltx_condition_strength = gr.Slider(label='LTX input strength', minimum=0.0, maximum=1.0, step=0.05, value=1.0, elem_id='ltx_condition_strength')
|
||||
with gr.Row():
|
||||
last_image = gr.Image(label='Last image', elem_id='ltx_last_image', type='pil', image_mode='RGB', width=256, height=256)
|
||||
multi_condition_group = gr.Group(visible=False)
|
||||
with multi_condition_group:
|
||||
gr.Markdown('**Prefix conditioning**: supply a video or gallery to anchor the opening frames', elem_id='ltx_prefix_conditioning_label')
|
||||
@@ -137,7 +147,7 @@ def create_ui(prompt, negative, styles, overrides, init_image, _init_strength, l
|
||||
seed,
|
||||
upsample_enable, upsample_ratio,
|
||||
refine_enable, refine_strength,
|
||||
ltx_condition_strength, ltx_init_image, init_image, last_image, condition_files, condition_video, condition_video_frames, condition_video_skip,
|
||||
ltx_condition_strength, ltx_init_image, last_image, condition_files, condition_video, condition_video_frames, condition_video_skip,
|
||||
decode_timestep, image_cond_noise_scale,
|
||||
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf,
|
||||
audio_enable,
|
||||
|
||||
+14
-11
@@ -28,24 +28,27 @@ def create_ui():
|
||||
with gr.Row(elem_id="video_interface", equal_height=False):
|
||||
with gr.Tabs(elem_classes=['video-tabs'], elem_id='video-tabs'):
|
||||
overrides = ui_common.create_override_inputs('video')
|
||||
with gr.Tab('Size', id='video-size-tab') as _video_size_tab:
|
||||
from modules.video_models import video_ui
|
||||
width, height, frames, seed, reuse_seed = video_ui.create_ui_size()
|
||||
with gr.Tab('Inputs', id='video-inputs-tab') as _video_inputs_tab:
|
||||
from modules.video_models import video_ui
|
||||
init_image, init_strength, last_image = video_ui.create_ui_inputs()
|
||||
with gr.Tab('Video Output', id='video-outputs-tab') as _video_outputs_tab:
|
||||
with gr.Tab('Output', id='video-outputs-tab') as _video_outputs_tab:
|
||||
from modules.video_models import video_ui
|
||||
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf = video_ui.create_ui_outputs()
|
||||
with gr.Tab('Models', id='video-core-tab') as video_core_tab:
|
||||
with gr.Tab('Generic', id='video-core-tab') as video_core_tab:
|
||||
from modules.video_models import video_ui
|
||||
engine, model, steps, sampler_index = video_ui.create_ui(prompt, negative, styles, overrides, init_image, init_strength, last_image, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, width, height, frames, seed, reuse_seed)
|
||||
engine, model, steps, sampler_index, width, height, frames, seed = video_ui.create_ui(
|
||||
prompt, negative, styles, overrides,
|
||||
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf,
|
||||
)
|
||||
with gr.Tab('FramePack', id='framepack-tab') as framepack_tab:
|
||||
from modules.framepack import framepack_ui
|
||||
framepack_ui.create_ui(prompt, negative, styles, overrides, init_image, last_image, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf)
|
||||
framepack_ui.create_ui(
|
||||
prompt, negative, styles, overrides,
|
||||
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf,
|
||||
)
|
||||
with gr.Tab('LTX', id='ltx-tab') as ltx_tab:
|
||||
from modules.ltx import ltx_ui
|
||||
ltx_ui.create_ui(prompt, negative, styles, overrides, init_image, init_strength, last_image, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, width, height, frames, seed)
|
||||
ltx_ui.create_ui(
|
||||
prompt, negative, styles, overrides,
|
||||
mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf,
|
||||
)
|
||||
|
||||
paste_fields = [
|
||||
(prompt, "Prompt"), # cannot add more fields as they are not defined yet
|
||||
|
||||
@@ -86,17 +86,6 @@ def run_video(*args):
|
||||
return video_utils.queue_err(f'model not found: engine="{engine}" model="{model}"')
|
||||
|
||||
|
||||
def create_ui_inputs():
|
||||
with gr.Row():
|
||||
with gr.Column(variant='compact', elem_id="video_inputs", elem_classes=['settings-column'], scale=1):
|
||||
init_strength = gr.Slider(label='Init strength', minimum=0.0, maximum=1.0, step=0.01, value=0.8, elem_id="video_denoising_strength")
|
||||
gr.HTML("<br>  Init image")
|
||||
init_image = gr.Image(elem_id="video_image", show_label=False, type="pil", image_mode="RGB", width=256, height=256)
|
||||
gr.HTML("<br>  Last image")
|
||||
last_image = gr.Image(elem_id="video_last", show_label=False, type="pil", image_mode="RGB", width=256, height=256)
|
||||
return init_image, init_strength, last_image
|
||||
|
||||
|
||||
def create_ui_outputs():
|
||||
with gr.Row():
|
||||
with gr.Column(variant='compact', elem_id="video_outputs", elem_classes=['settings-column'], scale=1):
|
||||
@@ -105,31 +94,17 @@ def create_ui_outputs():
|
||||
mp4_interpolate = gr.Slider(label="Video interpolation", minimum=0, maximum=10, value=0, step=1)
|
||||
with gr.Row():
|
||||
mp4_codec = gr.Dropdown(label="Video codec", choices=['none', 'libx264'], value='libx264', type='value')
|
||||
ui_common.create_refresh_button(mp4_codec, video_utils.get_codecs, elem_id="framepack_mp4_codec_refresh")
|
||||
mp4_ext = gr.Textbox(label="Video format", value='mp4', elem_id="framepack_mp4_ext")
|
||||
mp4_opt = gr.Textbox(label="Video options", value='crf:16', elem_id="framepack_mp4_opt")
|
||||
ui_common.create_refresh_button(mp4_codec, video_utils.get_codecs, elem_id="video_mp4_codec_refresh")
|
||||
mp4_ext = gr.Textbox(label="Video format", value='mp4', elem_id="video_mp4_ext")
|
||||
mp4_opt = gr.Textbox(label="Video options", value='crf:16', elem_id="video_mp4_opt")
|
||||
with gr.Row():
|
||||
mp4_video = gr.Checkbox(label='Video save video', value=True, elem_id="framepack_mp4_video")
|
||||
mp4_frames = gr.Checkbox(label='Video save frames', value=False, elem_id="framepack_mp4_frames")
|
||||
mp4_sf = gr.Checkbox(label='Video save safetensors', value=False, elem_id="framepack_mp4_sf")
|
||||
mp4_video = gr.Checkbox(label='Video save video', value=True, elem_id="video_mp4_video")
|
||||
mp4_frames = gr.Checkbox(label='Video save frames', value=False, elem_id="video_mp4_frames")
|
||||
mp4_sf = gr.Checkbox(label='Video save safetensors', value=False, elem_id="video_mp4_sf")
|
||||
return mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf
|
||||
|
||||
|
||||
def create_ui_size():
|
||||
with gr.Row():
|
||||
with gr.Column(variant='compact', elem_id="video_size", elem_classes=['settings-column'], scale=1):
|
||||
with gr.Row():
|
||||
width, height = ui_sections.create_resolution_inputs('video', default_width=832, default_height=480)
|
||||
with gr.Row():
|
||||
frames = gr.Slider(label='Frames', minimum=1, maximum=1024, step=1, value=17, elem_id="video_frames")
|
||||
seed = gr.Number(label='Initial seed', value=-1, elem_id="video_seed", container=True)
|
||||
random_seed = ToolButton(ui_symbols.random, elem_id="video_seed_random")
|
||||
reuse_seed = ToolButton(ui_symbols.reuse, elem_id="video_seed_reuse")
|
||||
random_seed.click(fn=lambda: -1, show_progress='hidden', inputs=[], outputs=[seed])
|
||||
return width, height, frames, seed, reuse_seed
|
||||
|
||||
|
||||
def create_ui(prompt, negative, styles, overrides, init_image, init_strength, last_image, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, width, height, frames, seed, reuse_seed):
|
||||
def create_ui(prompt, negative, styles, overrides, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf):
|
||||
with gr.Row():
|
||||
with gr.Column(variant='compact', elem_id="video_settings", elem_classes=['settings-column'], scale=1):
|
||||
with gr.Row():
|
||||
@@ -138,7 +113,7 @@ def create_ui(prompt, negative, styles, overrides, init_image, init_strength, la
|
||||
engine = gr.Dropdown(label='Video engine', choices=visible_engines(), value='None', elem_id="video_engine")
|
||||
model = gr.Dropdown(label='Video model', choices=[''], value='None', elem_id="video_model")
|
||||
btn_load = ToolButton(ui_symbols.loading, elem_id="video_model_load")
|
||||
with gr.Row():
|
||||
with gr.Accordion(open=True, label="Model", elem_id='video_model_accordion'):
|
||||
url = gr.HTML(label='Model URL', elem_id='video_model_url', value='<br><br>')
|
||||
with gr.Accordion(open=False, label="Parameters", elem_id='video_parameters_accordion'):
|
||||
steps, sampler_index = ui_sections.create_sampler_and_steps_selection(None, "video", default_steps=50)
|
||||
@@ -148,6 +123,21 @@ def create_ui(prompt, negative, styles, overrides, init_image, init_strength, la
|
||||
with gr.Row():
|
||||
guidance_scale = gr.Slider(label='Guidance scale', minimum=-1.0, maximum=14.0, step=0.1, value=-1.0, elem_id="video_guidance_scale")
|
||||
guidance_true = gr.Slider(label='True guidance', minimum=-1.0, maximum=14.0, step=0.1, value=-1.0, elem_id="video_guidance_true")
|
||||
with gr.Accordion(open=False, label="Size", elem_id='video_size_accordion'):
|
||||
with gr.Row():
|
||||
width, height = ui_sections.create_resolution_inputs('video', default_width=832, default_height=480)
|
||||
with gr.Row():
|
||||
frames = gr.Slider(label='Frames', minimum=1, maximum=1024, step=1, value=17, elem_id="video_frames")
|
||||
seed = gr.Number(label='Initial seed', value=-1, elem_id="video_seed", container=True)
|
||||
random_seed = ToolButton(ui_symbols.random, elem_id="video_seed_random")
|
||||
reuse_seed = ToolButton(ui_symbols.reuse, elem_id="video_seed_reuse")
|
||||
random_seed.click(fn=lambda: -1, show_progress='hidden', inputs=[], outputs=[seed])
|
||||
with gr.Accordion(open=False, label="Inputs", elem_id='video_inputs_accordion'):
|
||||
init_strength = gr.Slider(label='Init strength', minimum=0.0, maximum=1.0, step=0.01, value=0.8, elem_id="video_denoising_strength")
|
||||
gr.HTML("<br>  Init image")
|
||||
init_image = gr.Image(elem_id="video_image", show_label=False, type="pil", image_mode="RGB", width=256, height=256)
|
||||
gr.HTML("<br>  Last image")
|
||||
last_image = gr.Image(elem_id="video_last", show_label=False, type="pil", image_mode="RGB", width=256, height=256)
|
||||
with gr.Accordion(open=False, label="Decode", elem_id='video_decode_accordion'):
|
||||
with gr.Row():
|
||||
vae_type = gr.Dropdown(label='VAE decode', choices=['Default', 'Tiny', 'Remote', 'Upscale'], value='Default', elem_id="video_vae_type")
|
||||
@@ -163,18 +153,15 @@ def create_ui(prompt, negative, styles, overrides, init_image, init_strength, la
|
||||
with gr.Tab('Frames', id='out-gallery'):
|
||||
gallery, gen_info, html_info, _html_info_formatted, html_log = ui_common.create_output_panel("video", prompt=prompt, preview=False, transfer=False, scale=2)
|
||||
|
||||
# connect reuse seed button
|
||||
ui_common.connect_reuse_seed(seed, reuse_seed, gen_info, is_subseed=False)
|
||||
# handle engine and model change
|
||||
engine.change(fn=engine_change, inputs=[engine], outputs=[model])
|
||||
model.change(fn=model_change, inputs=[engine, model], outputs=[url])
|
||||
btn_load.click(fn=model_load, inputs=[engine, model], outputs=[html_log])
|
||||
# hidden fields
|
||||
|
||||
task_id = gr.Textbox(visible=False, value='')
|
||||
ui_state = gr.Textbox(visible=False, value='')
|
||||
state_inputs = [task_id, ui_state]
|
||||
|
||||
# generate args
|
||||
video_inputs = [
|
||||
engine, model,
|
||||
prompt, negative, styles,
|
||||
@@ -206,4 +193,4 @@ def create_ui(prompt, negative, styles, overrides, init_image, init_strength, la
|
||||
show_progress='hidden',
|
||||
)
|
||||
generate.click(**video_dict)
|
||||
return [engine, model, steps, sampler_index]
|
||||
return engine, model, steps, sampler_index, width, height, frames, seed
|
||||
|
||||
Reference in New Issue
Block a user