Aduc-sdr-2_5s / app_wan.py
x2XcarleX2x's picture
Update app_wan.py
68b5422 verified
raw
history blame
8.71 kB
# app_wan.py (v1.5.0 - com yield para atualizações em tempo real)
import os
import gradio as gr
import numpy as np
from PIL import Image
# === Constantes da UI ===
MAX_SEED = np.iinfo(np.int32).max
MIN_TOTAL_FRAMES = 9
MAX_TOTAL_FRAMES = 81
STEP_TOTAL_FRAMES = 4 # Garante 4n+1 (9, 13, 17...)
MIN_HANDLER_FRAME = 17 # Garante 8n+1 e buffer inicial (2*8+1)
MAX_HANDLER_FRAME = 73 # Garante buffer final (9*8+1)
STEP_HANDLER_FRAME = 8 # Garante 8n+1
# === Importa o serviço de geração (manager) ===
from aduc_framework.managers.wan_manager import WanManager
wan_manager = WanManager()
# === Wrapper da UI para o Serviço (agora é um GERADOR) ===
def ui_generate_video(
# --- Inputs da Aba 1: Image-to-Video ---
convergent_img_i2v,
handler_img_i2v,
handler_frame_slider,
handler_weight_slider,
causal_img_i2v,
total_frames_slider,
causal_weight_slider,
# --- Inputs da Aba 2: Video Extender ---
convergent_img_v2v,
causal_video_upload,
# --- Inputs Comuns ---
prompt,
negative_prompt,
fps,
resolution,
steps,
guidance_scale,
guidance_scale_2,
seed,
randomize_seed,
progress=gr.Progress(track_tqdm=True),
):
# Determina o modo de operação e a imagem convergente correta
is_v2v_mode = causal_video_upload is not None
convergent_img = convergent_img_v2v if is_v2v_mode else convergent_img_i2v
# Validação de entradas essenciais
if convergent_img is None:
raise gr.Error("A 'Convergent Image (Start)' é obrigatória em ambos os modos.")
if not is_v2v_mode and causal_img_i2v is None:
raise gr.Error("A 'Causal Image (End)' é obrigatória no modo Image-to-Video.")
# Itera sobre os resultados parciais produzidos pelo manager
# A última iteração conterá o resultado final completo.
for result in wan_manager.generate_video(
convergent_img=convergent_img,
causal_video_path=causal_video_upload,
causal_img=causal_img_i2v,
handler_img=handler_img_i2v,
total_frames=int(total_frames_slider),
handler_frame=int(handler_frame_slider),
causal_weight=float(causal_weight_slider),
handler_weight=float(handler_weight_slider),
prompt=prompt,
negative_prompt=negative_prompt,
fps=int(fps),
resolution=resolution,
steps=int(steps),
guidance_scale=float(guidance_scale),
guidance_scale_2=float(guidance_scale_2),
seed=int(seed),
randomize_seed=bool(randomize_seed),
):
# result é uma tupla: (video_path, seed, lista_de_videos_de_passo)
final_video_path, current_seed, denoising_videos = result
# Cria um dicionário de atualização para o Gradio.
# A cada passo, atualizamos a galeria com a lista de vídeos.
# No último passo, o vídeo principal e a seed também são atualizados.
update_dict = {
output_video: gr.update(value=final_video_path),
seed_input: gr.update(value=current_seed),
steps_video_gallery: gr.update(value=denoising_videos)
}
# Produz (yield) a atualização para a UI do Gradio
yield update_dict
# === Interface Gradio ===
css = '''
.fillable{max-width: 1100px !important}
.dark .progress-text {color: white}
#general_items{margin-top: 2em}
'''
with gr.Blocks(theme=gr.themes.Glass(), css=css) as app:
gr.Markdown("# Wan 2.2 Aduca-SDR")
with gr.Row(elem_id="general_items"):
with gr.Column(scale=2):
with gr.Tabs() as tabs:
with gr.TabItem("Image-to-Video", id="i2v_tab"):
with gr.Row():
with gr.Column():
convergent_image_i2v = gr.Image(type="pil", label="Convergent Img (Start)", sources=["upload", "clipboard"])
with gr.Column():
handler_image_i2v = gr.Image(type="pil", label="Handler Img (Middle)", sources=["upload", "clipboard"])
handler_frame_slider = gr.Slider(
minimum=MIN_HANDLER_FRAME, maximum=MAX_HANDLER_FRAME, step=STEP_HANDLER_FRAME,
value=25, label="Handler Frame"
)
handler_weight_slider = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, value=1.0, label="Handler Weight")
with gr.Column():
causal_image_i2v = gr.Image(type="pil", label="Causal Img (End)", sources=["upload", "clipboard"])
total_frames_slider = gr.Slider(
minimum=MIN_TOTAL_FRAMES, maximum=MAX_TOTAL_FRAMES, step=STEP_TOTAL_FRAMES,
value=33, label="Total Frames"
)
causal_weight_slider = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, value=1.0, label="Causal Weight")
with gr.TabItem("Video Extender", id="v2v_tab"):
with gr.Row():
with gr.Column():
convergent_image_v2v = gr.Image(type="pil", label="Convergent Img (Start)", sources=["upload", "clipboard"])
gr.Markdown("<p style='font-size:0.8rem;color:gray'>A imagem para iniciar a nova seção do vídeo.</p>")
with gr.Column():
causal_video_upload = gr.Video(label="Causal Video", sources=["upload"])
gr.Markdown("<p style='font-size:0.8rem;color:gray'>O vídeo a ser estendido.</p>")
gr.Markdown("---")
prompt = gr.Textbox(
label="Prompt",
info="Descreva a nova cena ou transição. Ex: 'the scene changes to a futuristic city at night'."
)
with gr.Accordion("Advanced Settings", open=False):
with gr.Row():
resolution_selector = gr.Dropdown(
choices=["480x832", "832x480", "240x416", "416x240", "720x1280", "1280x720", "512x512"],
value="480x832", label="Resolution (H x W)",
info="No modo Video Extender, o vídeo será conformado para esta resolução."
)
fps_selector = gr.Dropdown(choices=[8, 16, 24], value=16, label="FPS", info="O vídeo será conformado para este FPS.")
negative_prompt_input = gr.Textbox(
label="Negative Prompt",
value=wan_manager.default_negative_prompt,
lines=3
)
steps_slider = gr.Slider(minimum=1, maximum=30, step=1, value=8, label="Inference Steps")
guidance_scale_input = gr.Slider(
minimum=0.0, maximum=10.0, step=0.5, value=1.0, label="Guidance Scale (High Noise)"
)
guidance_scale_2_input = gr.Slider(
minimum=0.0, maximum=10.0, step=0.5, value=1.0, label="Guidance Scale (Low Noise)"
)
with gr.Row():
seed_input = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=42, interactive=True)
randomize_seed_checkbox = gr.Checkbox(label="Randomize Seed", value=True)
generate_button = gr.Button("Generate Video", variant="primary")
with gr.Column(scale=1):
output_video = gr.Video(label="Generated Video", autoplay=True)
with gr.Accordion("Denoising Process Visuals", open=True):
gr.Markdown("Evolução do vídeo completo em cada passo do Denoising.")
steps_video_gallery = gr.Gallery(
label="Denoising Steps",
object_fit="contain",
height="auto",
columns=4,
)
ui_inputs = [
convergent_image_i2v,
handler_image_i2v, handler_frame_slider, handler_weight_slider,
causal_image_i2v, total_frames_slider, causal_weight_slider,
convergent_image_v2v,
causal_video_upload,
prompt, negative_prompt_input,
fps_selector, resolution_selector,
steps_slider, guidance_scale_input, guidance_scale_2_input,
seed_input, randomize_seed_checkbox,
]
ui_outputs = [output_video, seed_input, steps_video_gallery]
generate_button.click(fn=ui_generate_video, inputs=ui_inputs, outputs=ui_outputs)
if __name__ == "__main__":
app.launch(server_name="0.0.0.0", server_port=7860, show_error=True)