caarleexx commited on
Commit
bc7a0e0
·
verified ·
1 Parent(s): 3f5d2ec

Update api/ltx_server_refactored.py

Browse files
Files changed (1) hide show
  1. api/ltx_server_refactored.py +169 -0
api/ltx_server_refactored.py CHANGED
@@ -19,6 +19,14 @@ from pathlib import Path
19
  from typing import List, Dict, Optional, Tuple, Union
20
  import cv2
21
 
 
 
 
 
 
 
 
 
22
  # --- Configurações de Logging e Avisos ---
23
  warnings.filterwarnings("ignore", category=UserWarning)
24
  warnings.filterwarnings("ignore", category=FutureWarning)
@@ -247,6 +255,55 @@ class VideoService:
247
  RESULTS_DIR.mkdir(exist_ok=True)
248
  print(f"[INFO] VideoService pronto. Tempo de inicialização: {time.perf_counter()-t0:.2f}s")
249
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
  # --------------------------------------------------------------------------
251
  # --- Métodos Públicos (API do Serviço) ---
252
  # --------------------------------------------------------------------------
@@ -510,6 +567,8 @@ class VideoService:
510
  return final_video_path, final_latents_path, used_seed
511
 
512
 
 
 
513
  def refine_texture_only(
514
  self,
515
  latents_path: str,
@@ -518,6 +577,116 @@ class VideoService:
518
  guidance_scale: float,
519
  seed: Optional[int] = None,
520
  conditioning_items: Optional[List[ConditioningItem]] = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
521
  ) -> Tuple[str, str]:
