From 3c3ebca5b2e869422348b512c2b9d22f84e60686 Mon Sep 17 00:00:00 2001 From: Meisoftcoltd <38667978+Meisoftcoltd@users.noreply.github.com> Date: Tue, 30 Jun 2026 21:14:53 +0000 Subject: [PATCH] Refactor loop flow control to center on global_loop_index Centralizes flow control using global_loop_index as the single source of truth. Removes legacy batch reset logic from loaders and passive nodes. Strips VRAM memory clearing hacks from Trigger node, delegating entirely to dedicated defragmenter. Updates DynamicSceneDirector and AudioBatchSelector to passive observer logic. --- loop.py | 94 +++++++-------------------------------------------------- 1 file changed, 11 insertions(+), 83 deletions(-) diff --git a/loop.py b/loop.py index 4547dc0..0952c0f 100644 --- a/loop.py +++ b/loop.py @@ -87,21 +87,15 @@ class SequentialLoopStart: is_reset = str(reset_loop).lower() in ['true', '1', 't', 'y'] - # 💡 FIX: Detectar si es un arranque manual del usuario para resetear el lote - if loop_idx == 0 and not is_reset: - global_is_batch_advancing = False - global_batch_index = 0 - print(" -> 🆕 Arranque manual detectado. Lote (Batch) reiniciado a 0.") - if is_reset or loop_idx == 0: global_loop_index = 0 global_accumulated_frames = 0 global_ltx_mode = False + global_is_batch_advancing = False + global_batch_index = 0 print(" -> 🔄 Bucle y Acumulador reiniciados a 0.") - # HACK: Mantenemos global_is_batch_advancing = True durante el ciclo 0 else: global_loop_index = loop_idx - # Lo apagamos a partir del ciclo 1 global_is_batch_advancing = False print(f" -> 📍 Índice actual de bucle: {global_loop_index}") @@ -151,25 +145,11 @@ class AutoLoopCalculatorTTSBatch: mode = split_mode[0] if isinstance(split_mode, list) else split_mode idx = current_loop_index[0] if isinstance(current_loop_index, list) else current_loop_index - # 💡 FIX: Detección inteligente de nuevos flujos mediante Hash - current_hash = hash(str(texts)) - last_hash = getattr(loop, 'global_last_text_hash', None) + # El batch index es extraído directamente de idx para evitar bloqueos + current_batch_idx = idx - if idx == 0: - if current_hash != last_hash: - _log(" -> 🆕 Nuevo texto detectado. Forzando reinicio del lote (Batch) a 0.") - loop.global_batch_index = 0 - loop.global_is_batch_advancing = False - loop.global_last_text_hash = current_hash - elif not getattr(loop, 'global_is_batch_advancing', False): - loop.global_batch_index = 0 - - current_batch_idx = getattr(loop, 'global_batch_index', 0) - - # Seguridad adicional por si el índice se desborda por cachés antiguos if current_batch_idx >= len(texts): current_batch_idx = len(texts) - 1 - loop.global_batch_index = current_batch_idx current_file_text = texts[current_batch_idx] current_name = names[current_batch_idx] if current_batch_idx < len(names) else "unknown" @@ -443,10 +423,8 @@ class SequentialLoopTrigger: inputs["is_final_cycle"] = is_next_final if is_final_chunk and has_more_batches: - loop.global_batch_index = getattr(loop, 'global_batch_index', 0) + 1 - loop.global_is_batch_advancing = True - print(f" -> 📦 Archivo finalizado. Iniciando archivo {loop.global_batch_index + 1} del lote...") - + print(f" -> 📦 Archivo finalizado. Iniciando siguiente archivo del lote...") + else: print(f" -> ⚙️ Preparando Ciclo {next_loop}...") p = {"prompt": prompt} @@ -459,31 +437,8 @@ class SequentialLoopTrigger: except Exception as e: print(f" -> ❌ Error HTTP: {e}") - import gc, torch - gc.collect() - if torch.cuda.is_available(): torch.cuda.empty_cache() - else: print(f" -> 🏁 ¡Generación Finalizada! Todos los archivos del lote completados.") - print(f" -> 🧹 Iniciando vaciado automático de VRAM...") - import gc - import torch - import comfy.model_management as mm - try: - mm.unload_all_models() - mm.soft_empty_cache() - except Exception as e: - pass - gc.collect() - if torch.cuda.is_available(): - torch.cuda.empty_cache() - torch.cuda.ipc_collect() - import ctypes - try: ctypes.CDLL('libc.so.6').malloc_trim(0) - except Exception: pass - elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available(): - torch.mps.empty_cache() - print(f" -> ✨ VRAM liberada con éxito. Gráfica lista para nuevos flujos.") print(f"{'='*50}\n") return () @@ -586,37 +541,23 @@ class AudioBatchSelector: idx = current_loop_index[0] if isinstance(current_loop_index, list) else current_loop_index - current_hash = hash(str(names)) - last_hash = getattr(loop, 'global_last_audio_hash', None) - - if idx == 0: - if current_hash != last_hash: - _log(" -> 🆕 Nuevo lote de audios detectado. Reiniciando Batch a 0.") - loop.global_batch_index = 0 - loop.global_is_batch_advancing = False - loop.global_last_audio_hash = current_hash - elif not getattr(loop, 'global_is_batch_advancing', False): - loop.global_batch_index = 0 - - current_batch_idx = getattr(loop, 'global_batch_index', 0) + # Extraer el índice del lote basado en el input (el motor Trigger/Start maneja los índices) + # Como este nodo es ahora sólo de lectura, current_loop_index determinará el archivo a cargar. + current_batch_idx = idx if current_batch_idx >= len(audios): current_batch_idx = len(audios) - 1 - loop.global_batch_index = current_batch_idx current_audio = audios[current_batch_idx] current_name = names[current_batch_idx] total_audios = len(audios) - # Control de comunicación con el Trigger final loop.global_has_more_batches = (current_batch_idx < total_audios - 1) _log(f"\n{'='*50}") _log(f"🎛️ [Secuencial Batcher] NODO: Audio Batch Selector") _log(f" -> Lote (Batch) Actual: {current_batch_idx + 1} de {total_audios}") - _log(f" -> Ciclo interno del video: {idx}") _log(f" -> Archivo activo: {current_name}") - _log(f" -> Quedan archivos en el lote: {'Sí' if loop.global_has_more_batches else 'No'}") _log(f"{'='*50}\n") return (current_audio, current_name, current_batch_idx, total_audios, "\n".join(log_output)) @@ -683,24 +624,11 @@ class DynamicSceneDirector: if total_scenes == 0: raise ValueError("❌ JSON sin escenas.") # 2. ⏱️ MÁQUINA DE ESTADOS (1 Ciclo = 1 Escena) - if idx == 0: - loop.global_current_scene_index = 0 - _log(" -> 🆕 Inicio de Proyecto. Estado reseteado.") - else: - loop.global_current_scene_index = getattr(loop, 'global_current_scene_index', 0) + 1 - - scene_idx = loop.global_current_scene_index + # El director es un observador pasivo, scene_idx se deriva directamente de idx + scene_idx = idx if scene_idx >= total_scenes: scene_idx = total_scenes - 1 - loop.global_is_absolute_video_final = True - else: - loop.global_is_absolute_video_final = False - - # 3. 🧠 ENGAÑO AL STITCHER Y AL TRIGGER - # Obligamos a que el sistema avance escena por escena - loop.global_source_frame_count = total_scenes - loop.global_accumulated_frames = scene_idx scene = scenes[scene_idx]