Eueuiaa commited on
Commit
a65518f
·
verified ·
1 Parent(s): 39769b3

Update api/ltx_server.py

Browse files
Files changed (1) hide show
  1. api/ltx_server.py +90 -72
api/ltx_server.py CHANGED
@@ -366,31 +366,57 @@ class VideoService:
366
  return yaml.safe_load(file)
367
 
368
  def _load_models(self):
 
 
 
 
 
 
369
  t0 = time.perf_counter()
370
  LTX_REPO = "Lightricks/LTX-Video"
371
- print("[DEBUG] Baixando checkpoint principal...")
372
- distilled_model_path = hf_hub_download(
373
- repo_id=LTX_REPO,
374
- filename=self.config["checkpoint_path"],
375
- local_dir=os.getenv("HF_HOME"),
376
- cache_dir=os.getenv("HF_HOME_CACHE"),
377
- token=os.getenv("HF_TOKEN"),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
  )
379
  self.config["checkpoint_path"] = distilled_model_path
380
- print(f"[DEBUG] Checkpoint em: {distilled_model_path}")
381
-
382
- print("[DEBUG] Baixando upscaler espacial...")
383
- spatial_upscaler_path = hf_hub_download(
384
- repo_id=LTX_REPO,
385
- filename=self.config["spatial_upscaler_model_path"],
386
- local_dir=os.getenv("HF_HOME"),
387
- cache_dir=os.getenv("HF_HOME_CACHE"),
388
- token=os.getenv("HF_TOKEN")
389
  )
390
  self.config["spatial_upscaler_model_path"] = spatial_upscaler_path
391
- print(f"[DEBUG] Upscaler em: {spatial_upscaler_path}")
392
 
393
- print("[DEBUG] Construindo pipeline...")
 
394
  pipeline = create_ltx_video_pipeline(
395
  ckpt_path=self.config["checkpoint_path"],
396
  precision=self.config["precision"],
@@ -408,6 +434,7 @@ class VideoService:
408
  print("[DEBUG] Construindo latent_upsampler...")
409
  latent_upsampler = create_latent_upsampler(self.config["spatial_upscaler_model_path"], device="cpu")
410
  print("[DEBUG] Upsampler pronto.")
 
411
  print(f"[DEBUG] _load_models() tempo total={time.perf_counter()-t0:.3f}s")
412
  return pipeline, latent_upsampler
413
 
@@ -435,8 +462,6 @@ class VideoService:
435
  pass
436
  print(f"[DEBUG] FP8→BF16: params_promoted={p_cnt}, buffers_promoted={b_cnt}")
437
 
438
-
439
-
440
  @torch.no_grad()
441
  def _upsample_latents_internal(self, latents: torch.Tensor) -> torch.Tensor:
442
  """
@@ -453,11 +478,8 @@ class VideoService:
453
  upsampled_latents = self.latent_upsampler(latents)
454
  upsampled_latents = normalize_latents(upsampled_latents, self.pipeline.vae, vae_per_channel_normalize=True)
455
  print(f"[DEBUG-UPSAMPLE] Shape de saída: {tuple(upsampled_latents.shape)}")
456
-
457
  return upsampled_latents
458
 
459
-
460
-
461
  def _apply_precision_policy(self):
462
  prec = str(self.config.get("precision", "")).lower()
463
  self.runtime_autocast_dtype = torch.float32
@@ -491,7 +513,6 @@ class VideoService:
491
  print(f"[DEBUG] Cond shape={tuple(out.shape)} dtype={out.dtype} device={out.device}")
492
  return out
493
 
494
-
495
  def _dividir_latentes_por_tamanho(self, latents_brutos, num_latente_por_chunk: int, overlap: int = 1):
496
  """
497
  Divide o tensor de latentes em chunks com tamanho definido em número de latentes.
@@ -626,7 +647,6 @@ class VideoService:
626
  print(f"[DEBUG] Video podado {i+1} adicionado {self._get_total_frames(video_podado)} frames ✅")
627
 
628
 
629
-
630
  print("===========CONCATECAO CAUSAL=============")
631
  print(f"[DEBUG] {nova_lista}")
632
  return nova_lista
@@ -804,7 +824,7 @@ class VideoService:
804
  except Exception:
805
  pass
806
 
807
- latents_parts_up = self._dividir_latentes_por_tamanho(latents_cpu_up,15,1)
808
 
809
  for latents in latents_parts_up:
810
 
@@ -832,8 +852,8 @@ class VideoService:
832
  "output_type": "latent",
833
  "width": second_pass_width,
834
  "height": second_pass_height,
835
- #"num_frames": num_pixel_frames_part,
836
- "latents": upsampled_latents, # O tensor upscaled
837
  "guidance_scale": float(guidance_scale),
838
  **second_pass_config
839
  })
