euiiiia commited on
Commit
a01cea0
·
verified ·
1 Parent(s): 9204c48

Update api/ltx_server_refactored.py

Browse files
Files changed (1) hide show
  1. api/ltx_server_refactored.py +43 -335
api/ltx_server_refactored.py CHANGED
@@ -1,8 +1,17 @@
1
  # ltx_server_refactored.py — VideoService (Modular Version with Simple Overlap Chunking)
2
- # Em api/ltx_server_refactored.py
3
 
 
4
  import warnings
 
 
 
5
  from huggingface_hub import logging
 
 
 
 
 
 
6
  import os, subprocess, shlex, tempfile
7
  import torch
8
  import json
@@ -24,23 +33,12 @@ import shutil
24
  import contextlib
25
  import time
26
  import traceback
27
- from api.gpu_manager import gpu_manager
28
  from einops import rearrange
29
  import torch.nn.functional as F
30
  from managers.vae_manager import vae_manager_singleton
31
  from tools.video_encode_tool import video_encode_tool_singleton
32
-
33
  DEPS_DIR = Path("/data")
34
  LTX_VIDEO_REPO_DIR = DEPS_DIR / "LTX-Video"
35
- logging.set_verbosity_error()
36
- logging.set_verbosity_warning()
37
- logging.set_verbosity_info()
38
- logging.set_verbosity_debug()
39
- LTXV_DEBUG=1
40
- LTXV_FRAME_LOG_EVERY=8
41
- warnings.filterwarnings("ignore", category=UserWarning)
42
- warnings.filterwarnings("ignore", category=FutureWarning)
43
- warnings.filterwarnings("ignore", message=".*")
44
 
45
  # (Todas as funções de setup, helpers e inicialização da classe permanecem inalteradas)
46
  # ... (run_setup, add_deps_to_path, _query_gpu_processes_via_nvml, etc.)
@@ -100,6 +98,24 @@ from api.ltx.inference import (
100
  )
101
 
102
  class VideoService:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  def _load_config(self):
104
  base = LTX_VIDEO_REPO_DIR / "configs"
105
  config_path = base / "ltxv-13b-0.9.8-distilled-fp8.yaml"
@@ -119,6 +135,10 @@ class VideoService:
119
  pass
120
  except Exception as e:
121
  print(f"[DEBUG] Finalize: limpeza GPU falhou: {e}")
 
 
 
 
122
 
123
  def _load_models(self):
124
  t0 = time.perf_counter()
@@ -200,11 +220,11 @@ class VideoService:
200
 
201
 
202
  def _save_and_log_video(self, pixel_tensor, base_filename, fps, temp_dir, results_dir, used_seed, progress_callback=None):
203
- output_path = os.path.join(temp_dir, f"{base_filename}_.mp4")
204
  video_encode_tool_singleton.save_video_from_tensor(
205
  pixel_tensor, output_path, fps=fps, progress_callback=progress_callback
206
  )
207
- final_path = os.path.join(results_dir, f"{base_filename}_.mp4")
208
  shutil.move(output_path, final_path)
209
  print(f"[DEBUG] Vídeo salvo em: {final_path}")
210
  return final_path
@@ -243,8 +263,7 @@ class VideoService:
243
  first_pass_kwargs = {
244
  "prompt": prompt, "negative_prompt": negative_prompt, "height": downscaled_height, "width": downscaled_width,
245
  "num_frames": actual_num_frames, "frame_rate": int(FPS), "generator": torch.Generator(device=self.device).manual_seed(used_seed),
246
- "output_type": "latent", "conditioning_items": conditioning_items,
247
- #"guidance_scale": float(guidance_scale),
248
  **(self.config.get("first_pass", {}))
249
  }
250
  try:
@@ -258,283 +277,13 @@ class VideoService:
258
  return video_path, tensor_path, used_seed
259
 
260
  except Exception as e:
