Upload ltx_server.py
Browse files- api/ltx_server.py +33 -39
api/ltx_server.py
CHANGED
|
@@ -1,5 +1,13 @@
|
|
| 1 |
-
# ltx_server.py — VideoService (beta 1.
|
| 2 |
# Sempre output_type="latent"; no final: VAE (bloco inteiro) → pixels → MP4.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
# --- 1. IMPORTAÇÕES ---
|
| 5 |
import torch
|
|
@@ -21,22 +29,9 @@ import contextlib
|
|
| 21 |
import time
|
| 22 |
import traceback
|
| 23 |
|
| 24 |
-
|
| 25 |
-
from
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
logging.set_verbosity_error()
|
| 29 |
-
logging.set_verbosity_warning()
|
| 30 |
-
logging.set_verbosity_info()
|
| 31 |
-
logging.set_verbosity_debug()
|
| 32 |
-
|
| 33 |
-
enable_progress_bars()
|
| 34 |
-
LTXV_DEBUG=1
|
| 35 |
-
LTXV_FRAME_LOG_EVERY=8
|
| 36 |
-
|
| 37 |
-
# Singletons do projeto para VAE e Encoder
|
| 38 |
-
from tools.video_encode_tool import video_encode_tool_singleton
|
| 39 |
-
from managers.vae_manager import vae_manager_singleton
|
| 40 |
|
| 41 |
# --- 2. GERENCIAMENTO DE DEPENDÊNCIAS E SETUP ---
|
| 42 |
def _query_gpu_processes_via_nvml(device_index: int) -> List[Dict]:
|
|
@@ -61,6 +56,7 @@ def _query_gpu_processes_via_nvml(device_index: int) -> List[Dict]:
|
|
| 61 |
name = "unknown"
|
| 62 |
user = "unknown"
|
| 63 |
try:
|
|
|
|
| 64 |
pr = psutil.Process(pid)
|
| 65 |
name = pr.name()
|
| 66 |
user = pr.username()
|
|
@@ -126,18 +122,6 @@ if not LTX_VIDEO_REPO_DIR.exists():
|
|
| 126 |
print(f"[DEBUG] Repositório não encontrado em {LTX_VIDEO_REPO_DIR}. Rodando setup...")
|
| 127 |
run_setup()
|
| 128 |
|
| 129 |
-
|
| 130 |
-
from api.ltx.inference import (
|
| 131 |
-
create_ltx_video_pipeline,
|
| 132 |
-
create_latent_upsampler,
|
| 133 |
-
load_image_to_tensor_with_resize_and_crop,
|
| 134 |
-
seed_everething,
|
| 135 |
-
calculate_padding,
|
| 136 |
-
load_media_file,
|
| 137 |
-
)
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
def add_deps_to_path():
|
| 142 |
repo_path = str(LTX_VIDEO_REPO_DIR.resolve())
|
| 143 |
if str(LTX_VIDEO_REPO_DIR.resolve()) not in sys.path:
|
|
@@ -147,6 +131,14 @@ def add_deps_to_path():
|
|
| 147 |
add_deps_to_path()
|
| 148 |
|
| 149 |
# --- 3. IMPORTAÇÕES ESPECÍFICAS DO MODELO ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
from ltx_video.pipelines.pipeline_ltx_video import ConditioningItem, LTXMultiScalePipeline
|
| 151 |
from ltx_video.utils.skip_layer_strategy import SkipLayerStrategy
|
| 152 |
|
|
@@ -191,6 +183,14 @@ class VideoService:
|
|
| 191 |
self._apply_precision_policy()
|
| 192 |
print(f"[DEBUG] runtime_autocast_dtype = {getattr(self, 'runtime_autocast_dtype', None)}")
|
| 193 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
if self.device == "cuda":
|
| 195 |
torch.cuda.empty_cache()
|
| 196 |
self._log_gpu_memory("Após carregar modelos")
|
|
@@ -513,7 +513,6 @@ class VideoService:
|
|
| 513 |
result = multi_scale_pipeline(**multi_scale_call_kwargs)
|
| 514 |
print(f"[DEBUG] multi_scale_pipeline tempo={time.perf_counter()-t_ms:.3f}s")
|
| 515 |
|
| 516 |
-
# Captura latentes
|
| 517 |
if hasattr(result, "latents"):
|
| 518 |
latents = result.latents
|
| 519 |
elif hasattr(result, "images") and isinstance(result.images, torch.Tensor):
|
|
@@ -561,24 +560,20 @@ class VideoService:
|
|
| 561 |
output_video_path = os.path.join(temp_dir, f"output_{used_seed}.mp4")
|
| 562 |
final_output_path = None
|
| 563 |
|
|
|
|
|
|
|
| 564 |
pixel_tensor = vae_manager_singleton.decode(
|
| 565 |
latents.to(self.device, non_blocking=True),
|
| 566 |
decode_timestep=float(self.config.get("decode_timestep", 0.05))
|
| 567 |
)
|
| 568 |
-
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
print("[DEBUG] Decodificando bloco de latentes com VAE → tensor de pixels...")
|
| 572 |
-
# Se desejar “desocupar” a GPU antes do decode, pode-se mover p/ CPU e limpar:
|
| 573 |
-
# latents_cpu = latents.detach().to("cpu", non_blocking=True); torch.cuda.empty_cache(); torch.cuda.ipc_collect(); latents = latents_cpu.to(self.device)
|
| 574 |
-
pixel_tensor = vae_manager_singleton.decode(latents.to(self.device, non_blocking=True))
|
| 575 |
log_tensor_info(pixel_tensor, "Pixel tensor (VAE saída)")
|
| 576 |
|
| 577 |
print("[DEBUG] Codificando MP4 a partir do tensor de pixels (bloco inteiro)...")
|
| 578 |
video_encode_tool_singleton.save_video_from_tensor(
|
| 579 |
pixel_tensor,
|
| 580 |
output_video_path,
|
| 581 |
-
fps=call_kwargs["frame_rate"]
|
|
|
|
| 582 |
)
|
| 583 |
|
| 584 |
candidate_final = os.path.join(results_dir, f"output_{used_seed}.mp4")
|
|
@@ -627,4 +622,3 @@ class VideoService:
|
|
| 627 |
|
| 628 |
print("Criando instância do VideoService. O carregamento do modelo começará agora...")
|
| 629 |
video_generation_service = VideoService()
|
| 630 |
-
|
|
|
|
| 1 |
+
# ltx_server.py — VideoService (beta 1.1)
|
| 2 |
# Sempre output_type="latent"; no final: VAE (bloco inteiro) → pixels → MP4.
|
| 3 |
+
# Ignora UserWarning/FutureWarning e injeta VAE no manager com dtype/device corretos.
|
| 4 |
+
|
| 5 |
+
# --- 0. WARNINGS E AMBIENTE ---
|
| 6 |
+
import warnings
|
| 7 |
+
warnings.filterwarnings("ignore", category=UserWarning)
|
| 8 |
+
warnings.filterwarnings("ignore", category=FutureWarning)
|
| 9 |
+
warnings.filterwarnings("ignore", message=".*torch.meshgrid.*indexing.*")
|
| 10 |
+
warnings.filterwarnings("ignore", message=".*Accessing config attribute `in_channels`.*")
|
| 11 |
|
| 12 |
# --- 1. IMPORTAÇÕES ---
|
| 13 |
import torch
|
|
|
|
| 29 |
import time
|
| 30 |
import traceback
|
| 31 |
|
| 32 |
+
# Singletons (versões simples)
|
| 33 |
+
from vae_manager import vae_manager_singleton
|
| 34 |
+
from video_encode_tool import video_encode_tool_singleton
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
# --- 2. GERENCIAMENTO DE DEPENDÊNCIAS E SETUP ---
|
| 37 |
def _query_gpu_processes_via_nvml(device_index: int) -> List[Dict]:
|
|
|
|
| 56 |
name = "unknown"
|
| 57 |
user = "unknown"
|
| 58 |
try:
|
| 59 |
+
import psutil
|
| 60 |
pr = psutil.Process(pid)
|
| 61 |
name = pr.name()
|
| 62 |
user = pr.username()
|
|
|
|
| 122 |
print(f"[DEBUG] Repositório não encontrado em {LTX_VIDEO_REPO_DIR}. Rodando setup...")
|
| 123 |
run_setup()
|
| 124 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
def add_deps_to_path():
|
| 126 |
repo_path = str(LTX_VIDEO_REPO_DIR.resolve())
|
| 127 |
if str(LTX_VIDEO_REPO_DIR.resolve()) not in sys.path:
|
|
|
|
| 131 |
add_deps_to_path()
|
| 132 |
|
| 133 |
# --- 3. IMPORTAÇÕES ESPECÍFICAS DO MODELO ---
|
| 134 |
+
from inference import (
|
| 135 |
+
create_ltx_video_pipeline,
|
| 136 |
+
create_latent_upsampler,
|
| 137 |
+
load_image_to_tensor_with_resize_and_crop,
|
| 138 |
+
seed_everething,
|
| 139 |
+
calculate_padding,
|
| 140 |
+
load_media_file,
|
| 141 |
+
)
|
| 142 |
from ltx_video.pipelines.pipeline_ltx_video import ConditioningItem, LTXMultiScalePipeline
|
| 143 |
from ltx_video.utils.skip_layer_strategy import SkipLayerStrategy
|
| 144 |
|
|
|
|
| 183 |
self._apply_precision_policy()
|
| 184 |
print(f"[DEBUG] runtime_autocast_dtype = {getattr(self, 'runtime_autocast_dtype', None)}")
|
| 185 |
|
| 186 |
+
# Injeta pipeline/vae no manager (impede vae=None)
|
| 187 |
+
vae_manager_singleton.attach_pipeline(
|
| 188 |
+
self.pipeline,
|
| 189 |
+
device=self.device,
|
| 190 |
+
autocast_dtype=self.runtime_autocast_dtype
|
| 191 |
+
)
|
| 192 |
+
print(f"[DEBUG] VAE manager conectado: has_vae={hasattr(self.pipeline, 'vae')} device={self.device}")
|
| 193 |
+
|
| 194 |
if self.device == "cuda":
|
| 195 |
torch.cuda.empty_cache()
|
| 196 |
self._log_gpu_memory("Após carregar modelos")
|
|
|
|
| 513 |
result = multi_scale_pipeline(**multi_scale_call_kwargs)
|
| 514 |
print(f"[DEBUG] multi_scale_pipeline tempo={time.perf_counter()-t_ms:.3f}s")
|
| 515 |
|
|
|
|
| 516 |
if hasattr(result, "latents"):
|
| 517 |
latents = result.latents
|
| 518 |
elif hasattr(result, "images") and isinstance(result.images, torch.Tensor):
|
|
|
|
| 560 |
output_video_path = os.path.join(temp_dir, f"output_{used_seed}.mp4")
|
| 561 |
final_output_path = None
|
| 562 |
|
| 563 |
+
print("[DEBUG] Decodificando bloco de latentes com VAE → tensor de pixels...")
|
| 564 |
+
# Usar manager com timestep por item; previne target_shape e rota NoneType.decode
|
| 565 |
pixel_tensor = vae_manager_singleton.decode(
|
| 566 |
latents.to(self.device, non_blocking=True),
|
| 567 |
decode_timestep=float(self.config.get("decode_timestep", 0.05))
|
| 568 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 569 |
log_tensor_info(pixel_tensor, "Pixel tensor (VAE saída)")
|
| 570 |
|
| 571 |
print("[DEBUG] Codificando MP4 a partir do tensor de pixels (bloco inteiro)...")
|
| 572 |
video_encode_tool_singleton.save_video_from_tensor(
|
| 573 |
pixel_tensor,
|
| 574 |
output_video_path,
|
| 575 |
+
fps=call_kwargs["frame_rate"],
|
| 576 |
+
progress_callback=progress_callback
|
| 577 |
)
|
| 578 |
|
| 579 |
candidate_final = os.path.join(results_dir, f"output_{used_seed}.mp4")
|
|
|
|
| 622 |
|
| 623 |
print("Criando instância do VideoService. O carregamento do modelo começará agora...")
|
| 624 |
video_generation_service = VideoService()
|
|
|