Spaces:
Paused
Paused
Update app_ltx.py
Browse files- app_ltx.py +37 -28
app_ltx.py
CHANGED
|
@@ -1,15 +1,16 @@
|
|
| 1 |
-
|
| 2 |
import os
|
| 3 |
import gradio as gr
|
| 4 |
from pathlib import Path
|
| 5 |
from PIL import Image
|
|
|
|
| 6 |
|
| 7 |
# Importa o singleton do nosso novo servidor LTX (API Diffusers)
|
| 8 |
try:
|
| 9 |
from services.ltx_server import ltx_server_singleton as server
|
| 10 |
except Exception as e:
|
| 11 |
print(f"ERRO FATAL: Não foi possível importar o LTXServer. {e}")
|
| 12 |
-
|
|
|
|
| 13 |
|
| 14 |
# --- Função de Callback da UI ---
|
| 15 |
def generate_video_from_image(
|
|
@@ -21,28 +22,27 @@ def generate_video_from_image(
|
|
| 21 |
seed: int,
|
| 22 |
guidance_scale: float,
|
| 23 |
num_inference_steps: int,
|
| 24 |
-
|
| 25 |
-
decode_noise_scale: float,
|
| 26 |
progress=gr.Progress(track_tqdm=True)
|
| 27 |
):
|
|
|
|
| 28 |
progress(0.1, desc="Validando entradas...")
|
| 29 |
if not image_input and (not prompt or not prompt.strip()):
|
| 30 |
-
gr.Warning("Por favor, forneça uma imagem de entrada ou um prompt de texto.")
|
| 31 |
return None
|
| 32 |
|
| 33 |
try:
|
| 34 |
-
progress(0.
|
| 35 |
video_path = server.run_inference(
|
| 36 |
prompt=prompt,
|
| 37 |
image_path=image_input,
|
| 38 |
-
|
| 39 |
-
|
| 40 |
num_frames=int(num_frames),
|
| 41 |
seed=int(seed),
|
| 42 |
guidance_scale=float(guidance_scale),
|
| 43 |
num_inference_steps=int(num_inference_steps),
|
| 44 |
-
|
| 45 |
-
decode_noise_scale=float(decode_noise_scale)
|
| 46 |
)
|
| 47 |
progress(1.0, desc="Inferência concluída!")
|
| 48 |
return video_path
|
|
@@ -52,34 +52,33 @@ def generate_video_from_image(
|
|
| 52 |
return None
|
| 53 |
|
| 54 |
# --- Definição da Interface Gráfica com Gradio ---
|
| 55 |
-
with gr.Blocks(title="LTX-Video (
|
| 56 |
gr.HTML(
|
| 57 |
"""
|
| 58 |
<div style='text-align:center; margin-bottom: 20px;'>
|
| 59 |
-
<h1>LTX-Video - Geração de Vídeo
|
| 60 |
-
<p>Interface para a pipeline oficial LTX-Video.</p>
|
| 61 |
</div>
|
| 62 |
"""
|
| 63 |
)
|
| 64 |
|
| 65 |
with gr.Row():
|
| 66 |
with gr.Column(scale=1):
|
| 67 |
-
image_in = gr.Image(type="filepath", label="Imagem de Entrada (Opcional)")
|
| 68 |
-
prompt_in = gr.Textbox(label="Prompt", lines=4, placeholder="Ex: a cinematic shot of a majestic lion walking in the savanna")
|
| 69 |
|
| 70 |
-
with gr.Accordion("Parâmetros
|
| 71 |
with gr.Row():
|
| 72 |
-
height_in = gr.Slider(label="Altura (Height)", minimum=256, maximum=1024, step=32, value=
|
| 73 |
-
width_in = gr.Slider(label="Largura (Width)", minimum=256, maximum=
|
| 74 |
with gr.Row():
|
| 75 |
-
frames_in = gr.Slider(label="Número de Frames", minimum=17, maximum=161, step=8, value=33)
|
| 76 |
seed_in = gr.Number(label="Seed", value=42, precision=0)
|
| 77 |
|
| 78 |
with gr.Accordion("Parâmetros Avançados", open=False):
|
| 79 |
-
num_inference_steps_in = gr.Slider(label="Passos de Inferência", minimum=
|
| 80 |
-
guidance_scale_in = gr.Slider(label="Força do Guia (Guidance)", minimum=1.0, maximum=10.0, step=0.5, value=
|
| 81 |
-
|
| 82 |
-
decode_noise_scale_in = gr.Slider(label="Decode Noise Scale", minimum=0.0, maximum=0.2, step=0.005, value=0.025, info="Parâmetro do VAE.")
|
| 83 |
|
| 84 |
run_button = gr.Button("Gerar Vídeo", variant="primary")
|
| 85 |
|
|
@@ -88,18 +87,28 @@ with gr.Blocks(title="LTX-Video (Diffusers)", theme=gr.themes.Soft()) as demo:
|
|
| 88 |
|
| 89 |
run_button.click(
|
| 90 |
fn=generate_video_from_image,
|
| 91 |
-
inputs=[prompt_in, image_in, height_in, width_in, frames_in, seed_in, guidance_scale_in, num_inference_steps_in,
|
| 92 |
outputs=[video_out],
|
| 93 |
)
|
| 94 |
|
| 95 |
gr.Markdown("---")
|
| 96 |
# Cria uma imagem de exemplo se ela não existir
|
| 97 |
-
|
| 98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
|
| 100 |
gr.Examples(
|
| 101 |
-
examples=[["A
|
| 102 |
-
inputs=[prompt_in, image_in, height_in, width_in, frames_in, seed_in, guidance_scale_in, num_inference_steps_in,
|
|
|
|
|
|
|
|
|
|
| 103 |
)
|
| 104 |
|
| 105 |
if __name__ == "__main__":
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
import gradio as gr
|
| 3 |
from pathlib import Path
|
| 4 |
from PIL import Image
|
| 5 |
+
from typing import Optional
|
| 6 |
|
| 7 |
# Importa o singleton do nosso novo servidor LTX (API Diffusers)
|
| 8 |
try:
|
| 9 |
from services.ltx_server import ltx_server_singleton as server
|
| 10 |
except Exception as e:
|
| 11 |
print(f"ERRO FATAL: Não foi possível importar o LTXServer. {e}")
|
| 12 |
+
# Se o import falhar, a aplicação não tem como funcionar.
|
| 13 |
+
raise RuntimeError("Falha na inicialização do LTXServer.") from e
|
| 14 |
|
| 15 |
# --- Função de Callback da UI ---
|
| 16 |
def generate_video_from_image(
|
|
|
|
| 22 |
seed: int,
|
| 23 |
guidance_scale: float,
|
| 24 |
num_inference_steps: int,
|
| 25 |
+
denoise_strength: float,
|
|
|
|
| 26 |
progress=gr.Progress(track_tqdm=True)
|
| 27 |
):
|
| 28 |
+
"""Callback para a UI que chama o backend LTXServer."""
|
| 29 |
progress(0.1, desc="Validando entradas...")
|
| 30 |
if not image_input and (not prompt or not prompt.strip()):
|
| 31 |
+
gr.Warning("Por favor, forneça uma imagem de entrada e/ou um prompt de texto.")
|
| 32 |
return None
|
| 33 |
|
| 34 |
try:
|
| 35 |
+
progress(0.2, desc="Enviando tarefa para a pipeline LTX (Multi-Scale)...")
|
| 36 |
video_path = server.run_inference(
|
| 37 |
prompt=prompt,
|
| 38 |
image_path=image_input,
|
| 39 |
+
target_height=int(height),
|
| 40 |
+
target_width=int(width),
|
| 41 |
num_frames=int(num_frames),
|
| 42 |
seed=int(seed),
|
| 43 |
guidance_scale=float(guidance_scale),
|
| 44 |
num_inference_steps=int(num_inference_steps),
|
| 45 |
+
denoise_strength=float(denoise_strength)
|
|
|
|
| 46 |
)
|
| 47 |
progress(1.0, desc="Inferência concluída!")
|
| 48 |
return video_path
|
|
|
|
| 52 |
return None
|
| 53 |
|
| 54 |
# --- Definição da Interface Gráfica com Gradio ---
|
| 55 |
+
with gr.Blocks(title="LTX-Video (Multi-Scale)", theme=gr.themes.Soft()) as demo:
|
| 56 |
gr.HTML(
|
| 57 |
"""
|
| 58 |
<div style='text-align:center; margin-bottom: 20px;'>
|
| 59 |
+
<h1>LTX-Video - Geração de Vídeo Multi-Scale (FP8)</h1>
|
| 60 |
+
<p>Interface para a pipeline oficial LTX-Video via Diffusers.</p>
|
| 61 |
</div>
|
| 62 |
"""
|
| 63 |
)
|
| 64 |
|
| 65 |
with gr.Row():
|
| 66 |
with gr.Column(scale=1):
|
| 67 |
+
image_in = gr.Image(type="filepath", label="Imagem de Entrada (Opcional para txt2vid)")
|
| 68 |
+
prompt_in = gr.Textbox(label="Prompt", lines=4, placeholder="Ex: a cinematic shot of a majestic lion walking in the savanna, 4k, high quality")
|
| 69 |
|
| 70 |
+
with gr.Accordion("Parâmetros Principais", open=True):
|
| 71 |
with gr.Row():
|
| 72 |
+
height_in = gr.Slider(label="Altura Final (Height)", minimum=256, maximum=1024, step=32, value=480)
|
| 73 |
+
width_in = gr.Slider(label="Largura Final (Width)", minimum=256, maximum=1280, step=32, value=832)
|
| 74 |
with gr.Row():
|
| 75 |
+
frames_in = gr.Slider(label="Número de Frames", minimum=17, maximum=161, step=8, value=97, info="Deve ser um múltiplo de 8 + 1 (ex: 17, 25, 33, ...)")
|
| 76 |
seed_in = gr.Number(label="Seed", value=42, precision=0)
|
| 77 |
|
| 78 |
with gr.Accordion("Parâmetros Avançados", open=False):
|
| 79 |
+
num_inference_steps_in = gr.Slider(label="Passos de Inferência (Etapa 1)", minimum=4, maximum=50, step=1, value=30, info="Mais passos = melhor qualidade inicial. 4-10 para modelos 'distilled'.")
|
| 80 |
+
guidance_scale_in = gr.Slider(label="Força do Guia (Guidance)", minimum=1.0, maximum=10.0, step=0.5, value=1.0, info="Para modelos 'distilled', o valor recomendado é 1.0. Para outros, use ~5.0.")
|
| 81 |
+
denoise_strength_in = gr.Slider(label="Força do Refinamento (Denoise)", minimum=0.1, maximum=1.0, step=0.05, value=0.4, info="Controla a intensidade da Etapa 3 (refinamento). 0.4 significa 40% dos passos de inferência.")
|
|
|
|
| 82 |
|
| 83 |
run_button = gr.Button("Gerar Vídeo", variant="primary")
|
| 84 |
|
|
|
|
| 87 |
|
| 88 |
run_button.click(
|
| 89 |
fn=generate_video_from_image,
|
| 90 |
+
inputs=[prompt_in, image_in, height_in, width_in, frames_in, seed_in, guidance_scale_in, num_inference_steps_in, denoise_strength_in],
|
| 91 |
outputs=[video_out],
|
| 92 |
)
|
| 93 |
|
| 94 |
gr.Markdown("---")
|
| 95 |
# Cria uma imagem de exemplo se ela não existir
|
| 96 |
+
example_image_path = "ltx_example_penguin.png"
|
| 97 |
+
if not os.path.exists(example_image_path):
|
| 98 |
+
try:
|
| 99 |
+
# Tenta baixar a imagem de exemplo da documentação
|
| 100 |
+
from diffusers.utils import load_image
|
| 101 |
+
load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/penguin.png").save(example_image_path)
|
| 102 |
+
except:
|
| 103 |
+
# Se falhar, cria uma imagem cinza
|
| 104 |
+
Image.new('RGB', (512, 512), color = 'gray').save(example_image_path)
|
| 105 |
|
| 106 |
gr.Examples(
|
| 107 |
+
examples=[["A cute little penguin takes out a book and starts reading it", example_image_path, 480, 832, 97, 0, 1.0, 30, 0.4]],
|
| 108 |
+
inputs=[prompt_in, image_in, height_in, width_in, frames_in, seed_in, guidance_scale_in, num_inference_steps_in, denoise_strength_in],
|
| 109 |
+
outputs=[video_out],
|
| 110 |
+
fn=generate_video_from_image,
|
| 111 |
+
cache_examples=False,
|
| 112 |
)
|
| 113 |
|
| 114 |
if __name__ == "__main__":
|