261
- print(f"[DEBUG] falhou: {e}")
262
- finally:
263
- torch.cuda.empty_cache()
264
- torch.cuda.ipc_collect()
265
- self.finalize(keep_paths=[])
266
-
267
- # ==============================================================================
268
- # --- FUNÇÃO #1: GERADOR DE CHUNK ÚNICO (AUXILIAR INTERNA) ---
269
- # ==============================================================================
270
- def _generate_single_chunk_low(
271
- self, prompt, negative_prompt,
272
- height, width, num_frames, guidance_scale,
273
- seed, initial_latent_condition=None, image_conditions=None,
274
- ltx_configs_override=None):
275
- """
276
- [NÓ DE GERAÇÃO]
277
- Gera um ÚNICO chunk de latentes brutos. Esta é a unidade de trabalho fundamental.
278
- """
279
- print("\n" + "-"*20 + " INÍCIO: _generate_single_chunk_low " + "-"*20)
280
-
281
- used_seed = random.randint(0, 2**32 - 1) if seed is None else int(seed)
282
- seed_everething(used_seed)
283
-
284
- # --- NÓ 1.1: SETUP DE PARÂMETROS ---
285
- height_padded = ((height - 1) // 8 + 1) * 8
286
- width_padded = ((width - 1) // 8 + 1) * 8
287
- generator = torch.Generator(device=self.device).manual_seed(seed)
288
-
289
- downscale_factor = self.config.get("downscale_factor", 0.6666666)
290
- vae_scale_factor = self.pipeline.vae_scale_factor
291
-
292
- x_width = int(width_padded * downscale_factor)
293
- downscaled_width = x_width - (x_width % vae_scale_factor)
294
- x_height = int(height_padded * downscale_factor)
295
- downscaled_height = x_height - (x_height % vae_scale_factor)
296
-
297
- # --- NÓ 1.2: MONTAGEM DE CONDIÇÕES E OVERRIDES ---
298
- all_conditions = []
299
- if image_conditions: all_conditions.extend(image_conditions)
300
- if initial_latent_condition: all_conditions.append(initial_latent_condition)
301
-
302
- first_pass_config = self.config.get("first_pass", {}).copy()
303
-
304
- if ltx_configs_override:
305
- print("[DEBUG] Sobrepondo configurações do LTX com valores da UI...")
306
- preset = ltx_configs_override.get("guidance_preset")
307
- if preset == "Customizado":
308
- try:
309
- first_pass_config["guidance_scale"] = json.loads(ltx_configs_override["guidance_scale_list"])
310
- first_pass_config["stg_scale"] = json.loads(ltx_configs_override["stg_scale_list"])
311
- #first_pass_config["guidance_timesteps"] = json.loads(ltx_configs_override["timesteps_list"])
312
- except Exception as e:
313
- print(f" > ERRO ao parsear valores customizados: {e}. Usando Padrão como fallback.")
314
- elif preset == "Agressivo":
315
- first_pass_config["guidance_scale"] = [1, 2, 8, 12, 8, 2, 1]
316
- first_pass_config["stg_scale"] = [0, 0, 5, 6, 5, 3, 2]
317
- elif preset == "Suave":
318
- first_pass_config["guidance_scale"] = [1, 1, 4, 5, 4, 1, 1]
319
- first_pass_config["stg_scale"] = [0, 0, 2, 2, 2, 1, 0]
320
-
321
- first_pass_kwargs = {
322
- "prompt": prompt, "negative_prompt": negative_prompt, "height": downscaled_height, "width": downscaled_width,
323
- "num_frames": num_frames, "frame_rate": 24, "generator": generator, "output_type": "latent",
324
- "conditioning_items": all_conditions if all_conditions else None,
325
- **first_pass_config
326
- }
327
-
328
- results_dir = "/app/output"; os.makedirs(results_dir, exist_ok=True)
329
-
330
-
331
- # --- NÓ 1.3: CHAMADA AO PIPELINE ---
332
- try:
333
- with torch.autocast(device_type="cuda", dtype=self.runtime_autocast_dtype, enabled=self.device.type == 'cuda'):
334
- latents_bruto = self.pipeline(**first_pass_kwargs).images
335
- latents_cpu_bruto = latents_bruto.detach().to("cpu")
336
- tensor_path_cpu = os.path.join(results_dir, f"latents_low_res.pt")
337
- torch.save(latents_cpu_bruto, tensor_path_cpu)
338
- log_tensor_info(latents_bruto, f"Latente Bruto Gerado para: '{prompt[:40]}...'")
339
-
340
- print("-" * 20 + " FIM: _generate_single_chunk_low " + "-"*20)
341
- return tensor_path_cpu
342
- except Exception as e:
343
- print("-" * 20 + f" ERRO: _generate_single_chunk_low {e} " + "-"*20)
344
- finally:
345
- torch.cuda.empty_cache()
346
- torch.cuda.ipc_collect()
347
- self.finalize(keep_paths=[])
348
-
349
- # ==============================================================================
350
- # --- FUNÇÃO #2: ORQUESTRADOR NARRATIVO (MÚLTIPLOS PROMPTS) ---
351
- # ==============================================================================
352
- def generate_narrative_low(
353
- self, prompt: str, negative_prompt,
354
- height, width, duration, guidance_scale,
355
- seed, initial_image_conditions=None, overlap_frames: int = 8,
356
- ltx_configs_override: dict = None):
357
- """
358
- [ORQUESTRADOR NARRATIVO]
359
- Gera um vídeo em múltiplos chunks sequenciais a partir de um prompt com várias linhas.
360
- """
361
- print("\n" + "="*80)
362
- print("====== INICIANDO GERAÇÃO NARRATIVA EM CHUNKS (LOW-RES) ======")
363
- print("="*80)
364
-
365
-
366
- used_seed = random.randint(0, 2**32 - 1) if seed is None else int(seed)
367
- seed_everething(used_seed)
368
- FPS = 24.0
369
-
370
- prompt_list = [p.strip() for p in prompt.splitlines() if p.strip()]
371
- num_chunks = len(prompt_list)
372
- if num_chunks == 0: raise ValueError("O prompt está vazio ou não contém linhas válidas.")
373
-
374
- total_actual_frames = max(9, int(round((round(duration * FPS) - 1) / 8.0) * 8 + 1))
375
-
376
- if num_chunks > 1:
377
- total_blocks = (total_actual_frames - 1) // 8
378
- blocks_per_chunk = total_blocks // num_chunks
379
- blocks_last_chunk = total_blocks - (blocks_per_chunk * (num_chunks - 1))
380
- frames_per_chunk = blocks_per_chunk * 8 + 1
381
- frames_per_chunk_last = blocks_last_chunk * 8 + 1
382
- else:
383
- frames_per_chunk = total_actual_frames
384
- frames_per_chunk_last = total_actual_frames
385
-
386
- frames_per_chunk = max(9, frames_per_chunk)
387
- frames_per_chunk_last = max(9, frames_per_chunk_last)
388
-
389
- poda_latents_num = overlap_frames // self.pipeline.video_scale_factor if self.pipeline.video_scale_factor > 0 else 0
390
-
391
- latentes_chunk_video = []
392
- lista_patch_latentes_chunk = []
393
- condition_item_latent_overlap = None
394
- temp_dir = tempfile.mkdtemp(prefix="ltxv_narrative_"); self._register_tmp_dir(temp_dir)
395
- results_dir = "/app/output"; os.makedirs(results_dir, exist_ok=True)
396
-
397
- for i, chunk_prompt in enumerate(prompt_list):
398
- print(f"\n--- Gerando Chunk Narrativo {i+1}/{num_chunks}: '{chunk_prompt}' ---")
399
-
400
- current_image_conditions = []
401
- if initial_image_conditions:
402
- cond_item_original = initial_image_conditions[0]
403
- if i == 0:
404
- current_image_conditions.append(cond_item_original)
405
- else:
406
- cond_item_fraco = ConditioningItem(
407
- media_item=cond_item_original.media_item, media_frame_number=0, conditioning_strength=0.1
408
- )
409
- current_image_conditions.append(cond_item_fraco)
410
-
411
-
412
- poda_latents_num = 8
413
-
414
- if i > 0 and poda_latents_num > 0:
415
- frames_per_chunk += poda_latents_num
416
- else:
417
- frames_per_chunk = frames_per_chunk
418
-
419
- if i == num_chunks - 1:
420
- frames_per_chunk = frames_per_chunk_last+poda_latents_num
421
-
422
- frames_per_chunk = ((frames_per_chunk//8)*8)+1
423
-
424
- latent_path = self._generate_single_chunk_low(
425
- prompt=chunk_prompt, negative_prompt=negative_prompt, height=height, width=width,
426
- num_frames=frames_per_chunk, guidance_scale=guidance_scale, seed=used_seed + i,
427
- initial_latent_condition=condition_item_latent_overlap, image_conditions=current_image_conditions,
428
- ltx_configs_override=ltx_configs_override
429
- )
430
-
431
- latentes_bruto = torch.load(latent_path).to("cpu")
432
-
433
- #poda inicio overlap
434
- if i > 0 and poda_latents_num > 0:
435
- latentes_bruto = latentes_bruto[:, :, poda_latents_num:, :, :]
436
-
437
-
438
- # cria estado overlap para proximo
439
- if i < num_chunks - 1 and poda_latents_num > 0:
440
- overlap_latents = latentes_bruto[:, :, -poda_latents_num:, :, :].clone()
441
- overlap_latents = overlap_latents.detach().to(self.device)
442
- condition_item_latent_overlap = ConditioningItem(
443
- media_item=overlap_latents, media_frame_number=0, conditioning_strength=1.0
444
- )
445
-
446
- #adiciona a lista
447
- tensor_path_podado = os.path.join(results_dir, f"latents_poda{i}_res.pt")
448
- torch.save(latentes_bruto, tensor_path_podado)
449
- lista_patch_latentes_chunk.append(tensor_path_podado)
450
-
451
- print("\n--- Finalizando Narrativa: Concatenando chunks ---")
452
-
453
- # Carrega cada tensor do disco
454
- lista_tensores = [torch.load(caminho) for caminho in lista_patch_latentes_chunk]
455
-
456
- # Concatena ao longo da dimensão de frames (dim=2)
457
- final_latents = torch.cat(lista_tensores, dim=2).to(self.device)
458
- log_tensor_info(final_latents, "Tensor de Latentes Final Concatenado")
459
-
460
- try:
461
- with torch.autocast(device_type="cuda", dtype=self.runtime_autocast_dtype, enabled=self.device.type == 'cuda'):
462
- pixel_tensor = vae_manager_singleton.decode(final_latents, decode_timestep=float(self.config.get("decode_timestep", 0.05)))
463
- pixel_tensor_cpu = pixel_tensor.detach().to("cpu")
464
- video_path = self._save_and_log_video(pixel_tensor_cpu, "narrative_video", FPS, temp_dir, results_dir, used_seed)
465
- final_latents_cpu = final_latents.detach().to("cpu")
466
- final_latents_patch = os.path.join(results_dir, f"latents_low_fim.pt")
467
- torch.save(final_latents_cpu, final_latents_patch)
468
- return video_path, final_latents_patch, used_seed
469
-
470
- except Exception as e:
471
- print(f"[DEBUG] falhou: {e}")
472
  finally:
473
  torch.cuda.empty_cache()
474
  torch.cuda.ipc_collect()
475
  self.finalize(keep_paths=[])
476
 
477
- # ==============================================================================
478
- # --- FUNÇÃO #3: ORQUESTRADOR SIMPLES (PROMPT ÚNICO) ---
479
- # ==============================================================================
480
- def generate_single_low(
481
- self, prompt: str, negative_prompt,
482
- height, width, duration, guidance_scale,
483
- seed, initial_image_conditions=None,
484
- ltx_configs_override: dict = None):
485
- """
486
- [ORQUESTRADOR SIMPLES]
487
- Gera um vídeo completo em um único chunk. Ideal para prompts simples e curtos.
488
- """
489
- print("\n" + "="*80)
490
- print("====== INICIANDO GERAÇÃO SIMPLES EM CHUNK ÚNICO (LOW-RES) ======")
491
- print("="*80)
492
-
493
- used_seed = random.randint(0, 2**32 - 1) if seed is None else int(seed)
494
- seed_everething(used_seed)
495
- FPS = 24.0
496
-
497
- total_actual_frames = max(9, int(round((round(duration * FPS) - 1) / 8.0) * 8 + 1))
498
-
499
- temp_dir = tempfile.mkdtemp(prefix="ltxv_single_"); self._register_tmp_dir(temp_dir)
500
- results_dir = "/app/output"; os.makedirs(results_dir, exist_ok=True)
501
-
502
- # Chama a função de geração de chunk único para fazer todo o trabalho
503
- latent_path = self._generate_single_chunk_low(
504
- prompt=prompt, negative_prompt=negative_prompt, height=height, width=width,
505
- num_frames=total_actual_frames, guidance_scale=guidance_scale, seed=used_seed,
506
- image_conditions=initial_image_conditions,
507
- ltx_configs_override=ltx_configs_override
508
- )
509
-
510
- final_latents = torch.load(latent_path).to(self.device)
511
- print("\n--- Finalizando Geração Simples: Salvando e decodificando ---")
512
- log_tensor_info(final_latents, "Tensor de Latentes Final")
513
-
514
- try:
515
- with torch.autocast(device_type="cuda", dtype=self.runtime_autocast_dtype, enabled=self.device.type == 'cuda'):
516
- pixel_tensor = vae_manager_singleton.decode(final_latents.clone(), decode_timestep=float(self.config.get("decode_timestep", 0.05)))
517
- video_path = self._save_and_log_video(pixel_tensor, "single_video", FPS, temp_dir, results_dir, used_seed)
518
- latents_cpu = final_latents.detach().to("cpu")
519
- tensor_path = os.path.join(results_dir, f"latents_single.pt")
520
- torch.save(latents_cpu, tensor_path)
521
- return video_path, tensor_path, used_seed
522
- except Exception as e:
523
- print(f"[DEBUG] falhou: {e}")
524
- finally:
525
- torch.cuda.empty_cache()
526
- torch.cuda.ipc_collect()
527
- self.finalize(keep_paths=[])
528
-
529
-
530
-
531
- # ==============================================================================
532
- # --- FUNÇÃO #4: ORQUESTRADOR (Upscaler + texturas hd) ---
533
- # ==============================================================================
534
- def generate_upscale_denoise(
535
- self, latents_path, prompt, negative_prompt,
536
- guidance_scale, seed,
537
- ):
538
  used_seed = random.randint(0, 2**32 - 1) if seed is None else int(seed)
539
  seed_everething(used_seed)
540
  temp_dir = tempfile.mkdtemp(prefix="ltxv_up_"); self._register_tmp_dir(temp_dir)
@@ -560,8 +309,7 @@ class VideoService:
560
  second_pass_width = chunk.shape[4] * self.pipeline.vae_scale_factor
561
  second_pass_kwargs = {
562
  "prompt": prompt, "negative_prompt": negative_prompt, "height": second_pass_height, "width": second_pass_width,
563
- "num_frames": chunk.shape[2], "latents": chunk,
564
- #"guidance_scale": float(guidance_scale),
565
  "output_type": "latent", "generator": torch.Generator(device=self.device).manual_seed(used_seed),
566
  **(self.config.get("second_pass", {}))
567
  }
@@ -582,6 +330,8 @@ class VideoService:
582
  video_path = self._save_and_log_video(pixel_tensor, "refined_video", 24.0, temp_dir, results_dir, used_seed)
583
  return video_path, tensor_path
584
 
 
 
585
  def encode_mp4(self, latents_path: str, fps: int = 24):
586
  latents = torch.load(latents_path)
587
  seed = random.randint(0, 99999)
@@ -609,51 +359,9 @@ class VideoService:
609
  final_pixel_tensor = torch.cat(pixel_chunks_to_concat, dim=2)
610
  final_video_path = self._save_and_log_video(final_pixel_tensor, f"final_concatenated_{seed}", fps, temp_dir, results_dir, seed)
611
  return final_video_path
612
-
613
- def __init__(self):
614
- t0 = time.perf_counter()
615
- print("[DEBUG] Inicializando VideoService...")
616
-
617
- # 1. Obter o dispositivo alvo a partir do gerenciador
618
- # Não definimos `self.device` ainda, apenas guardamos o alvo.
619
- target_device = gpu_manager.get_ltx_device()
620
- print(f"[DEBUG] LTX foi alocado para o dispositivo: {target_device}")
621
-
622
- # 2. Carregar a configuração e os modelos (na CPU, como a função _load_models faz)
623
- self.config = self._load_config()
624
- self.pipeline, self.latent_upsampler = self._load_models()
625
-
626
- # 3. Mover os modelos para o dispositivo alvo e definir `self.device`
627
- self.move_to_device(target_device) # Usando a função que já criamos!
628
-
629
- # 4. Configurar o resto dos componentes com o dispositivo correto
630
- self._apply_precision_policy()
631
- vae_manager_singleton.attach_pipeline(
632
- self.pipeline,
633
- device=self.device, # Agora `self.device` está correto
634
- autocast_dtype=self.runtime_autocast_dtype
635
- )
636
- self._tmp_dirs = set()
637
- print(f"[DEBUG] VideoService pronto. boot_time={time.perf_counter()-t0:.3f}s")
638
-
639
- # A função move_to_device que criamos antes é essencial aqui
640
- def move_to_device(self, device):
641
- """Move os modelos do pipeline para o dispositivo especificado."""
642
- print(f"[LTX] Movendo modelos para {device}...")
643
- self.device = torch.device(device) # Garante que é um objeto torch.device
644
- self.pipeline.to(self.device)
645
- if self.latent_upsampler:
646
- self.latent_upsampler.to(self.device)
647
- print(f"[LTX] Modelos agora estão em {self.device}.")
648
 
649
- def move_to_cpu(self):
650
- """Move os modelos para a CPU para liberar VRAM."""
651
- self.move_to_device(torch.device("cpu"))
652
- if torch.cuda.is_available():
653
- torch.cuda.empty_cache()
654
 
655
-
656
- # Instanciação limpa, sem usar `self` fora da classe.
657
- print("Criando instância do VideoService...")
658
  video_generation_service = VideoService()
659
- print("Instância do VideoService pronta.")
 
1
  # ltx_server_refactored.py — VideoService (Modular Version with Simple Overlap Chunking)
 
2
 
3
+ # --- 0. WARNINGS E AMBIENTE ---
4
  import warnings
5
+ warnings.filterwarnings("ignore", category=UserWarning)
6
+ warnings.filterwarnings("ignore", category=FutureWarning)
7
+ warnings.filterwarnings("ignore", message=".*")
8
  from huggingface_hub import logging
9
+ logging.set_verbosity_error()
10
+ logging.set_verbosity_warning()
11
+ logging.set_verbosity_info()
12
+ logging.set_verbosity_debug()
13
+ LTXV_DEBUG=1
14
+ LTXV_FRAME_LOG_EVERY=8
15
  import os, subprocess, shlex, tempfile
16
  import torch
17
  import json
 
33
  import contextlib
34
  import time
35
  import traceback
 
36
  from einops import rearrange
37
  import torch.nn.functional as F
38
  from managers.vae_manager import vae_manager_singleton
39
  from tools.video_encode_tool import video_encode_tool_singleton
 
40
  DEPS_DIR = Path("/data")
41
  LTX_VIDEO_REPO_DIR = DEPS_DIR / "LTX-Video"
 
 
 
 
 
 
 
 
 
42
 
43
  # (Todas as funções de setup, helpers e inicialização da classe permanecem inalteradas)
44
  # ... (run_setup, add_deps_to_path, _query_gpu_processes_via_nvml, etc.)
 
98
  )
99
 
100
  class VideoService:
101
+ def __init__(self):
102
+ t0 = time.perf_counter()
103
+ print("[DEBUG] Inicializando VideoService...")
104
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
105
+ self.config = self._load_config()
106
+ self.pipeline, self.latent_upsampler = self._load_models()
107
+ self.pipeline.to(self.device)
108
+ if self.latent_upsampler:
109
+ self.latent_upsampler.to(self.device)
110
+ self._apply_precision_policy()
111
+ vae_manager_singleton.attach_pipeline(
112
+ self.pipeline,
113
+ device=self.device,
114
+ autocast_dtype=self.runtime_autocast_dtype
115
+ )
116
+ self._tmp_dirs = set()
117
+ print(f"[DEBUG] VideoService pronto. boot_time={time.perf_counter()-t0:.3f}s")
118
+
119
  def _load_config(self):
120
  base = LTX_VIDEO_REPO_DIR / "configs"
121
  config_path = base / "ltxv-13b-0.9.8-distilled-fp8.yaml"
 
135
  pass
136
  except Exception as e:
137
  print(f"[DEBUG] Finalize: limpeza GPU falhou: {e}")
138
+ try:
139
+ self._log_gpu_memory("Após finalize")
140
+ except Exception as e:
141
+ print(f"[DEBUG] Log GPU pós-finalize falhou: {e}")
142
 
143
  def _load_models(self):
144
  t0 = time.perf_counter()
 
220
 
221
 
222
  def _save_and_log_video(self, pixel_tensor, base_filename, fps, temp_dir, results_dir, used_seed, progress_callback=None):
223
+ output_path = os.path.join(temp_dir, f"{base_filename}_{used_seed}.mp4")
224
  video_encode_tool_singleton.save_video_from_tensor(
225
  pixel_tensor, output_path, fps=fps, progress_callback=progress_callback
226
  )
227
+ final_path = os.path.join(results_dir, f"{base_filename}_{used_seed}.mp4")
228
  shutil.move(output_path, final_path)
229
  print(f"[DEBUG] Vídeo salvo em: {final_path}")
230
  return final_path
 
263
  first_pass_kwargs = {
264
  "prompt": prompt, "negative_prompt": negative_prompt, "height": downscaled_height, "width": downscaled_width,
265
  "num_frames": actual_num_frames, "frame_rate": int(FPS), "generator": torch.Generator(device=self.device).manual_seed(used_seed),
266
+ "output_type": "latent", "conditioning_items": conditioning_items, "guidance_scale": float(guidance_scale),
 
267
  **(self.config.get("first_pass", {}))
268
  }
269
  try:
 
277
  return video_path, tensor_path, used_seed
278
 
279
  except Exception as e:
280
+ pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  finally:
282
  torch.cuda.empty_cache()
283
  torch.cuda.ipc_collect()
284
  self.finalize(keep_paths=[])
285
 
286
+ def generate_upscale_denoise(self, latents_path, prompt, negative_prompt, guidance_scale, seed):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  used_seed = random.randint(0, 2**32 - 1) if seed is None else int(seed)
288
  seed_everething(used_seed)
289
  temp_dir = tempfile.mkdtemp(prefix="ltxv_up_"); self._register_tmp_dir(temp_dir)
 
309
  second_pass_width = chunk.shape[4] * self.pipeline.vae_scale_factor
310
  second_pass_kwargs = {
311
  "prompt": prompt, "negative_prompt": negative_prompt, "height": second_pass_height, "width": second_pass_width,
312
+ "num_frames": chunk.shape[2], "latents": chunk, "guidance_scale": float(guidance_scale),
 
313
  "output_type": "latent", "generator": torch.Generator(device=self.device).manual_seed(used_seed),
314
  **(self.config.get("second_pass", {}))
315
  }
 
330
  video_path = self._save_and_log_video(pixel_tensor, "refined_video", 24.0, temp_dir, results_dir, used_seed)
331
  return video_path, tensor_path
332
 
333
+
334
+
335
  def encode_mp4(self, latents_path: str, fps: int = 24):
336
  latents = torch.load(latents_path)
337
  seed = random.randint(0, 99999)
 
359
  final_pixel_tensor = torch.cat(pixel_chunks_to_concat, dim=2)
360
  final_video_path = self._save_and_log_video(final_pixel_tensor, f"final_concatenated_{seed}", fps, temp_dir, results_dir, seed)
361
  return final_video_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
 
 
 
 
 
 
363
 
364
+ # --- INSTANCIAÇÃO DO SERVIÇO ---
365
+ print("Criando instância do VideoService. O carregamento do modelo começará agora...")
 
366
  video_generation_service = VideoService()
367
+ print("Instância do VideoService pronta para uso.")