caarleexx commited on
Commit
a2fb210
·
verified ·
1 Parent(s): 6966f74

Update api/ltx_server_refactored.py

Browse files
Files changed (1) hide show
  1. api/ltx_server_refactored.py +145 -1
api/ltx_server_refactored.py CHANGED
@@ -509,7 +509,7 @@ class VideoService:
509
  print("[SUCCESS] ETAPA 1 Concluída.")
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 +518,150 @@ 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 SEM alterar sua resolução
 
509
  print("[SUCCESS] ETAPA 1 Concluída.")
510
  return final_video_path, final_latents_path, used_seed
511
 
512
+
513
  def refine_texture_only(
514
  self,
515
  latents_path: str,
 
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.
524
+ Implementa uma decodificação VAE com janela deslizante para processar vídeos longos
525
+ sem estourar a memória da GPU, preservando a continuidade temporal.
526
+ """
527
+ print("\n======================================================================")
528
+ print("====== [INFO] Iniciando ETAPA 2: Refinamento de Textura Detalhado ======")
529
+ print("======================================================================\n")
530
+
531
+ # --- FASE 1: Configuração e Preparação ---
532
+ print("[LOG] FASE 1: Configuração e Preparação")
533
+ used_seed = random.randint(0, 2**32 - 1) if seed is None else int(seed)
534
+ print(f" [LOG] Seed a ser utilizado (consistente com Etapa 1): {used_seed}")
535
+
536
+ temp_dir = tempfile.mkdtemp(prefix="ltxv_refine_")
537
+ self._register_tmp_dir(temp_dir)
538
+ print(f" [LOG] Diretório temporário para artefatos criado em: {temp_dir}")
539
+
540
+ print(f" [LOG] Carregando latentes de baixa resolução de: {latents_path}")
541
+ latents_to_refine = torch.load(latents_path).to(self.device)
542
+ print(f" [LOG] Latentes carregados para a GPU. Shape: {latents_to_refine.shape}, Dtype: {latents_to_refine.dtype}")
543
+
544
+ if conditioning_items:
545
+ print(f" [LOG] {len(conditioning_items)} item(ns) de condicionamento serão utilizados no refinamento.")
546
+
547
+ # --- FASE 2: Execução do Refinamento (Transformer) ---
548
+ print("\n[LOG] FASE 2: Execução do Refinamento (Transformer Pass)")
549
+ with torch.autocast(device_type=self.device.split(':')[0], dtype=self.runtime_autocast_dtype, enabled=(self.device == 'cuda')):
550
+
551
+ refine_height = latents_to_refine.shape[3] * self.pipeline.vae_scale_factor
552
+ refine_width = latents_to_refine.shape[4] * self.pipeline.vae_scale_factor
553
+ print(f" [LOG] Dimensões alvo para o refinamento: {refine_height}x{refine_width}")
554
+
555
+ second_pass_kwargs = {
556
+ "prompt": prompt, "negative_prompt": negative_prompt,
557
+ "height": refine_height, "width": refine_width,
558
+ "frame_rate": int(DEFAULT_FPS), "num_frames": latents_to_refine.shape[2],
559
+ "latents": latents_to_refine, "guidance_scale": float(guidance_scale),
560
+ "output_type": "latent",
561
+ "generator": torch.Generator(device=self.device).manual_seed(used_seed),
562
+ "conditioning_items": conditioning_items,
563
+ **(self.config.get("second_pass", {}))
564
+ }
565
+
566
+ print(" [LOG] Enviando tensor completo para a pipeline de refinamento (Transformer)...")
567
+ final_latents = self.pipeline(**second_pass_kwargs).images
568
+ print(f" [LOG] [SUCESSO] Latentes refinados pelo Transformer. Shape resultante: {final_latents.shape}")
569
+
570
+ # --- FASE 3: Decodificação VAE com Janela Deslizante ---
571
+ print("\n[LOG] FASE 3: Decodificação VAE com Lógica de Janela Deslizante")
572
+
573
+ print(" [LOG] Gerenciamento de Memória: Movendo tensor de latentes refinados para a CPU...")
574
+ final_latents_cpu = final_latents.cpu()
575
+ print(" [LOG] Gerenciamento de Memória: Liberando tensores da VRAM para maximizar espaço para o VAE.")
576
+ del final_latents, latents_to_refine
577
+ torch.cuda.empty_cache()
578
+
579
+ total_latents = final_latents_cpu.shape[2]
580
+
581
+ # Caso 1: Vídeo curto. Processo simplificado.
582
+ if total_latents <= 10:
583
+ print(f" [LOG] Detecção: Vídeo curto ({total_latents} latentes <= 10). Usando decodificação direta.")
584
+ pixel_tensor = vae_manager_singleton.decode(
585
+ final_latents_cpu.to(self.device),
586
+ decode_timestep=float(self.config.get("decode_timestep", 0.05))
587
+ ).cpu()
588
+
589
+ # Caso 2: Vídeo longo. Aplica sua lógica de 3 grupos.
590
+ else:
591
+ print(f" [LOG] Detecção: Vídeo longo ({total_latents} latentes). Ativando modo de janela deslizante.")
592
+ # 3.1: Cálculo dos Pontos de Corte
593
+ print(" [LOG] 3.1: Calculando janelas de decodificação (grupos)...")
594
+ sobreposicao = 2
595
+ tamanho_base = (total_latents - 1) // 3
596
+ print(f" [CALC] Total Latentes: {total_latents}, Sobreposição: {sobreposicao}, Tamanho Base por Grupo: {tamanho_base}")
597
+
598
+ pontos_de_corte = [
599
+ (0, tamanho_base + sobreposicao),
600
+ (tamanho_base - sobreposicao, (2 * tamanho_base) + sobreposicao),
601
+ ((2 * tamanho_base) - sobreposicao, total_latents)
602
+ ]
603
+ print(f" [CALC] Pontos de corte definidos: Grupo 1 ({pontos_de_corte[0][0]}-{pontos_de_corte[0][1]-1}), Grupo 2 ({pontos_de_corte[1][0]}-{pontos_de_corte[1][1]-1}), Grupo 3 ({pontos_de_corte[2][0]}-{pontos_de_corte[2][1]-1})")
604
+
605
+ # 3.2: Decodificação dos Chunks em Loop
606
+ print("\n [LOG] 3.2: Decodificando cada grupo em loop...")
607
+ pixel_chunks_list = []
608
+ for i, (start, end) in enumerate(pontos_de_corte):
609
+ latent_chunk = final_latents_cpu[:, :, start:end, :, :]
610
+ print(f" [LOOP] Processando Grupo {i+1}/{len(pontos_de_corte)} (latentes {start} a {end-1}), shape: {latent_chunk.shape}")
611
+
612
+ pixel_chunk = vae_manager_singleton.decode(
613
+ latent_chunk.to(self.device),
614
+ decode_timestep=float(self.config.get("decode_timestep", 0.05))
615
+ )
616
+ print(f" [VAE] Grupo {i+1} decodificado. Shape de pixels resultante: {pixel_chunk.shape}")
617
+ pixel_chunks_list.append(pixel_chunk.cpu())
618
+ print(f" [VRAM] Resultado movido para CPU. Limpando VRAM para o próximo grupo.")
619
+ torch.cuda.empty_cache()
620
+
621
+ # 3.3: Costura Inteligente dos Vídeos
622
+ print("\n [LOG] 3.3: Costurando os vídeos decodificados para montagem final...")
623
+
624
+ frames_p1 = tamanho_base * 8
625
+ parte1 = pixel_chunks_list[0][:, :, :frames_p1, :, :]
626
+ print(f" [STITCH] Parte 1 (do Grupo 1): Pegando os primeiros {frames_p1} frames. Shape: {parte1.shape}")
627
+
628
+ descarte_inicio_p2 = sobreposicao * 8
629
+ frames_p2 = tamanho_base * 8
630
+ parte2 = pixel_chunks_list[1][:, :, descarte_inicio_p2 : descarte_inicio_p2 + frames_p2, :, :]
631
+ print(f" [STITCH] Parte 2 (do Grupo 2): Descartando {descarte_inicio_p2} frames, pegando os próximos {frames_p2}. Shape: {parte2.shape}")
632
+
633
+ descarte_inicio_p3 = sobreposicao * 8
634
+ parte3 = pixel_chunks_list[2][:, :, descarte_inicio_p3:, :, :]
635
+ print(f" [STITCH] Parte 3 (do Grupo 3): Descartando {descarte_inicio_p3} frames, pegando todo o resto. Shape: {parte3.shape}")
636
+
637
+ pixel_tensor = torch.cat([parte1, parte2, parte3], dim=2)
638
+
639
+ print(f"\n[LOG] [SUCESSO] Tensor de pixels final montado com shape: {pixel_tensor.shape}")
640
+
641
+ # --- FASE 4: Salvamento e Limpeza ---
642
+ print("\n[LOG] FASE 4: Salvamento dos Artefatos Finais e Limpeza")
643
+ video_path_out = self._save_video_from_tensor(pixel_tensor, "refined_video_final", used_seed, temp_dir)
644
+ print(f" [LOG] Vídeo final salvo em: {video_path_out}")
645
+ latents_path_out = self._save_latents_to_disk(final_latents_cpu, "latents_refined_final", used_seed)
646
+ print(f" [LOG] Latentes refinados finais (CPU) salvos em: {latents_path_out}")
647
+
648
+ print(" [LOG] Liberando tensores finais da memória.")
649
+ del pixel_tensor, final_latents_cpu
650
+ self._finalize()
651
+
652
+ print("\n======================================================================")
653
+ print("============ [SUCCESS] ETAPA 2 Concluída com Sucesso =============")
654
+ print("======================================================================\n")
655
+ return video_path_out, latents_path_out
656
+
657
+ def refine_texture_only1(
658
+ self,
659
+ latents_path: str,
660
+ prompt: str,
661
+ negative_prompt: str,
662
+ guidance_scale: float,
663
+ seed: Optional[int] = None,
664
+ conditioning_items: Optional[List[ConditioningItem]] = None
665
  ) -> Tuple[str, str]:
666
  """
667
  ETAPA 2: Refina a textura dos latentes existentes SEM alterar sua resolução