euIaxs22 commited on
Commit
83f4660
·
verified ·
1 Parent(s): 76ccc8e

Update app_ltx.py

Browse files
Files changed (1) hide show
  1. app_ltx.py +90 -94
app_ltx.py CHANGED
@@ -1,110 +1,106 @@
1
  import os
2
- import subprocess
3
- import sys
4
  from pathlib import Path
5
- import time # <<< CORREÇÃO AQUI: Importa o módulo 'time'
6
- from typing import Optional, Tuple
7
 
8
- from huggingface_hub import snapshot_download
 
 
 
 
 
 
9
 
10
- class LTXServer:
11
- """
12
- Gerencia o setup e a execução da inferência para o LTX-Video Q8.
13
- """
14
- _instance = None
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
- def __new__(cls, *args, **kwargs):
17
- if not cls._instance:
18
- cls._instance = super(LTXServer, cls).__new__(cls)
19
- return cls._instance
20
-
21
- def __init__(self):
22
- if hasattr(self, '_initialized') and self._initialized:
23
- return
24
-
25
- print("🚀 LTXServer (Q8) inicializando e preparando o ambiente...")
26
 
27
- self.LTX_REPO_DIR = Path(os.getenv("LTX_REPO_DIR", "/data/LTX-Video"))
28
- self.LTX_CKPT_DIR = Path(os.getenv("LTX_CKPT_DIR", "/data/ckpt/ltxvideo_q8"))
29
- self.OUTPUT_ROOT = Path(os.getenv("OUTPUT_ROOT", "/app/outputs/ltx"))
30
- self.HF_HOME_CACHE = Path(os.getenv("HF_HOME", "/data/.cache/huggingface"))
 
 
 
 
31
 
32
- self.REPO_URL = "https://github.com/KONAKONA666/LTX-Video.git"
33
- self.MODEL_REPO_ID = "konakona/ltxvideo_q8"
34
 
35
- for p in [self.LTX_REPO_DIR.parent, self.LTX_CKPT_DIR, self.OUTPUT_ROOT, self.HF_HOME_CACHE]:
36
- p.mkdir(parents=True, exist_ok=True)
37
-
38
- self.setup_dependencies()
39
- self._initialized = True
40
- print("✅ LTXServer (Q8) pronto.")
41
-
42
- def setup_dependencies(self):
43
- self._ensure_repo()
44
- self._ensure_model()
45
-
46
- def _ensure_repo(self) -> None:
47
- if not (self.LTX_REPO_DIR / ".git").exists():
48
- print(f"[LTXServer] Clonando repositório para {self.LTX_REPO_DIR}...")
49
- subprocess.run(["git", "clone", "--depth", "1", self.REPO_URL, str(self.LTX_REPO_DIR)], check=True)
50
- else:
51
- print("[LTXServer] Repositório LTX-Video já existe.")
52
 
53
- def _ensure_model(self) -> None:
54
- print(f"[LTXServer] Verificando checkpoints em {self.LTX_CKPT_DIR}...")
55
- snapshot_download(
56
- repo_id=self.MODEL_REPO_ID,
57
- local_dir=str(self.LTX_CKPT_DIR),
58
- cache_dir=str(self.HF_HOME_CACHE),
59
- repo_type='model',
60
- token=os.getenv("HF_TOKEN")
61
- )
62
- print("[LTXServer] Checkpoints Q8 prontos.")
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
- def run_inference(self, prompt: str, image_path: str, height: int, width: int, num_frames: int, seed: int) -> str:
65
- if not Path(image_path).exists():
66
- raise FileNotFoundError(f"Arquivo de imagem de entrada não encontrado: {image_path}")
67
 
68
- script_path = self.LTX_REPO_DIR / "inference.py"
69
- if not script_path.exists():
70
- raise FileNotFoundError(f"Script de inferência não encontrado em: {script_path}")
71
 
72
- job_output_dir = self.OUTPUT_ROOT / f"run_{int(time.time())}_{os.urandom(4).hex()}"
73
- job_output_dir.mkdir(parents=True)
 
 
 
74
 
75
- cmd = [
76
- "python", str(script_path),
77
- "--ckpt_dir", str(self.LTX_CKPT_DIR),
78
- "--output_dir", str(job_output_dir),
79
- "--low_vram",
80
- "--transformer_type=q8_kernels",
81
- "--prompt", prompt,
82
- "--input_image_path", image_path,
83
- "--height", str(height),
84
- "--width", str(width),
85
- "--num_frames", str(num_frames),
86
- "--seed", str(seed),
87
- ]
88
 
89
- print("[LTXServer] Comando de execução:", " ".join(cmd))
90
-
91
  try:
92
- subprocess.run(
93
- cmd,
94
- cwd=str(self.LTX_REPO_DIR),
95
- check=True,
96
- env=os.environ.copy(),
97
- stdout=sys.stdout,
98
- stderr=sys.stderr
99
- )
100
- except Exception as e:
101
- print(f"[LTXServer] Erro na execução da inferência: {e}")
102
- raise
103
-
104
- output_videos = sorted(job_output_dir.glob("*.mp4"))
105
- if not output_videos:
106
- raise FileNotFoundError(f"Nenhum vídeo foi gerado no diretório de saída: {job_output_dir}")
107
-
108
- return str(output_videos[0])
109
 
