Update api/ltx_server.py
Browse files- api/ltx_server.py +66 -20
api/ltx_server.py
CHANGED
|
@@ -639,7 +639,17 @@ class VideoService:
|
|
| 639 |
|
| 640 |
conditioning_items = []
|
| 641 |
if mode == "image-to-video":
|
| 642 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 643 |
|
| 644 |
call_kwargs = {
|
| 645 |
"prompt": prompt, "negative_prompt": negative_prompt,
|
|
@@ -732,31 +742,67 @@ class VideoService:
|
|
| 732 |
print("\n--- INICIANDO ETAPA FINAL: DECODIFICAÇÃO E MONTAGEM ---")
|
| 733 |
|
| 734 |
latents_cpu = latents.detach().to("cpu", non_blocking=True)
|
| 735 |
-
|
| 736 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 737 |
temp_dir = tempfile.mkdtemp(prefix="ltxv_"); self._register_tmp_dir(temp_dir)
|
| 738 |
results_dir = "/app/output"; os.makedirs(results_dir, exist_ok=True)
|
| 739 |
-
|
| 740 |
-
# (A lógica de divisão de latentes e concatenação com fade que você já tem vai aqui)
|
| 741 |
-
latents_parts = self._dividir_latentes_por_tamanho(latents_cpu, 4, 1) # Exemplo de divisão
|
| 742 |
partes_mp4 = []
|
| 743 |
-
|
| 744 |
-
|
| 745 |
-
|
| 746 |
-
|
| 747 |
-
|
| 748 |
-
|
| 749 |
-
|
| 750 |
-
|
| 751 |
-
|
| 752 |
-
|
| 753 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 754 |
else:
|
| 755 |
-
|
|
|
|
| 756 |
|
| 757 |
self._log_gpu_memory("Fim da Geração")
|
| 758 |
-
return
|
| 759 |
|
|
|
|
| 760 |
except Exception as e:
|
| 761 |
print("[DEBUG] EXCEÇÃO NA GERAÇÃO:")
|
| 762 |
print("".join(traceback.format_exception(type(e), e, e.__traceback__)))
|
|
@@ -788,4 +834,4 @@ class VideoService:
|
|
| 788 |
print(f"[DEBUG] finalize() no finally falhou: {e}")
|
| 789 |
|
| 790 |
print("Criando instância do VideoService. O carregamento do modelo começará agora...")
|
| 791 |
-
video_generation_service = VideoService(
|
|
|
|
| 639 |
|
| 640 |
conditioning_items = []
|
| 641 |
if mode == "image-to-video":
|
| 642 |
+
start_tensor = self._prepare_conditioning_tensor(start_image_filepath, height, width, padding_values)
|
| 643 |
+
conditioning_items.append(ConditioningItem(start_tensor, 0, 1.0))
|
| 644 |
+
if middle_image_filepath and middle_frame_number is not None:
|
| 645 |
+
middle_tensor = self._prepare_conditioning_tensor(middle_image_filepath, height, width, padding_values)
|
| 646 |
+
safe_middle_frame = max(0, min(int(middle_frame_number), actual_num_frames - 1))
|
| 647 |
+
conditioning_items.append(ConditioningItem(middle_tensor, safe_middle_frame, float(middle_image_weight)))
|
| 648 |
+
if end_image_filepath:
|
| 649 |
+
end_tensor = self._prepare_conditioning_tensor(end_image_filepath, height, width, padding_values)
|
| 650 |
+
last_frame_index = actual_num_frames - 1
|
| 651 |
+
conditioning_items.append(ConditioningItem(end_tensor, last_frame_index, float(end_image_weight)))
|
| 652 |
+
print(f"[DEBUG] Conditioning items: {len(conditioning_items)}")
|
| 653 |
|
| 654 |
call_kwargs = {
|
| 655 |
"prompt": prompt, "negative_prompt": negative_prompt,
|
|
|
|
| 742 |
print("\n--- INICIANDO ETAPA FINAL: DECODIFICAÇÃO E MONTAGEM ---")
|
| 743 |
|
| 744 |
latents_cpu = latents.detach().to("cpu", non_blocking=True)
|
| 745 |
+
torch.cuda.empty_cache()
|
| 746 |
+
try:
|
| 747 |
+
torch.cuda.ipc_collect()
|
| 748 |
+
except Exception:
|
| 749 |
+
pass
|
| 750 |
+
|
| 751 |
+
latents_parts = self._dividir_latentes_por_tamanho(latents_cpu,4,1)
|
| 752 |
+
|
| 753 |
temp_dir = tempfile.mkdtemp(prefix="ltxv_"); self._register_tmp_dir(temp_dir)
|
| 754 |
results_dir = "/app/output"; os.makedirs(results_dir, exist_ok=True)
|
| 755 |
+
|
|
|
|
|
|
|
| 756 |
partes_mp4 = []
|
| 757 |
+
par = 0
|
| 758 |
+
|
| 759 |
+
for latents in latents_parts:
|
| 760 |
+
print(f"[DEBUG] Partição {par}: {tuple(latents.shape)}")
|
| 761 |
+
|
| 762 |
+
par = par + 1
|
| 763 |
+
output_video_path = os.path.join(temp_dir, f"output_{used_seed}_{par}.mp4")
|
| 764 |
+
final_output_path = None
|
| 765 |
+
|
| 766 |
+
print("[DEBUG] Decodificando bloco de latentes com VAE → tensor de pixels...")
|
| 767 |
+
# Usar manager com timestep por item; previne target_shape e rota NoneType.decode
|
| 768 |
+
pixel_tensor = vae_manager_singleton.decode(
|
| 769 |
+
latents.to(self.device, non_blocking=True),
|
| 770 |
+
decode_timestep=float(self.config.get("decode_timestep", 0.05))
|
| 771 |
+
)
|
| 772 |
+
log_tensor_info(pixel_tensor, "Pixel tensor (VAE saída)")
|
| 773 |
+
|
| 774 |
+
print("[DEBUG] Codificando MP4 a partir do tensor de pixels (bloco inteiro)...")
|
| 775 |
+
video_encode_tool_singleton.save_video_from_tensor(
|
| 776 |
+
pixel_tensor,
|
| 777 |
+
output_video_path,
|
| 778 |
+
fps=call_kwargs["frame_rate"],
|
| 779 |
+
progress_callback=progress_callback
|
| 780 |
+
)
|
| 781 |
+
|
| 782 |
+
candidate = os.path.join(results_dir, f"output_par_{par}.mp4")
|
| 783 |
+
try:
|
| 784 |
+
shutil.move(output_video_path, candidate)
|
| 785 |
+
final_output_path = candidate
|
| 786 |
+
print(f"[DEBUG] MP4 parte {par} movido para {final_output_path}")
|
| 787 |
+
partes_mp4.append(final_output_path)
|
| 788 |
+
|
| 789 |
+
except Exception as e:
|
| 790 |
+
final_output_path = output_video_path
|
| 791 |
+
print(f"[DEBUG] Falha no move; usando tmp como final: {e}")
|
| 792 |
+
|
| 793 |
+
total_partes = len(partes_mp4)
|
| 794 |
+
if (total_partes>1):
|
| 795 |
+
final_vid = os.path.join(results_dir, f"concat_fim_{used_seed}.mp4")
|
| 796 |
+
partes_mp4_fade = self._gerar_lista_com_transicoes(pasta=results_dir, video_paths=partes_mp4, crossfade_frames=8)
|
| 797 |
+
self._concat_mp4s_no_reencode(partes_mp4_fade, final_vid)
|
| 798 |
else:
|
| 799 |
+
final_vid = partes_mp4[0]
|
| 800 |
+
|
| 801 |
|
| 802 |
self._log_gpu_memory("Fim da Geração")
|
| 803 |
+
return final_vid, used_seed
|
| 804 |
|
| 805 |
+
|
| 806 |
except Exception as e:
|
| 807 |
print("[DEBUG] EXCEÇÃO NA GERAÇÃO:")
|
| 808 |
print("".join(traceback.format_exception(type(e), e, e.__traceback__)))
|
|
|
|
| 834 |
print(f"[DEBUG] finalize() no finally falhou: {e}")
|
| 835 |
|
| 836 |
print("Criando instância do VideoService. O carregamento do modelo começará agora...")
|
| 837 |
+
video_generation_service = VideoService()
|