@@ -861,54 +881,52 @@ class VideoService:
861
 
862
  # --- ETAPA FINAL: DECODIFICAÇÃO E CODIFICAÇÃO MP4 ---
863
  print("\n--- INICIANDO ETAPA FINAL: DECODIFICAÇÃO E MONTAGEM ---")
 
 
864
 
865
- #latents_cpu = latents.detach().to("cpu", non_blocking=True)
866
- #torch.cuda.empty_cache()
867
- #try:
868
- # torch.cuda.ipc_collect()
869
- #except Exception:
870
- # pass
871
-
872
- latents_parts = []
873
- for latents in latents_list:
874
- latents_parts.append(self._dividir_latentes_por_tamanho(latents,15,1))
875
 
 
 
876
 
877
- partes_mp4 = []
878
- par = 0
879
- for latents in latents_parts:
880
-
881
- par = par + 1
882
- output_video_path = os.path.join(results_dir, f"output_{used_seed}_{par}.mp4")
883
- final_output_path = None
884
-
885
- print("[DEBUG] Decodificando bloco de latentes com VAE {par} → tensor de pixels...")
886
- # Usar manager com timestep por item; previne target_shape e rota NoneType.decode
887
- pixel_tensor = vae_manager_singleton.decode(
888
- latents.to(self.device, non_blocking=True),
889
- decode_timestep=float(self.config.get("decode_timestep", 0.05))
890
- )
891
- log_tensor_info(pixel_tensor, "Pixel tensor (VAE saída)")
892
-
893
- print("[DEBUG] Codificando MP4 a partir do tensor de pixels (bloco inteiro)...")
894
- video_encode_tool_singleton.save_video_from_tensor(
895
- pixel_tensor,
896
- output_video_path,
897
- fps=call_kwargs["frame_rate"],
898
- progress_callback=progress_callback
899
- )
 
 
 
 
 
 
 
900
 
901
- candidate = os.path.join(results_dir, f"output_par_{par}.mp4")
902
- try:
903
- shutil.move(output_video_path, candidate)
904
- final_output_path = candidate
905
- print(f"[DEBUG] MP4 parte {par} movido para {final_output_path}")
906
- partes_mp4.append(final_output_path)
907
-
908
- except Exception as e:
909
- final_output_path = output_video_path
910
- print(f"[DEBUG] Falha no move; usando tmp como final: {e}")
911
-
912
  total_partes = len(partes_mp4)
913
  if (total_partes>1):
914
  final_vid = os.path.join(results_dir, f"concat_fim_{used_seed}.mp4")
 
366
  return yaml.safe_load(file)
367
 
368
  def _load_models(self):
369
+ """
370
+ Carrega os modelos de forma inteligente:
371
+ 1. Tenta resolver o caminho do cache local (rápido, sem rede).
372
+ 2. Se o arquivo não for encontrado localmente, baixa como fallback.
373
+ Garante que o serviço possa iniciar mesmo que o setup.py não tenha sido executado.
374
+ """
375
  t0 = time.perf_counter()