110
- ltx_server_singleton = LTXServer()
 
 
 
 
 
1
  import os
2
+ import gradio as gr
 
3
  from pathlib import Path
 
 
4
 
5
+ # Importa o singleton do nosso novo servidor LTX
6
+ try:
7
+ from services.ltx_server import ltx_server_singleton as server
8
+ except Exception as e:
9
+ print(f"ERRO FATAL: Não foi possível importar o LTXServer. A aplicação não pode iniciar.")
10
+ print(f"Detalhe do erro: {e}")
11
+ raise
12
 
13
+ # --- Função de Callback da UI ---
14
+ def generate_video_from_image(
15
+ prompt: str,
16
+ image_input: str,
17
+ height: int,
18
+ width: int,
19
+ num_frames: int,
20
+ seed: int,
21
+ progress=gr.Progress(track_tqdm=True) # <<< ADICIONADO PROGRESSO AQUI
22
+ ):
23
+ """Callback para a UI que chama o backend LTXServer."""
24
+ progress(0.1, desc="Validando entradas...")
25
+ if not image_input or not Path(image_input).exists():
26
+ gr.Warning("Por favor, faça o upload de uma imagem de entrada.")
27
+ return None
28
+ if not prompt or not prompt.strip():
29
+ gr.Warning("Por favor, insira um prompt.")
30
+ return None
31
 
32
+ try:
33
+ progress(0.5, desc="Enviando tarefa para o backend LTX (Q8). A inferência pode demorar um pouco...")
 
 
 
 
 
 
 
 
34
 
35
+ video_path = server.run_inference(
36
+ prompt=prompt,
37
+ image_path=image_input,
38
+ height=int(height),
39
+ width=int(width),
40
+ num_frames=int(num_frames),
41
+ seed=int(seed)
42
+ )
43
 
44
+ progress(1.0, desc="Inferência concluída!")
45
+ return video_path
46
 
47
+ except Exception as e:
48
+ print(f"[UI LTX ERROR] A inferência falhou: {e}")
49
+ gr.Error(f"Erro na Geração: {e}")
50
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ # --- Definição da Interface Gráfica com Gradio ---
53
+ with gr.Blocks(title="LTX-Video (Q8 Img2Vid)") as demo:
54
+ gr.HTML(
55
+ """
56
+ <div style='text-align:center; margin-bottom: 20px;'>
57
+ <h1>LTX-Video Q8 - Imagem para Vídeo</h1>
58
+ <p>Interface de teste isolada para o modelo LTX-Video quantizado.</p>
59
+ </div>
60
+ """
61
+ )
62
+
63
+ with gr.Row():
64
+ with gr.Column(scale=1):
65
+ image_in = gr.Image(type="filepath", label="Imagem de Entrada")
66
+ prompt_in = gr.Textbox(label="Prompt", lines=3, placeholder="Ex: a cinematic shot of a woman smiling")
67
+
68
+ with gr.Accordion("Parâmetros de Geração", open=True):
69
+ with gr.Row():
70
+ height_in = gr.Slider(label="Altura (Height)", minimum=256, maximum=1024, step=64, value=512)
71
+ width_in = gr.Slider(label="Largura (Width)", minimum=256, maximum=1024, step=64, value=512)
72
+ with gr.Row():
73
+ frames_in = gr.Slider(label="Número de Frames", minimum=16, maximum=128, step=8, value=32)
74
+ seed_in = gr.Number(label="Seed", value=42, precision=0)
75
 
76
+ run_button = gr.Button("Gerar Vídeo", variant="primary")
 
 
77
 
78
+ with gr.Column(scale=1):
79
+ video_out = gr.Video(label="Vídeo Gerado")
 
80
 
81
+ run_button.click(
82
+ fn=generate_video_from_image,
83
+ inputs=[prompt_in, image_in, height_in, width_in, frames_in, seed_in],
84
+ outputs=[video_out],
85
+ )
86
 
87
+ gr.Markdown("---")
88
+ gr.Examples(
89
+ examples=[["A beautiful woman with a gentle smile, cinematic lighting", "frame_1.png", 512, 512, 32, 123]],
90
+ inputs=[prompt_in, image_in, height_in, width_in, frames_in, seed_in],
91
+ )
 
 
 
 
 
 
 
 
92
 
93
+ if __name__ == "__main__":
94
+ if not os.path.exists("frame_1.png"):
95
  try:
96
+ from PIL import Image
97
+ img = Image.new('RGB', (512, 512), color = 'grey')
98
+ img.save('frame_1.png')
99
+ except:
100
+ pass
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
+ demo.launch(
103
+ server_name=os.getenv("GRADIO_SERVER_NAME", "0.0.0.0"),
104
+ server_port=int(os.getenv("GRADIO_SERVER_PORT", "7861")),
105
+ show_error=True,
106
+ )