Test / app.py
Eueuiaa's picture
Update app.py
fb6c034 verified
raw
history blame
13.1 kB
# app_refactored_with_postprod.py (com Modos de Geração e Opções LTX Completas)
import gradio as gr
import os
import sys
import traceback
from pathlib import Path
# --- Import dos Serviços de Backend ---
#try:
from api.ltx_server_refactored import video_generation_service
#except ImportError:
# print("ERRO FATAL: Não foi possível importar 'video_generation_service' de 'api.ltx_server_refactored'.")
# sys.exit(1)
#try:
from api.seedvr_server import SeedVRServer
#except ImportError:
# print("AVISO: Não foi possível importar SeedVRServer. A aba de upscaling SeedVR será desativada.")
# SeedVRServer = None
seedvr_inference_server = SeedVRServer() if SeedVRServer else None
# --- ESTADO DA SESSÃO ---
def create_initial_state():
return {"low_res_video": None, "low_res_latents": None, "used_seed": None}
# --- FUNÇÕES WRAPPER PARA A UI ---
def run_generate_base_video(
# Parâmetros de Geração
generation_mode, prompt, neg_prompt, start_img, height, width, duration, cfg, seed, randomize_seed,
# Novos parâmetros LTX (completos)
fp_num_inference_steps, fp_guidance_scale,
sampler, stg_mode, stochastic_sampling,
decode_timestep, decode_noise_scale, downscale_factor,
progress=gr.Progress(track_tqdm=True)
):
"""
Função wrapper que decide qual pipeline de backend chamar, passando todas as configurações LTX.
"""
print(f"UI: Iniciando geração no modo: {generation_mode}")
try:
initial_image_conditions = []
if start_img:
num_frames_estimate = int(duration * 24)
items_list = [[start_img, 0, 1.0]]
initial_image_conditions = video_generation_service.prepare_condition_items(items_list, height, width, num_frames_estimate)
used_seed = None if randomize_seed else seed
# Agrupa todas as configurações LTX em um único dicionário para o backend
ltx_configs = {
# First Pass
"first_pass_num_inference_steps": fp_num_inference_steps,
"first_pass_guidance_scale": fp_guidance_scale,
# Gerais
"sampler": sampler,
"stg_mode": stg_mode,
"stochastic_sampling": stochastic_sampling,
"decode_timestep": decode_timestep,
"decode_noise_scale": decode_noise_scale,
"downscale_factor": downscale_factor,
}
# Decide qual função de backend chamar com base no modo
if generation_mode == "Narrativa (Múltiplos Prompts)":
video_path, tensor_path, final_seed = video_generation_service.generate_narrative_low(
prompt=prompt, negative_prompt=neg_prompt,
height=height, width=width, duration=duration,
guidance_scale=cfg, seed=used_seed,
initial_image_conditions=initial_image_conditions,
ltx_configs_override=ltx_configs
)
else: # Modo "Simples (Prompt Único)"
video_path, tensor_path, final_seed = video_generation_service.generate_single_low(
prompt=prompt, negative_prompt=neg_prompt,
height=height, width=width, duration=duration,
guidance_scale=cfg, seed=used_seed,
initial_image_conditions=initial_image_conditions,
ltx_configs_override=ltx_configs
)
new_state = {"low_res_video": video_path, "low_res_latents": tensor_path, "used_seed": final_seed}
return video_path, new_state, gr.update(visible=True)
except Exception as e:
error_message = f"❌ Ocorreu um erro na Geração Base:\n{e}"
print(f"{error_message}\nDetalhes: {traceback.format_exc()}")
raise gr.Error(error_message)
def run_ltx_refinement(state, prompt, neg_prompt, cfg, progress=gr.Progress(track_tqdm=True)):
if not state or not state.get("low_res_latents"):
raise gr.Error("Erro: Gere um vídeo base primeiro na Etapa 1.")
try:
# Nota: O refinamento também poderia aceitar um dicionário de configs para o second_pass
video_path, tensor_path = video_generation_service.generate_upscale_denoise(
latents_path=state["low_res_latents"], prompt=prompt,
negative_prompt=neg_prompt, guidance_scale=cfg, seed=state["used_seed"]
)
state["refined_video_ltx"] = video_path; state["refined_latents_ltx"] = tensor_path
return video_path, state
except Exception as e:
raise gr.Error(f"Erro no Refinamento LTX: {e}")
def run_seedvr_upscaling(state, seed, resolution, batch_size, fps, progress=gr.Progress(track_tqdm=True)):
if not state or not state.get("low_res_video"):
raise gr.Error("Erro: Gere um vídeo base primeiro na Etapa 1.")
if not seedvr_inference_server:
raise gr.Error("Erro: O servidor SeedVR não está disponível.")
try:
def progress_wrapper(p, desc=""): progress(p, desc=desc)
output_filepath = seedvr_inference_server.run_inference(
file_path=state["low_res_video"], seed=seed, resolution=resolution,
batch_size=batch_size, fps=fps, progress=progress_wrapper
)
return gr.update(value=output_filepath), gr.update(value=f"✅ Concluído!\nSalvo em: {output_filepath}")
except Exception as e:
return None, gr.update(value=f"❌ Erro no SeedVR:\n{e}")
# --- DEFINIÇÃO DA INTERFACE GRADIO ---
with gr.Blocks(css="#col-container { margin: 0 auto; max-width: 900px; }", theme=gr.themes.Monochrome()) as demo:
gr.Markdown("# LTX Video - Geração e Pós-Produção por Etapas")
app_state = gr.State(value=create_initial_state())
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Etapa 1: Configurações de Geração")
generation_mode_input = gr.Radio(
label="Modo de Geração", choices=["Simples (Prompt Único)", "Narrativa (Múltiplos Prompts)"],
value="Narrativa (Múltiplos Prompts)", info="Simples para uma ação, Narrativa para uma sequência (uma cena por linha)."
)
prompt_input = gr.Textbox(label="Prompt(s)", value="Um leão majestoso caminha pela savana\nEle sobe em uma grande pedra e olha o horizonte", lines=4)
neg_prompt_input = gr.Textbox(label="Negative Prompt", value="blurry, low quality, bad anatomy", lines=2)
start_image = gr.Image(label="Imagem de Início (Opcional)", type="filepath", sources=["upload"])
with gr.Accordion("Parâmetros Principais", open=True):
duration_input = gr.Slider(label="Duração Total (s)", value=8, step=1, minimum=2, maximum=40)
with gr.Row():
height_input = gr.Slider(label="Height", value=512, step=32, minimum=256, maximum=1024)
width_input = gr.Slider(label="Width", value=704, step=32, minimum=256, maximum=1024)
with gr.Row():
seed_input = gr.Number(label="Seed", value=42, precision=0)
randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
with gr.Accordion("Opções Adicionais LTX (Avançado)", open=False):
gr.Markdown("Estes parâmetros sobrepõem os valores padrão do arquivo de configuração do LTX.")
with gr.Tabs():
with gr.TabItem("First Pass"):
fp_num_inference_steps = gr.Slider(
label="Passos de Inferência", minimum=10, maximum=100, step=1, value=30,
info="Padrão do config é 30. Controla o número de passos do denoise inicial."
)
fp_guidance_scale = gr.Slider(
label="Força da Guiagem (Pico)", minimum=1.0, maximum=15.0, step=0.5, value=8.0,
info="Padrão do config tem um pico de 8.0. Controla o quão forte o prompt guia a formação da imagem."
)
with gr.TabItem("Geral"):
sampler = gr.Radio(
label="Sampler", choices=["from_checkpoint", "uniform", "linear-quadratic"], value="from_checkpoint",
info="Como o scheduler calcula os timesteps."
)
stg_mode = gr.Radio(
label="Modo de Guiagem Espaço-Temporal (STG)",
choices=["attention_values", "attention_skip", "residual", "transformer_block"],
value="attention_values", info="Como a guiagem de movimento é aplicada."
)
stochastic_sampling = gr.Checkbox(label="Amostragem Estocástica", value=False, info="Adiciona aleatoriedade ao denoise.")
downscale_factor = gr.Slider(label="Fator de Downscale", minimum=0.1, maximum=1.0, step=0.01, value=0.66, info="Tamanho da geração inicial (padrão ~0.66).")
with gr.TabItem("Decode VAE"):
decode_timestep = gr.Slider(label="Decode Timestep", minimum=0.0, maximum=1.0, step=0.01, value=0.05, info="Nível de ruído para o VAE denoiser.")
decode_noise_scale = gr.Slider(label="Decode Noise Scale", minimum=0.0, maximum=1.0, step=0.005, value=0.025, info="Escala do ruído no decode.")
cfg_input = gr.Slider(label="Guidance Scale (CFG)", info="Afeta o refinamento (se usado) e não tem efeito no First Pass dos modelos 'distilled'.", value=3.0, step=0.1, minimum=1.0, maximum=10.0)
generate_low_btn = gr.Button("1. Gerar Vídeo Base", variant="primary")
with gr.Column(scale=1):
gr.Markdown("### Vídeo Base Gerado")
low_res_video_output = gr.Video(label="O resultado da Etapa 1 aparecerá aqui", interactive=False)
with gr.Group(visible=False) as post_prod_group:
gr.Markdown("<hr style='margin-top: 20px; margin-bottom: 20px;'>")
gr.Markdown("## Etapa 2: Pós-Produção")
with gr.Tabs():
with gr.TabItem("🚀 Upscaler Textura (LTX)"):
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("Reutiliza o prompt e CFG para refinar a textura.")
ltx_refine_btn = gr.Button("Aplicar Refinamento LTX", variant="primary")
with gr.Column(scale=1):
ltx_refined_video_output = gr.Video(label="Vídeo com Textura Refinada", interactive=False)
with gr.TabItem("✨ Upscaler SeedVR"):
with gr.Row():
with gr.Column(scale=1):
seedvr_seed = gr.Slider(minimum=0, maximum=999999, value=42, step=1, label="Seed")
seedvr_resolution = gr.Slider(minimum=720, maximum=1440, value=1072, step=8, label="Resolução Vertical")
seedvr_batch_size = gr.Slider(minimum=1, maximum=16, value=4, step=1, label="Batch Size por GPU")
seedvr_fps_output = gr.Number(label="FPS de Saída (0 = original)", value=0)
run_seedvr_button = gr.Button("Iniciar Upscaling SeedVR", variant="primary", interactive=(seedvr_inference_server is not None))
if not seedvr_inference_server:
gr.Markdown("<p style='color: red;'>Serviço SeedVR não disponível.</p>")
with gr.Column(scale=1):
seedvr_video_output = gr.Video(label="Vídeo com Upscale SeedVR", interactive=False)
seedvr_status_box = gr.Textbox(label="Status", value="Aguardando...", lines=3, interactive=False)
# --- LÓGICA DE EVENTOS ---
all_ltx_inputs = [
fp_num_inference_steps, fp_guidance_scale,
sampler, stg_mode, stochastic_sampling,
decode_timestep, decode_noise_scale, downscale_factor,
]
generate_low_btn.click(
fn=run_generate_base_video,
inputs=[
generation_mode_input, prompt_input, neg_prompt_input, start_image, height_input, width_input,
duration_input, cfg_input, seed_input, randomize_seed,
*all_ltx_inputs
],
outputs=[low_res_video_output, app_state, post_prod_group]
)
ltx_refine_btn.click(
fn=run_ltx_refinement,
inputs=[app_state, prompt_input, neg_prompt_input, cfg_input],
outputs=[ltx_refined_video_output, app_state]
)
run_seedvr_button.click(
fn=run_seedvr_upscaling,
inputs=[app_state, seedvr_seed, seedvr_resolution, seedvr_batch_size, seedvr_fps_output],
outputs=[seedvr_video_output, seedvr_status_box]
)
if __name__ == "__main__":
demo.queue().launch(server_name="0.0.0.0", server_port=7860, debug=True, show_error=True)