From 608be498418493b3fb27e0a7fd9d9a65a81afd13 Mon Sep 17 00:00:00 2001 From: Meisoftcoltd <38667978+Meisoftcoltd@users.noreply.github.com> Date: Sun, 5 Apr 2026 17:03:15 +0000 Subject: [PATCH] fix: Silence YOLO outputs and improve transparency in calculators --- __pycache__/loop.cpython-312.pyc | Bin 0 -> 11504 bytes __pycache__/video.cpython-312.pyc | Bin 0 -> 19936 bytes loop.py | 18 ++++++-- test_video_calculator.py | 70 +++++++++++++++++++++++++++++ video.py | 71 ++++++++++++++++++++++-------- 5 files changed, 137 insertions(+), 22 deletions(-) create mode 100644 __pycache__/loop.cpython-312.pyc create mode 100644 __pycache__/video.cpython-312.pyc create mode 100644 test_video_calculator.py diff --git a/__pycache__/loop.cpython-312.pyc b/__pycache__/loop.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ae70f83bb6ea215173cf1de96aad62059e93aff8 GIT binary patch literal 11504 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 H$k6^jmmgO4 literal 0 HcmV?d00001 diff --git a/__pycache__/video.cpython-312.pyc b/__pycache__/video.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f69fb318770eb968ac32ffce2ffdbce80b53402b GIT binary patch literal 19936 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 ⚖️ Ajuste Proporcional LTX: Target recalculado a {adjusted_target} frames por ciclo.") + + # --- LOGS MEJORADOS Y TRANSPARENTES --- + print(f" -> 🎞️ Capacidad del video: {potential_effective_frames} frames procesables (Nth: {select_every_nth})") + if effective_loss > 0: + print(f" -> 🛡️ Ajuste VAE: Se usarán {safe_effective_frames} frames (Descarte técnico: {effective_loss} frame/s de proceso)") + else: + print(f" -> ✅ Ajuste VAE: Perfecto. Regla 8n+1 detectada.") + + print(f" -> 📊 Timeline final: 0 a {safe_source_frame_count} (de {source_frame_count} totales)") # ------------------------------------------------------------- loop.global_select_every_nth = select_every_nth diff --git a/test_video_calculator.py b/test_video_calculator.py new file mode 100644 index 0000000..1c3ea47 --- /dev/null +++ b/test_video_calculator.py @@ -0,0 +1,70 @@ +import sys +import types +import os + +# Create dummy modules for comfyui dependencies +comfy_module = types.ModuleType("comfy") +comfy_mm_module = types.ModuleType("comfy.model_management") +comfy_module.model_management = comfy_mm_module +sys.modules["comfy"] = comfy_module +sys.modules["comfy.model_management"] = comfy_mm_module + +folder_paths_module = types.ModuleType("folder_paths") +sys.modules["folder_paths"] = folder_paths_module + +nodes_module = types.ModuleType("nodes") +sys.modules["nodes"] = nodes_module + +# Mock torchaudio and torch +sys.modules["torch"] = types.ModuleType("torch") +sys.modules["torchaudio"] = types.ModuleType("torchaudio") +sys.modules["cv2"] = types.ModuleType("cv2") +sys.modules["numpy"] = types.ModuleType("numpy") +sys.modules["tqdm"] = types.ModuleType("tqdm") +def mock_tqdm(iter_obj, *args, **kwargs): + class DummyPbar: + def update(self, *args, **kwargs): pass + def close(self): pass + if isinstance(iter_obj, int): + return DummyPbar() + return iter_obj +sys.modules["tqdm"].tqdm = mock_tqdm + +# Mock parent package for relative imports +dummy_pkg = types.ModuleType("dummy_pkg") +def mock_register_node(cls): + return cls +dummy_pkg.register_node = mock_register_node +sys.modules["dummy_pkg"] = dummy_pkg + +# Overwrite sys.modules for testing so `from . import register_node` works +# We'll just load the file using importlib +import importlib.util +def load_module(name, path): + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + # make it part of dummy_pkg + module.__package__ = "dummy_pkg" + spec.loader.exec_module(module) + return module + +load_module("dummy_pkg.loop", "loop.py") +video = load_module("dummy_pkg.video", "video.py") +loop_mod = sys.modules["dummy_pkg.loop"] + +# Run tests +calc_base = video.AutoLoopCalculator() +calc_wan = video.AutoLoopCalculatorWan() +calc_ltx = loop_mod.AutoLoopCalculatorLTX() + +print("Testing base calculator...") +calc_base.calculate(source_frame_count=876, target_frames_per_loop=50, select_every_nth=8, current_loop_index=0) + +print("\nTesting WanVideo calculator...") +calc_wan.calculate(source_frame_count=876, target_frames_per_loop=48, select_every_nth=8, current_loop_index=0) + +print("\nTesting LTX calculator...") +calc_ltx.calculate(source_frame_count=876, target_frames_per_loop=81, select_every_nth=8, current_loop_index=0) + +print("\nTests passed!") diff --git a/video.py b/video.py index 71fd1ac..5e96eda 100644 --- a/video.py +++ b/video.py @@ -1,6 +1,7 @@ import os import sys -from contextlib import redirect_stdout +import logging +from contextlib import redirect_stdout, redirect_stderr from tqdm import tqdm import math import torch @@ -141,25 +142,33 @@ class VideoAnalyzerWithAudio: cap.set(cv2.CAP_PROP_POS_FRAMES, 0) # Volver al inicio print(f" -> 🤖 Iniciando escaneo de rostros por GPU...") - for idx in tqdm(range(frame_count), desc="🔍 Escaneando frames", unit="frame"): + + # Silenciamos el logger de ultralytics antes de empezar + logging.getLogger("ultralytics").setLevel(logging.ERROR) + + # Barra de progreso profesional (desc=Descripción, unit=unidad, leave=True para que no desaparezca) + pbar = tqdm(total=frame_count, desc="🔍 Analizando Rostros", unit="frame", dynamic_ncols=True) + + for idx in range(frame_count): ret, frame = cap.read() if not ret: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) variance = cv2.Laplacian(gray, cv2.CV_64F).var() + faces_found = False if variance > blur_threshold: - faces_found = False if bbox_detector is not None: frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) img_tensor = torch.from_numpy(frame_rgb.astype(np.float32) / 255.0).unsqueeze(0).cpu() try: - # 🔇 SILENCIAMOS EL SPAM INTERNO DE ULTRALYTICS/YOLO - with open(os.devnull, 'w') as devnull, redirect_stdout(devnull): - # ⚠️ CORRECCIÓN: detect devuelve la tupla SEGS directamente - segs = bbox_detector.detect(img_tensor, 0.5, 0, 1.0, 10) + # 🤐 CÁPSULA DE VACÍO: Silenciamos TODO el ruido de la consola + with open(os.devnull, 'w') as fnull: + with redirect_stdout(fnull), redirect_stderr(fnull): + # Inferencia + segs = bbox_detector.detect(img_tensor, 0.5, 0, 1.0, 10) if segs is not None: # Formato ImpactPack: (shape, [lista_de_segs]) @@ -169,8 +178,8 @@ class VideoAnalyzerWithAudio: # Otros formatos directos elif isinstance(segs, list) and len(segs) > 0: faces_found = True - except Exception as e: - print(f" -> ⚠️ Error en detector YOLO/ONNX: {e}") + except Exception: + pass # Fallback silencioso si el detector falla elif HAS_OPENCV and use_face_detector: # Fallback silencioso a OpenCV si el usuario no conectó el cable ONNX @@ -180,6 +189,11 @@ class VideoAnalyzerWithAudio: if faces_found: safe_faces.append(idx) + + # Actualizamos la barra una sola vez por frame + pbar.update(1) + + pbar.close() # Cerramos la barra al terminar print(f" -> ✅ Encontrados {len(safe_faces)} frames nítidos con rostros.") else: print(f" -> 🤖 Escaneo de rostros DESACTIVADO.") @@ -217,14 +231,26 @@ class AutoLoopCalculator: import math from . import loop - total_effective_frames = source_frame_count // select_every_nth - safe_source_frame_count = total_effective_frames * select_every_nth - loop.global_source_frame_count = safe_source_frame_count + potential_effective_frames = source_frame_count // select_every_nth + safe_effective_frames = potential_effective_frames # Sin restricciones - estimated_loops = math.ceil(total_effective_frames / target_frames_per_loop) + safe_source_frame_count = safe_effective_frames * select_every_nth + loop.global_source_frame_count = safe_source_frame_count + effective_loss = potential_effective_frames - safe_effective_frames + + estimated_loops = math.ceil(safe_effective_frames / target_frames_per_loop) if estimated_loops > 0: - target_frames_per_loop = math.ceil(total_effective_frames / estimated_loops) + target_frames_per_loop = math.ceil(safe_effective_frames / estimated_loops) print(f" -> ⚖️ Ajuste Proporcional: Target recalculado a {target_frames_per_loop} frames por ciclo.") + + # --- LOGS MEJORADOS Y TRANSPARENTES --- + print(f" -> 🎞️ Capacidad del video: {potential_effective_frames} frames procesables (Nth: {select_every_nth})") + if effective_loss > 0: + print(f" -> 🛡️ Ajuste VAE: Se usarán {safe_effective_frames} frames (Descarte técnico: {effective_loss} frame/s de proceso)") + else: + print(f" -> ✅ Ajuste VAE: Perfecto. Múltiplo de 4 detectado.") # Manteniendo el mismo string por ahora o podemos omitirlo, lo adapto a que es genérico + + print(f" -> 📊 Timeline final: 0 a {safe_source_frame_count} (de {source_frame_count} totales)") # ------------------------------------------------------------- loop.global_select_every_nth = select_every_nth @@ -343,11 +369,13 @@ class AutoLoopCalculatorWan: # --- MEISOFT PATCH: Sincronización Matemática y Ajuste Proporcional --- # 1. Truncado a múltiplo de 4 (Desechamos los 2-3 frames residuales) - total_effective_frames = source_frame_count // select_every_nth - safe_effective_frames = (total_effective_frames // 4) * 4 - safe_source_frame_count = safe_effective_frames * select_every_nth + potential_effective_frames = source_frame_count // select_every_nth + safe_effective_frames = (potential_effective_frames // 4) * 4 + safe_source_frame_count = safe_effective_frames * select_every_nth loop.global_source_frame_count = safe_source_frame_count + effective_loss = potential_effective_frames - safe_effective_frames + loop.global_select_every_nth = select_every_nth # 2. Ajuste Proporcional Real (Evitar micro-ciclos al final) @@ -361,7 +389,14 @@ class AutoLoopCalculatorWan: print(f" -> ⚖️ Ajuste Proporcional: Target recalculado de {target_frames_per_loop} a {adjusted_target} frames por ciclo (para {estimated_loops} ciclos)") target_frames_per_loop = adjusted_target - print(f" -> 📊 Timeline ajustado para VAE: {safe_source_frame_count} / {source_frame_count} (Truncado {source_frame_count - safe_source_frame_count} frames)") + # --- LOGS MEJORADOS Y TRANSPARENTES --- + print(f" -> 🎞️ Capacidad del video: {potential_effective_frames} frames procesables (Nth: {select_every_nth})") + if effective_loss > 0: + print(f" -> 🛡️ Ajuste VAE: Se usarán {safe_effective_frames} frames (Descarte técnico: {effective_loss} frame/s de proceso)") + else: + print(f" -> ✅ Ajuste VAE: Perfecto. Múltiplo de 4 detectado.") + + print(f" -> 📊 Timeline final: 0 a {safe_source_frame_count} (de {source_frame_count} totales)") # ------------------------------------------------------------- current_pos = getattr(loop, 'global_accumulated_frames', 0)