376
  LTX_REPO = "Lightricks/LTX-Video"
377
+
378
+ print("[DEBUG] Resolvendo caminhos dos modelos de forma inteligente...")
379
+
380
+ # --- Função Auxiliar para Carregamento Inteligente ---
381
+ def get_or_download_model(repo_id, filename, description):
382
+ try:
383
+ # hf_hub_download é a ferramenta certa aqui. Ela verifica o cache PRIMEIRO.
384
+ # Se o arquivo estiver no cache, retorna o caminho instantaneamente (após uma verificação rápida de metadados).
385
+ # Se não estiver no cache, ela o baixa.
386
+ print(f"[DEBUG] Verificando {description}: {filename}...")
387
+ model_path = hf_hub_download(
388
+ repo_id=repo_id,
389
+ filename=filename,
390
+ # Forçar o uso de um cache específico se necessário
391
+ cache_dir=os.getenv("HF_HOME_CACHE"),
392
+ token=os.getenv("HF_TOKEN")
393
+ )
394
+ print(f"[DEBUG] Caminho do {description} resolvido com sucesso.")
395
+ return model_path
396
+ except Exception as e:
397
+ print("\n" + "="*80)
398
+ print(f"[ERRO CRÍTICO] Falha ao obter o modelo '{filename}'.")
399
+ print(f"Detalhe do erro: {e}")
400
+ print("Verifique sua conexão com a internet ou o estado do cache do Hugging Face.")
401
+ print("="*80 + "\n")
402
+ sys.exit(1)
403
+
404
+ # --- Checkpoint Principal ---
405
+ checkpoint_filename = self.config["checkpoint_path"]
406
+ distilled_model_path = get_or_download_model(
407
+ LTX_REPO, checkpoint_filename, "checkpoint principal"
408
  )
409
  self.config["checkpoint_path"] = distilled_model_path
410
+
411
+ # --- Upscaler Espacial ---
412
+ upscaler_filename = self.config["spatial_upscaler_model_path"]
413
+ spatial_upscaler_path = get_or_download_model(
414
+ LTX_REPO, upscaler_filename, "upscaler espacial"
 
 
 
 
415
  )
416
  self.config["spatial_upscaler_model_path"] = spatial_upscaler_path
 
417
 
418
+ # --- Construção dos Pipelines ---
419
+ print("\n[DEBUG] Construindo pipeline a partir dos caminhos resolvidos...")
420
  pipeline = create_ltx_video_pipeline(
421
  ckpt_path=self.config["checkpoint_path"],
422
  precision=self.config["precision"],
 
434
  print("[DEBUG] Construindo latent_upsampler...")
435
  latent_upsampler = create_latent_upsampler(self.config["spatial_upscaler_model_path"], device="cpu")
436
  print("[DEBUG] Upsampler pronto.")
437
+
438
  print(f"[DEBUG] _load_models() tempo total={time.perf_counter()-t0:.3f}s")
439
  return pipeline, latent_upsampler
440
 
 
462
  pass
463
  print(f"[DEBUG] FP8→BF16: params_promoted={p_cnt}, buffers_promoted={b_cnt}")
464
 
 
 
465
  @torch.no_grad()
466
  def _upsample_latents_internal(self, latents: torch.Tensor) -> torch.Tensor:
467
  """
 
478
  upsampled_latents = self.latent_upsampler(latents)
479
  upsampled_latents = normalize_latents(upsampled_latents, self.pipeline.vae, vae_per_channel_normalize=True)
480
  print(f"[DEBUG-UPSAMPLE] Shape de saída: {tuple(upsampled_latents.shape)}")
 
481
  return upsampled_latents
482
 
 
 
483
  def _apply_precision_policy(self):
484
  prec = str(self.config.get("precision", "")).lower()
485
  self.runtime_autocast_dtype = torch.float32
 
513
  print(f"[DEBUG] Cond shape={tuple(out.shape)} dtype={out.dtype} device={out.device}")
514
  return out
515
 
 
516
  def _dividir_latentes_por_tamanho(self, latents_brutos, num_latente_por_chunk: int, overlap: int = 1):
517
  """
518
  Divide o tensor de latentes em chunks com tamanho definido em número de latentes.
 
647
  print(f"[DEBUG] Video podado {i+1} adicionado {self._get_total_frames(video_podado)} frames ✅")
648
 
649
 
 
650
  print("===========CONCATECAO CAUSAL=============")
651
  print(f"[DEBUG] {nova_lista}")
652
  return nova_lista
 
824
  except Exception:
825
  pass
826
 
827
+ latents_parts_up = self._dividir_latentes_por_tamanho(latents_cpu_up,15,0)
828
 
829
  for latents in latents_parts_up:
830
 
 
852
  "output_type": "latent",
853
  "width": second_pass_width,
854
  "height": second_pass_height,
855
+ "num_frames": num_pixel_frames_part,
856
+ "latents": latents, # O tensor upscaled
857
  "guidance_scale": float(guidance_scale),
858
  **second_pass_config
859
  })
 
