EuuIia commited on
Commit
1259f38
·
verified ·
1 Parent(s): 4eef400

Update api/ltx_server.py

Browse files
Files changed (1) hide show
  1. api/ltx_server.py +88 -29
api/ltx_server.py CHANGED
@@ -396,6 +396,38 @@ class VideoService:
396
  print(f"[DEBUG] Cond shape={tuple(out.shape)} dtype={out.dtype} device={out.device}")
397
  return out
398
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  # --- 6. GERAÇÃO ---
400
  def generate(
401
  self,
@@ -569,40 +601,67 @@ class VideoService:
569
  print(f"[DEBUG] Latentes (single-pass): shape={tuple(latents.shape)}")
570
 
571
  # Staging e escrita MP4 (simples: VAE → pixels → MP4)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
572
  temp_dir = tempfile.mkdtemp(prefix="ltxv_"); self._register_tmp_dir(temp_dir)
573
  results_dir = "/app/output"; os.makedirs(results_dir, exist_ok=True)
574
- output_video_path = os.path.join(temp_dir, f"output_{used_seed}.mp4")
575
- final_output_path = None
576
-
577
- print("[DEBUG] Decodificando bloco de latentes com VAE → tensor de pixels...")
578
- # Usar manager com timestep por item; previne target_shape e rota NoneType.decode
579
- pixel_tensor = vae_manager_singleton.decode(
580
- latents.to(self.device, non_blocking=True),
581
- decode_timestep=float(self.config.get("decode_timestep", 0.05))
582
- )
583
- log_tensor_info(pixel_tensor, "Pixel tensor (VAE saída)")
584
-
585
- print("[DEBUG] Codificando MP4 a partir do tensor de pixels (bloco inteiro)...")
586
- video_encode_tool_singleton.save_video_from_tensor(
587
- pixel_tensor,
588
- output_video_path,
589
- fps=call_kwargs["frame_rate"],
590
- progress_callback=progress_callback
591
- )
592
-
593
- candidate_final = os.path.join(results_dir, f"output_{used_seed}.mp4")
594
- try:
595
- shutil.move(output_video_path, candidate_final)
596
- final_output_path = candidate_final
597
- print(f"[DEBUG] MP4 movido para {final_output_path}")
598
- except Exception as e:
599
- final_output_path = output_video_path
600
- print(f"[DEBUG] Falha no move; usando tmp como final: {e}")
601
 
602
- self._register_tmp_file(output_video_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  self._log_gpu_memory("Fim da Geração")
604
  print(f"[DEBUG] generate() fim ok. total_time={time.perf_counter()-t_all:.3f}s")
605
- return final_output_path, used_seed
 
606
 
607
  except Exception as e:
608
  print("[DEBUG] EXCEÇÃO NA GERAÇÃO:")
 
396
  print(f"[DEBUG] Cond shape={tuple(out.shape)} dtype={out.dtype} device={out.device}")
397
  return out
398
 
399
+ def dividir_latentes(latents_brutos):
400
+ total = latents_brutos.shape[2] # dimensão temporal (latentes)
401
+
402
+ if total % 2 == 1: # ÍMPAR
403
+ cut = total // 2
404
+ primeira = latents_brutos[:, :, :cut+1, :, :].clone()
405
+ segunda = latents_brutos[:, :, cut:, :, :].clone()
406
+ else: # PAR
407
+ cut = total // 2
408
+ # primeira parte até o meio, mas o último frame deve ser ajustado
409
+ primeira = latents_brutos[:, :, :cut+1, :, :].clone()
410
+ segunda = latents_brutos[:, :, cut:, :, :].clone()
411
+
412
+ return primeira, segunda
413
+
414
+ def _concat_mp4s_no_reencode(self, mp4_a: str, mp4_b: str, out_path: str):
415
+ # Concat demuxer do ffmpeg (sem reencode)
416
+ import tempfile, subprocess, shlex, os
417
+ with tempfile.NamedTemporaryFile("w", delete=False, suffix=".txt") as f:
418
+ f.write(f"file '{os.path.abspath(mp4_a)}'\n")
419
+ f.write(f"file '{os.path.abspath(mp4_b)}'\n")
420
+ list_path = f.name
421
+ cmd = f"ffmpeg -y -f concat -safe 0 -i {list_path} -c copy {out_path}"
422
+ print(f"[DEBUG] Concat: {cmd}")
423
+ try:
424
+ subprocess.check_call(shlex.split(cmd))
425
+ finally:
426
+ try: os.remove(list_path)
427
+ except Exception: pass
428
+
429
+
430
+
431
  # --- 6. GERAÇÃO ---
432
  def generate(
433
  self,
 
601
  print(f"[DEBUG] Latentes (single-pass): shape={tuple(latents.shape)}")
602
 
603
  # Staging e escrita MP4 (simples: VAE → pixels → MP4)
604
+
605
+ latents_cpu = latents.detach().to("cpu", non_blocking=True)
606
+ torch.cuda.empty_cache()
607
+ try:
608
+ torch.cuda.ipc_collect()
609
+ except Exception:
610
+ pass
611
+
612
+ # 2) Divide em duas partes
613
+ lat_a, lat_b = dividir_latentes(latents_cpu)
614
+ print(f"[DEBUG] Partição A: {tuple(lat_a.shape)}")
615
+ print(f"[DEBUG] Partição B: {tuple(lat_b.shape)}")
616
+
617
+ latents_parts = [lat_a, lat_b]
618
+
619
  temp_dir = tempfile.mkdtemp(prefix="ltxv_"); self._register_tmp_dir(temp_dir)
620
  results_dir = "/app/output"; os.makedirs(results_dir, exist_ok=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
621
 
622
+ partes_mp4 = []
623
+ par = 0
624
+
625
+ for latents in latents_parts:
626
+ par = par + 1
627
+ output_video_path = os.path.join(temp_dir, f"output_{used_seed}_{par}.mp4")
628
+ final_output_path = None
629
+
630
+ print("[DEBUG] Decodificando bloco de latentes com VAE → tensor de pixels...")
631
+ # Usar manager com timestep por item; previne target_shape e rota NoneType.decode
632
+ pixel_tensor = vae_manager_singleton.decode(
633
+ latents.to(self.device, non_blocking=True),
634
+ decode_timestep=float(self.config.get("decode_timestep", 0.05))
635
+ )
636
+ log_tensor_info(pixel_tensor, "Pixel tensor (VAE saída)")
637
+
638
+ print("[DEBUG] Codificando MP4 a partir do tensor de pixels (bloco inteiro)...")
639
+ video_encode_tool_singleton.save_video_from_tensor(
640
+ pixel_tensor,
641
+ output_video_path,
642
+ fps=call_kwargs["frame_rate"],
643
+ progress_callback=progress_callback
644
+ )
645
+
646
+ candidate_final = os.path.join(results_dir, f"output_{used_seed}.mp4")
647
+ try:
648
+ shutil.move(output_video_path, candidate_final)
649
+ final_output_path = candidate_final
650
+ print(f"[DEBUG] MP4 parte {par} movido para {final_output_path}")
651
+ partes_mp4.append(final_output_path)
652
+
653
+ except Exception as e:
654
+ final_output_path = output_video_path
655
+ print(f"[DEBUG] Falha no move; usando tmp como final: {e}")
656
+
657
+ final_concat_tmp = os.path.join(temp_dir, f"concat_{used_seed}.mp4")
658
+ self._concat_mp4s_no_reencode(partes_mp4[0], partes_mp4[1], final_concat_tmp)
659
+
660
+ self._register_tmp_file(final_concat_tmp)
661
  self._log_gpu_memory("Fim da Geração")
662
  print(f"[DEBUG] generate() fim ok. total_time={time.perf_counter()-t_all:.3f}s")
663
+ return final_concat_tmp, used_seed
664
+
665
 
666
  except Exception as e:
667
  print("[DEBUG] EXCEÇÃO NA GERAÇÃO:")