euIaxs22 commited on
Commit
111d2af
·
verified ·
1 Parent(s): e0c7b14

Create ltx_server.py

Browse files
Files changed (1) hide show
  1. services/ltx_server.py +135 -0
services/ltx_server.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import subprocess
3
+ import sys
4
+ from pathlib import Path
5
+ from typing import Optional, Tuple
6
+
7
+ from huggingface_hub import snapshot_download
8
+
9
+ class LTXServer:
10
+ """
11
+ Gerencia o setup e a execução da inferência para o LTX-Video Q8.
12
+ - Baixa o repositório e os modelos necessários.
13
+ - Executa o script 'inference.py' como um subprocesso.
14
+ """
15
+ _instance = None
16
+
17
+ def __new__(cls, *args, **kwargs):
18
+ if not cls._instance:
19
+ cls._instance = super(LTXServer, cls).__new__(cls)
20
+ return cls._instance
21
+
22
+ def __init__(self):
23
+ # Evita reinicialização
24
+ if hasattr(self, '_initialized') and self._initialized:
25
+ return
26
+
27
+ print("🚀 LTXServer (Q8) inicializando e preparando o ambiente...")
28
+
29
+ # Define os caminhos
30
+ self.LTX_REPO_DIR = Path(os.getenv("LTX_REPO_DIR", "/data/LTX-Video"))
31
+ self.LTX_CKPT_DIR = Path(os.getenv("LTX_CKPT_DIR", "/data/ckpt/ltxvideo_q8"))
32
+ self.OUTPUT_ROOT = Path(os.getenv("OUTPUT_ROOT", "/app/outputs/ltx"))
33
+ self.HF_HOME_CACHE = Path(os.getenv("HF_HOME", "/data/.cache/huggingface"))
34
+
35
+ self.REPO_URL = "https://github.com/KONAKONA666/LTX-Video.git"
36
+ self.MODEL_REPO_ID = "konakona/ltxvideo_q8"
37
+
38
+ # Garante que os diretórios existam
39
+ for p in [self.LTX_REPO_DIR.parent, self.LTX_CKPT_DIR, self.OUTPUT_ROOT, self.HF_HOME_CACHE]:
40
+ p.mkdir(parents=True, exist_ok=True)
41
+
42
+ self.setup_dependencies()
43
+ self._initialized = True
44
+ print("✅ LTXServer (Q8) pronto.")
45
+
46
+ def setup_dependencies(self):
47
+ """Orquestra o setup: clona o repo e baixa os modelos."""
48
+ self._ensure_repo()
49
+ self._ensure_model()
50
+
51
+ def _ensure_repo(self) -> None:
52
+ """Clona o repositório do LTX-Video se ele não existir."""
53
+ if not (self.LTX_REPO_DIR / ".git").exists():
54
+ print(f"[LTXServer] Clonando repositório para {self.LTX_REPO_DIR}...")
55
+ subprocess.run(["git", "clone", "--depth", "1", self.REPO_URL, str(self.LTX_REPO_DIR)], check=True)
56
+ else:
57
+ print("[LTXServer] Repositório LTX-Video já existe.")
58
+
59
+ def _ensure_model(self) -> None:
60
+ """Baixa os checkpoints do modelo Q8, utilizando o cache."""
61
+ print(f"[LTXServer] Verificando checkpoints em {self.LTX_CKPT_DIR}...")
62
+ try:
63
+ snapshot_download(
64
+ repo_id=self.MODEL_REPO_ID,
65
+ local_dir=str(self.LTX_CKPT_DIR),
66
+ cache_dir=str(self.HF_HOME_CACHE),
67
+ local_dir_use_symlinks=False,
68
+ repo_type='model',
69
+ token=os.getenv("HF_TOKEN")
70
+ )
71
+ print("[LTXServer] Checkpoints Q8 prontos.")
72
+ except Exception as e:
73
+ print(f"[LTXServer] ERRO durante o snapshot_download: {e}")
74
+ raise
75
+
76
+ def run_inference(
77
+ self,
78
+ prompt: str,
79
+ image_path: str,
80
+ height: int,
81
+ width: int,
82
+ num_frames: int,
83
+ seed: int
84
+ ) -> str:
85
+ """Executa a inferência img2vid como um subprocesso."""
86
+ if not Path(image_path).exists():
87
+ raise FileNotFoundError(f"Arquivo de imagem de entrada não encontrado: {image_path}")
88
+
89
+ script_path = self.LTX_REPO_DIR / "inference.py"
90
+ if not script_path.exists():
91
+ raise FileNotFoundError(f"Script de inferência não encontrado em: {script_path}")
92
+
93
+ # Cria um diretório de saída único para este job
94
+ job_output_dir = self.OUTPUT_ROOT / f"run_{int(time.time())}_{os.urandom(4).hex()}"
95
+ job_output_dir.mkdir(parents=True)
96
+
97
+ cmd = [
98
+ "python", str(script_path),
99
+ "--ckpt_dir", str(self.LTX_CKPT_DIR),
100
+ "--output_dir", str(job_output_dir), # Adiciona o diretório de saída
101
+ "--low_vram",
102
+ "--transformer_type=q8_kernels",
103
+ "--prompt", prompt,
104
+ "--input_image_path", image_path,
105
+ "--height", str(height),
106
+ "--width", str(width),
107
+ "--num_frames", str(num_frames),
108
+ "--seed", str(seed),
109
+ ]
110
+
111
+ print("[LTXServer] Comando de execução:", " ".join(cmd))
112
+
113
+ try:
114
+ # O 'cwd' é crucial para que o script encontre seus próprios módulos internos
115
+ subprocess.run(
116
+ cmd,
117
+ cwd=str(self.LTX_REPO_DIR),
118
+ check=True,
119
+ env=os.environ.copy(),
120
+ stdout=sys.stdout,
121
+ stderr=sys.stderr
122
+ )
123
+ except Exception as e:
124
+ print(f"[LTXServer] Erro na execução da inferência: {e}")
125
+ raise
126
+
127
+ # Encontra o vídeo gerado no diretório de saída
128
+ output_videos = sorted(job_output_dir.glob("*.mp4"))
129
+ if not output_videos:
130
+ raise FileNotFoundError(f"Nenhum vídeo foi gerado no diretório de saída: {job_output_dir}")
131
+
132
+ return str(output_videos[0])
133
+
134
+ # Instância Singleton que será usada pelo app Gradio
135
+ ltx_server_singleton = LTXServer()