From 64172b5c64bae08316eb38e3925008c0cefe8a84 Mon Sep 17 00:00:00 2001 From: Meisoftcoltd <38667978+Meisoftcoltd@users.noreply.github.com> Date: Mon, 30 Mar 2026 18:16:48 +0000 Subject: [PATCH] feat: add dedicated ResTool suite for safe resolutions This commit introduces a new `tools.py` module containing a `BaseResolutionTool` and its specific derived classes (`ResTool8x`, `ResTool16x`, `ResTool32x`, `ResTool64x`). These nodes calculate safe, model-specific dimensions that strictly conform to divisibility rules using provided aspect ratios and base resolutions. The `__init__.py` file is updated to import and register these tools along with emojis for UI display. Both the English and Spanish READMEs are updated to document the new `Tools` suite. --- README.md | 3 +++ README_EN.md | 3 +++ __init__.py | 8 ++++++- tools.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 tools.py diff --git a/README.md b/README.md index 922054f..dfbd3db 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,9 @@ El sistema se construye alrededor de tres categorías principales: 4. **📤 Session Image Sender (`SessionImageSender`)**: Extrae la última imagen del lote y la asegura en la memoria del sistema para el siguiente ciclo. - **💾 Guardado de Keyframes (¡Nuevo en v1.1.0!):** Ahora recibe el índice actual y realiza un volcado de seguridad en el disco duro, guardando progresivamente `keyframe_XXX.png` en cada ciclo para prevenir pérdidas de datos. +### 🛠️ Herramientas (Tools) +Una suite de nodos dedicados (ResTool 8x, 16x, 32x, 64x) para calcular resoluciones seguras al instante. Selecciona tu formato (ej. 9:16) y tu resolución base (ej. 1080). El nodo correspondiente aplicará una restricción matemática estricta hacia abajo para garantizar que el ancho y el alto sean perfectamente divisibles por la arquitectura de tu modelo, protegiendo tu VRAM de errores de tensores. + ### 🎞️ Video (Ensamblaje y Validación) 5. **🕵️ Video Analyzer + Audio (`VideoAnalyzerWithAudio`)**: Es el "Explorador" de la máquina. Escanea el vídeo usando OpenCV para detectar frames con rostros nítidos, extrae la pista de audio íntegra de forma pura mediante Torchaudio, y genera un visual **Preview del Frame de Referencia** en su propia interfaz. Emite dicho frame de referencia en formato de imagen (IMAGE) para el resto del flujo de trabajo. 6. **📊 Auto Loop Calculator (`AutoLoopCalculator`)**: Es el "Cerebro". Recibe la información del Explorador y calcula los cortes de los frames (chunk, skip) de forma asimétrica. Si se le pasa la lista de `safe_faces_list`, forzará los cortes en fotogramas donde haya rostros reconocibles para no romper la fluidez. Ahora incluye un **Margen Dinámico del ±10%** que absorbe los remanentes de vídeo en el último límite, garantizando que todos los ciclos mantengan una duración estable sin generar colas ineficientes. diff --git a/README_EN.md b/README_EN.md index 2d457a3..a3084b1 100644 --- a/README_EN.md +++ b/README_EN.md @@ -27,6 +27,9 @@ The system is built around three major categories: 4. **📤 Session Image Sender (`SessionImageSender`)**: Extracts the final image of a batch and secures it in system memory for the next cycle. - **💾 Keyframe Dumping (New in v1.1.0!):** Now receives the current index and performs a safety dump to the hard drive, progressively saving `keyframe_XXX.png` every cycle to prevent data loss. +### 🛠️ Tools +A suite of dedicated nodes (ResTool 8x, 16x, 32x, 64x) to calculate safe resolutions instantly. Select your aspect ratio (e.g., 9:16) and base resolution (e.g., 1080). The specific node will apply a strict downward mathematical constraint to guarantee that the width and height are perfectly divisible by your model's architecture, shielding your VRAM from tensor errors. + ### 🎞️ Video (Assembly and Validation) 5. **🕵️ Video Analyzer + Audio (`VideoAnalyzerWithAudio`)**: The "Explorer" of the machine. Scans the video using OpenCV to detect frames with sharp faces, extracts the pure, intact audio track using Torchaudio, and generates a **Reference Frame Visual Preview** on its own interface. It outputs this reference frame as an IMAGE format for the rest of the workflow. 6. **📊 Auto Loop Calculator (`AutoLoopCalculator`)**: The "Brain". Receives information from the Explorer and calculates frame cuts (chunk, skip) asymmetrically. If provided with a `safe_faces_list`, it forces cuts on frames with recognizable faces to maintain fluid continuity. Now includes a **Dynamic ±10% Margin** to absorb video remainders at the final boundary, ensuring all cycles maintain a stable duration without generating inefficient tail ends. diff --git a/__init__.py b/__init__.py index 749f4d4..3000e11 100644 --- a/__init__.py +++ b/__init__.py @@ -10,10 +10,16 @@ def register_node(c, display_name=None): NODE_DISPLAY_NAME_MAPPINGS[c.__name__] = display_name or c.__name__ return c -from . import image, loop, video +from . import image, loop, video, tools # Display name mappings with emojis NODE_DISPLAY_NAME_MAPPINGS.update({ + # Tools + "ResTool8x": "📐 ResTool 8x (SD1.5)", + "ResTool16x": "📏 ResTool 16x (SDXL)", + "ResTool32x": "🎞️ ResTool 32x (WanVideo)", + "ResTool64x": "🎬 ResTool 64x (Hunyuan)", + # Image (Memoria de Sesión) "SessionImageReceiver": "📥 Session Image Receiver", "SessionImageSender": "📤 Session Image Sender", diff --git a/tools.py b/tools.py new file mode 100644 index 0000000..6cd8af1 --- /dev/null +++ b/tools.py @@ -0,0 +1,66 @@ +from . import register_node + +# 🧠 Clase Base Invisible (El molde matemático) +class BaseResolutionTool: + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "aspect_ratio": (["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "3:2", "2:3"],), + "base_resolution": (["256", "360", "480", "512", "720", "768", "1024", "1080", "1280", "1440", "1920", "2048", "2160"], {"default": "1024"}), + } + } + + RETURN_TYPES = ("INT", "INT", "STRING") + RETURN_NAMES = ("width", "height", "debug_info") + FUNCTION = "get_resolution" + CATEGORY = "🔁 Sequential Batcher/Tools" + + def get_resolution(self, aspect_ratio, base_resolution): + div = self.DIVISOR + longest_side = int(base_resolution) + + w_str, h_str = aspect_ratio.split(':') + w_ratio = float(w_str) + h_ratio = float(h_str) + + # Matemática segura hacia abajo (Strictly Down) simulando tabla memorizada + actual_longest = max(div, (longest_side // div) * div) + + if w_ratio >= h_ratio: + ideal_w = actual_longest + ideal_h = ideal_w * (h_ratio / w_ratio) + width = ideal_w + height = max(div, (int(ideal_h) // div) * div) + else: + ideal_h = actual_longest + ideal_w = ideal_h * (w_ratio / h_ratio) + height = ideal_h + width = max(div, (int(ideal_w) // div) * div) + + debug_msg = f"{width}x{height} (Div {div})" + + print(f"\n{'='*50}") + print(f"🛠️ [DEBUG] NODO: Resolution Tool {div}x") + print(f" -> Petición: {base_resolution}p | Ratio {aspect_ratio}") + print(f" -> 🎯 Resultado Seguro: Ancho {width} | Alto {height}") + print(f"{'='*50}\n") + + return (width, height, debug_msg) + +# 📦 Los 4 Nodos Visibles para el Usuario +@register_node +class ResTool8x(BaseResolutionTool): + DIVISOR = 8 + +@register_node +class ResTool16x(BaseResolutionTool): + DIVISOR = 16 + +@register_node +class ResTool32x(BaseResolutionTool): + DIVISOR = 32 + +@register_node +class ResTool64x(BaseResolutionTool): + DIVISOR = 64