522
  """
523
  ETAPA 2: Refina a textura dos latentes existentes.
 
19
  from typing import List, Dict, Optional, Tuple, Union
20
  import cv2
21
 
22
+
23
+
24
+ # --- GATILHO DE OTIMIZAÇÃO DE MEMÓRIA ---
25
+ # Se "1", "true", ou "yes" (ignorando maiúsculas/minúsculas), ativa o descarregamento de modelos.
26
+ # Por padrão, fica ativado para segurança em ambientes com VRAM limitada.
27
+ ENABLE_MEMORY_OPTIMIZATION = os.getenv("ADUC_MEMORY_OPTIMIZATION", "1").lower() in ["1", "true", "yes"]
28
+
29
+
30
  # --- Configurações de Logging e Avisos ---
31
  warnings.filterwarnings("ignore", category=UserWarning)
32
  warnings.filterwarnings("ignore", category=FutureWarning)
 
255
  RESULTS_DIR.mkdir(exist_ok=True)
256
  print(f"[INFO] VideoService pronto. Tempo de inicialização: {time.perf_counter()-t0:.2f}s")
257
 
258
+
259
+ # --------------------------------------------------------------------------
260
+ # --- Métodos de Gerenciamento de Memória (com Gatilho) ---
261
+ # --------------------------------------------------------------------------
262
+
263
+ def _set_generation_environment(self):
264
+ """Prepara a GPU para tarefas de geração (Transformer)."""
265
+ if not ENABLE_MEMORY_OPTIMIZATION:
266
+ if not next(self.pipeline.transformer.parameters()).is_cuda: self.pipeline.transformer.to(self.device)
267
+ if not next(self.pipeline.text_encoder.parameters()).is_cuda: self.pipeline.text_encoder.to(self.device)
268
+ if not next(self.pipeline.vae.parameters()).is_cuda: self.pipeline.vae.to(self.device)
269
+ return
270
+
271
+ print("\n [VRAM Manager] Otimização ATIVA. Configurando ambiente de GERAÇÃO...")
272
+ if next(self.pipeline.vae.parameters()).is_cuda:
273
+ self.pipeline.vae.to('cpu')
274
+ print(" - Modelo VAE movido para a CPU.")
275
+
276
+ if not next(self.pipeline.transformer.parameters()).is_cuda:
277
+ self.pipeline.transformer.to(self.device)
278
+ print(" - Modelo Transformer carregado na GPU.")
279
+ if not next(self.pipeline.text_encoder.parameters()).is_cuda:
280
+ self.pipeline.text_encoder.to(self.device)
281
+ print(" - Modelo Text Encoder carregado na GPU.")
282
+
283
+ torch.cuda.empty_cache()
284
+ print(" [VRAM Manager] Ambiente de GERAÇÃO pronto.\n")
285
+
286
+ def _set_decode_environment(self):
287
+ """Prepara a GPU para tarefas de decodificação (VAE)."""
288
+ if not ENABLE_MEMORY_OPTIMIZATION:
289
+ return
290
+
291
+ print("\n [VRAM Manager] Otimização ATIVA. Configurando ambiente de DECODIFICAÇÃO...")
292
+ if next(self.pipeline.transformer.parameters()).is_cuda:
293
+ self.pipeline.transformer.to('cpu')
294
+ print(" - Modelo Transformer movido para a CPU.")
295
+ if next(self.pipeline.text_encoder.parameters()).is_cuda:
296
+ self.pipeline.text_encoder.to('cpu')
297
+ print(" - Modelo Text Encoder movido para a CPU.")
298
+
299
+ if not next(self.pipeline.vae.parameters()).is_cuda:
300
+ self.pipeline.vae.to(self.device)
301
+ print(" - Modelo VAE carregado na GPU.")
302
+
303
+ torch.cuda.empty_cache()
304
+ print(" [VRAM Manager] Ambiente de DECODIFICAÇÃO pronto.\n")
305
+
306
+
307
  # --------------------------------------------------------------------------
308
  # --- Métodos Públicos (API do Serviço) ---
309
  # --------------------------------------------------------------------------
 
567
  return final_video_path, final_latents_path, used_seed
568
 
569
 
570
+
571
+
572
  def refine_texture_only(
573
  self,
574
  latents_path: str,
 
577
  guidance_scale: float,
578
  seed: Optional[int] = None,
579
  conditioning_items: Optional[List[ConditioningItem]] = None
580
+ ) -> Tuple[str, str]:
581
+ """
582
+ Refina e decodifica latentes com gerenciamento explícito de modelos
583
+ na GPU para máxima performance e robustez ("hot-swap").
584
+ """
585
+ print("\n======================================================================")
586
+ print("====== [INFO] Iniciando ETAPA 2: Refinamento e Decodificação com Hot-Swap ======")
587
+ print("======================================================================\n")
588
+
589
+ temp_dir = tempfile.mkdtemp(prefix="ltxv_refine_")
590
+ self._register_tmp_dir(temp_dir)
591
+ used_seed = random.randint(0, 2**32 - 1) if seed is None else int(seed)
592
+
593
+ # --- FASE 1: GERAÇÃO DE LATENTES (TRABALHO DO TRANSFORMER) ---
594
+ print("[LOG] FASE 1: Geração de Latentes (Transformer na GPU)")
595
+ self._set_generation_environment()
596
+
597
+ latents_to_refine = torch.load(latents_path).to(self.device)
598
+ print(f" [LOG] Latentes carregados para a GPU. Shape: {latents_to_refine.shape}")
599
+
600
+ with torch.autocast(device_type=self.device.split(':')[0], dtype=self.runtime_autocast_dtype, enabled=(self.device == 'cuda')):
601
+ refine_height = latents_to_refine.shape[3] * self.pipeline.vae_scale_factor
602
+ refine_width = latents_to_refine.shape[4] * self.pipeline.vae_scale_factor
603
+ second_pass_kwargs = {
604
+ "prompt": prompt, "negative_prompt": negative_prompt, "height": refine_height, "width": refine_width,
605
+ "frame_rate": int(DEFAULT_FPS), "num_frames": latents_to_refine.shape[2],
606
+ "latents": latents_to_refine, "guidance_scale": float(guidance_scale), "output_type": "latent",
607
+ "generator": torch.Generator(device=self.device).manual_seed(used_seed),
608
+ "conditioning_items": conditioning_items, **(self.config.get("second_pass", {}))
609
+ }
610
+ print(" [LOG] Enviando para a pipeline de refinamento (Transformer)...")
611
+ final_latents = self.pipeline(**second_pass_kwargs).images
612
+ print(f" [LOG] [SUCESSO] Latentes refinados. Shape: {final_latents.shape}")
613
+
614
+ print(" [LOG] Geração de latentes concluída. Movendo resultado para a CPU.")
615
+ final_latents_cpu = final_latents.cpu()
616
+ del final_latents, latents_to_refine
617
+
618
+ # --- FASE 2: DECODIFICAÇÃO EM CHUNKS (TRABALHO DO VAE) ---
619
+ print("\n[LOG] FASE 2: Decodificação de Latentes (VAE na GPU)")
620
+ self._set_decode_environment()
621
+
622
+ total_latents = final_latents_cpu.shape[2]
623
+ if total_latents <= 10:
624
+ print(f" [LOG] Detecção: Vídeo curto ({total_latents} latentes). Usando decodificação direta.")
625
+ pixel_tensor = vae_manager_singleton.decode(
626
+ final_latents_cpu.to(self.device),
627
+ decode_timestep=float(self.config.get("decode_timestep", 0.05))
628
+ ).cpu()
629
+ else:
630
+ print(f" [LOG] Detecção: Vídeo longo ({total_latents} latentes). Ativando modo de janela deslizante.")
631
+ sobreposicao = 2
632
+ tamanho_base = (total_latents - 1) // 3
633
+ pontos_de_corte = [
634
+ (0, tamanho_base + sobreposicao),
635
+ (tamanho_base - sobreposicao, (2 * tamanho_base) + sobreposicao),
636
+ ((2 * tamanho_base) - sobreposicao, total_latents)
637
+ ]
638
+
639
+ pixel_chunks_list = []
640
+ for i, (start, end) in enumerate(pontos_de_corte):
641
+ latent_chunk = final_latents_cpu[:, :, start:end, :, :]
642
+ print(f" -> Decodificando Grupo {i+1} (latentes {start} a {end-1}), shape: {latent_chunk.shape}")
643
+ pixel_chunk = vae_manager_singleton.decode(
644
+ latent_chunk.to(self.device),
645
+ decode_timestep=float(self.config.get("decode_timestep", 0.05))
646
+ )
647
+ pixel_chunks_list.append(pixel_chunk.cpu())
648
+ torch.cuda.empty_cache()
649
+
650
+ print(" [LOG] Costurando os vídeos decodificados...")
651
+ frames_p1 = tamanho_base * 8
652
+ parte1 = pixel_chunks_list[0][:, :, :frames_p1, :, :]
653
+ descarte_inicio_p2 = sobreposicao * 8
654
+ frames_p2 = tamanho_base * 8
655
+ parte2 = pixel_chunks_list[1][:, :, descarte_inicio_p2 : descarte_inicio_p2 + frames_p2, :, :]
656
+ descarte_inicio_p3 = sobreposicao * 8
657
+ parte3 = pixel_chunks_list[2][:, :, descarte_inicio_p3:, :, :]
658
+ pixel_tensor = torch.cat([parte1, parte2, parte3], dim=2)
659
+
660
+ print(f"\n[LOG] [SUCESSO] Tensor de pixels final montado na CPU com shape: {pixel_tensor.shape}")
661
+
662
+ # --- FASE 3: SALVAMENTO E RESTAURAÇÃO DO AMBIENTE ---
663
+ print("\n[LOG] FASE 3: Salvamento e Restauração do Ambiente da GPU")
664
+
665
+ video_path_out = self._save_video_from_tensor(pixel_tensor, "refined_video_final", used_seed, temp_dir)
666
+ latents_path_out = self._save_latents_to_disk(final_latents_cpu, "latents_refined_final", used_seed)
667
+
668
+ print(" [LOG] Tarefa concluída. Restaurando ambiente de GERAÇÃO na GPU para a próxima execução...")
669
+ self._set_generation_environment()
670
+
671
+ print(" [LOG] Liberando tensores finais da memória da CPU.")
672
+ del pixel_tensor, final_latents_cpu
673
+ self._finalize()
674
+
675
+ print("\n======================================================================")
676
+ print("============ [SUCCESS] ETAPA 2 Concluída com Sucesso =============")
677
+ print("======================================================================\n")
678
+ return video_path_out, latents_path_out
679
+
680
+
681
+
682
+ def refine_texture_only1(
683
+ self,
684
+ latents_path: str,
685
+ prompt: str,
686
+ negative_prompt: str,
687
+ guidance_scale: float,
688
+ seed: Optional[int] = None,
689
+ conditioning_items: Optional[List[ConditioningItem]] = None
690
  ) -> Tuple[str, str]:
691
  """
692
  ETAPA 2: Refina a textura dos latentes existentes.