Merge pull request #19 from Meisoftcoltd/fix/simplify-loop-index-reset-9730679421414511812

Simplify flow by using current_loop_index for internal state reset
This commit is contained in:
Meisoft
2026-03-22 18:57:26 +01:00
committed by GitHub
4 changed files with 32 additions and 26 deletions
+3 -3
View File
@@ -74,15 +74,15 @@ Video models produce many frames that can easily exceed 24GB VRAM.
- **🎞️ Latent Batch To List**: Splits video latents frame-by-frame for VRAM-safe processing.
- **🎞️ Latent List To Batch**: Merges individual frames back into a video latent batch.
- **⏳ Progress Bar**: Generates a visual progress indicator.
- **📤 Session Image Sender** & **📥 Session Image Receiver**: A powerful Sender/Receiver pattern designed to pass the *last frame* of an image batch into the *first frame* of the next Auto Queue cycle. This avoids ComfyUI's cyclic dependency errors, allowing for infinite, continuous video generation loops.
- **📤 Session Image Sender** & **📥 Session Image Receiver**: A powerful Sender/Receiver pattern designed to pass the *last frame* of an image batch into the *first frame* of the next Auto Queue cycle. This avoids ComfyUI's cyclic dependency errors, allowing for infinite, continuous video generation loops. The Receiver now accepts the `current_loop_index` and automatically clears its session memory when the loop resets to `0`.
### 🎞️ Video Category (`🔁 Sequential Batcher/Video`)
- **🛡️ Wan Frame Validator**: Ensures video frame counts comply with Wan's strict 4k+1 architecture to prevent skipped or duplicated keyframes.
- **🎞️ FFmpeg Video Stitcher**: Final node in a video loop. Waits for the entire sequential batch to finish and stitches the video chunks together using FFmpeg without re-encoding.
- *Input*: `video_paths` (List of VHS_FILENAMES), `output_filename` (String).
- *Output*: `final_video_path` (Path to the stitched video).
- **🎞️ Incremental Auto-Stitcher**: Incremental stitching node designed specifically for Auto Queue cycles. It runs immediately after each chunk is saved and extracts the `.mp4` absolute paths strictly from the `VHS_FILENAMES` output JSON. It maintains an active session memory (which clears on ComfyUI restart) to stitch *only* the videos generated during the current session, guaranteeing immunity to old/garbage files in the output directory.
- *Input*: `trigger` (VHS_FILENAMES list/JSON), `output_filename` (String), `reset_list` (Boolean: toggle True once to manually flush the session memory and start a fresh video).
- **🎞️ Incremental Auto-Stitcher**: Incremental stitching node designed specifically for Auto Queue cycles. It runs immediately after each chunk is saved and extracts the `.mp4` absolute paths strictly from the `VHS_FILENAMES` output JSON. It maintains an active session memory to stitch *only* the videos generated during the current loop cycle, guaranteeing immunity to old/garbage files in the output directory.
- *Input*: `trigger` (VHS_FILENAMES list/JSON), `output_filename` (String), `current_loop_index` (Integer: connects to the loop index to automatically flush the session memory on the first cycle).
- *Output*: `final_video_path` (Path to the incrementally stitched final video).
---
+3 -3
View File
@@ -74,15 +74,15 @@ Los modelos de vídeo generan muchos fotogramas que pueden superar fácilmente l
- **🎞️ Latent Batch To List**: Divide latentes de vídeo fotograma a fotograma para un procesamiento seguro en VRAM.
- **🎞️ Latent List To Batch**: Une fotogramas individuales de nuevo en un lote latente de vídeo.
- **⏳ Progress Bar**: Genera un indicador visual de progreso.
- **📤 Session Image Sender** y **📥 Session Image Receiver**: Un patrón Emisor/Receptor diseñado para enviar el *último fotograma* de un lote como el *primer fotograma* del siguiente ciclo de Auto Queue. Esto evita los errores de dependencias cíclicas en ComfyUI y permite bucles de generación de vídeo continuos e infinitos.
- **📤 Session Image Sender** y **📥 Session Image Receiver**: Un patrón Emisor/Receptor diseñado para enviar el *último fotograma* de un lote como el *primer fotograma* del siguiente ciclo de Auto Queue. Esto evita los errores de dependencias cíclicas en ComfyUI y permite bucles de generación de vídeo continuos e infinitos. El Receiver ahora acepta el `current_loop_index` y vacía automáticamente su memoria de sesión cuando el bucle vuelve a `0`.
### 🎞️ Categoría Vídeo (`🔁 Sequential Batcher/Video`)
- **🛡️ Wan Frame Validator**: Garantiza que el recuento de fotogramas de vídeo cumpla estrictamente con la arquitectura 4k+1 de Wan, evitando fotogramas clave omitidos o duplicados.
- **🎞️ FFmpeg Video Stitcher**: Nodo final en un bucle de vídeo. Espera a que termine todo el lote secuencial y une los fragmentos de vídeo utilizando FFmpeg sin recodificar.
- *Entrada*: `video_paths` (Lista de VHS_FILENAMES), `output_filename` (Cadena de texto).
- *Salida*: `final_video_path` (Ruta del vídeo ensamblado).
- **🎞️ Incremental Auto-Stitcher**: Nodo de ensamblaje incremental diseñado específicamente para ciclos de Auto Queue. Se ejecuta inmediatamente después de que cada fragmento es guardado y extrae de manera estricta las rutas `.mp4` del JSON de salida que genera `VHS_FILENAMES`. Mantiene una lista en la memoria de la sesión activa (que se vacía automáticamente al reiniciar ComfyUI) para ensamblar *únicamente* los vídeos generados durante la sesión actual, garantizando inmunidad a archivos viejos o "basura" en el directorio de salida.
- *Entrada*: `trigger` (JSON/lista de VHS_FILENAMES), `output_filename` (Cadena de texto), `reset_list` (Booleano: actívalo a True en un ciclo para vaciar manualmente la memoria de la sesión y empezar un vídeo nuevo).
- **🎞️ Incremental Auto-Stitcher**: Nodo de ensamblaje incremental diseñado específicamente para ciclos de Auto Queue. Se ejecuta inmediatamente después de que cada fragmento es guardado y extrae de manera estricta las rutas `.mp4` del JSON de salida que genera `VHS_FILENAMES`. Mantiene una lista en la memoria de la sesión activa para ensamblar *únicamente* los vídeos generados durante el ciclo de bucle actual, garantizando inmunidad a archivos viejos o "basura" en el directorio de salida.
- *Entrada*: `trigger` (JSON/lista de VHS_FILENAMES), `output_filename` (Cadena de texto), `current_loop_index` (Entero: conéctalo al índice del bucle para vaciar automáticamente la memoria de la sesión en el primer ciclo).
- *Salida*: `final_video_path` (Ruta del vídeo ensamblado incremental).
---
+13 -10
View File
@@ -279,19 +279,19 @@ def tensor_to_temp_image(tensor_image, prefix="session_img"):
@register_node
class SessionImageReceiver:
"""Proporciona y MUESTRA la imagen inicial o la última generada del ciclo anterior."""
"""Proporciona la imagen inicial o la última generada, detectando el inicio automáticamente."""
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"initial_image": ("IMAGE",),
"reset_session": ("BOOLEAN", {"default": False}),
"current_loop_index": ("INT", {"default": 0, "min": 0, "max": 10000, "step": 1}),
},
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("current_image",)
OUTPUT_NODE = True # Necesario para que la UI se actualice
OUTPUT_NODE = True
FUNCTION = "get_image"
CATEGORY = "🔁 Sequential Batcher/Image"
@@ -299,19 +299,22 @@ class SessionImageReceiver:
def IS_CHANGED(cls, **kwargs):
return float("NaN")
def get_image(self, initial_image, reset_session):
def get_image(self, initial_image, current_loop_index):
global global_session_image
if reset_session or global_session_image is None:
# Extracción segura por si en el futuro se usa INPUT_IS_LIST
loop_idx = current_loop_index[0] if isinstance(current_loop_index, list) else current_loop_index
# LÓGICA NATIVA: Si es el primer ciclo (index 0), reiniciamos
is_first_cycle = (loop_idx == 0)
if is_first_cycle or global_session_image is None:
global_session_image = initial_image
print("[Sequential Batcher] Receiver: Iniciando sesión con la imagen original.")
print(f"[Sequential Batcher] Receiver: Ciclo {loop_idx}. Iniciando sesión con la imagen original.")
else:
print("[Sequential Batcher] Receiver: Usando el último fotograma del ciclo anterior.")
print(f"[Sequential Batcher] Receiver: Ciclo {loop_idx}. Usando el último fotograma del ciclo anterior.")
# Generar vista previa para la UI
ui_image = tensor_to_temp_image(global_session_image, "receiver")
# Devolver el diccionario con la actualización de la UI y el resultado real
return {"ui": {"images": [ui_image]}, "result": (global_session_image, )}
+13 -10
View File
@@ -140,7 +140,7 @@ class IncrementalVideoStitcher:
# Recibe la lista/JSON de VHS_VideoCombine
"trigger": ("VHS_FILENAMES", ),
"output_filename": ("STRING", {"default": "Pelicula_Final_Sesion.mp4"}),
"reset_list": ("BOOLEAN", {"default": False}),
"current_loop_index": ("INT", {"default": 0, "min": 0, "max": 10000, "step": 1}),
},
}
@@ -151,23 +151,26 @@ class IncrementalVideoStitcher:
FUNCTION = "stitch_incremental"
CATEGORY = "🔁 Sequential Batcher/Video"
def stitch_incremental(self, trigger, output_filename, reset_list):
def stitch_incremental(self, trigger, output_filename, current_loop_index):
global session_video_list
# Extraer variables si llegan en lista por INPUT_IS_LIST=True
do_reset = reset_list[0] if isinstance(reset_list, list) else reset_list
if do_reset:
session_video_list.clear()
print("[Sequential Batcher] Memoria de sesión vaciada (reset_list=True).")
if not shutil.which("ffmpeg"):
print("[Sequential Batcher] Error: FFmpeg no está instalado en el sistema.")
print("[Sequential Batcher] Error de FFmpeg: No está instalado.")
return ("", )
out_dir = folder_paths.get_output_directory()
out_name = output_filename[0] if isinstance(output_filename, list) else output_filename
# Extracción segura obligatoria por INPUT_IS_LIST = True
loop_idx = current_loop_index[0] if isinstance(current_loop_index, list) else current_loop_index
# LÓGICA NATIVA: Si es el primer ciclo, vaciamos la lista
is_first_cycle = (loop_idx == 0)
if is_first_cycle:
print(f"[Sequential Batcher] Auto-Stitcher: Ciclo {loop_idx}. Vaciando memoria de la sesión.")
session_video_list.clear()
# 1. Extracción recursiva: buscar cualquier archivo .mp4 dentro del JSON/lista recibido
current_mp4s = []
def extract_mp4s(data):