881
 
882
  # --- ETAPA FINAL: DECODIFICAÇÃO E CODIFICAÇÃO MP4 ---
883
  print("\n--- INICIANDO ETAPA FINAL: DECODIFICAÇÃO E MONTAGEM ---")
884
+
885
+ for latents_vae in latents_list:
886
 
887
+ latents_cpu_vae = latents_vae.detach().to("cpu", non_blocking=True)
888
+ torch.cuda.empty_cache()
889
+ try:
890
+ torch.cuda.ipc_collect()
891
+ except Exception:
892
+ pass
893
+
894
+ latents_parts_vae = self._dividir_latentes_por_tamanho(latents_cpu_vae,4,1)
 
 
895
 
896
+ for latents in latents_parts_vae:
897
+ print(f"[DEBUG] Partição {par}: {tuple(latents.shape)}")
898
 
899
+ par = par + 1
900
+ output_video_path = os.path.join(temp_dir, f"output_{used_seed}_{par}.mp4")
901
+ final_output_path = None
902
+
903
+ print("[DEBUG] Decodificando bloco de latentes com VAE → tensor de pixels...")
904
+ # Usar manager com timestep por item; previne target_shape e rota NoneType.decode
905
+ pixel_tensor = vae_manager_singleton.decode(
906
+ latents.to(self.device, non_blocking=True),
907
+ decode_timestep=float(self.config.get("decode_timestep", 0.05))
908
+ )
909
+ log_tensor_info(pixel_tensor, "Pixel tensor (VAE saída)")
910
+
911
+ print("[DEBUG] Codificando MP4 a partir do tensor de pixels (bloco inteiro)...")
912
+ video_encode_tool_singleton.save_video_from_tensor(
913
+ pixel_tensor,
914
+ output_video_path,
915
+ fps=call_kwargs["frame_rate"],
916
+ progress_callback=progress_callback
917
+ )
918
+
919
+ candidate = os.path.join(results_dir, f"output_par_{par}.mp4")
920
+ try:
921
+ shutil.move(output_video_path, candidate)
922
+ final_output_path = candidate
923
+ print(f"[DEBUG] MP4 parte {par} movido para {final_output_path}")
924
+ partes_mp4.append(final_output_path)
925
+
926
+ except Exception as e:
927
+ final_output_path = output_video_path
928
+ print(f"[DEBUG] Falha no move; usando tmp como final: {e}")
929
 
 
 
 
 
 
 
 
 
 
 
 
930
  total_partes = len(partes_mp4)
931
  if (total_partes>1):
932
  final_vid = os.path.join(results_dir, f"concat_fim_{used_seed}.mp4")