Merge pull request #42 from Meisoftcoltd/feat/tools-resolution-nodes-3416685684358741616

feat: add dedicated ResTool suite for safe resolutions
This commit is contained in:
Meisoft
2026-03-30 20:19:41 +02:00
committed by GitHub
4 changed files with 79 additions and 1 deletions
+3
View File
@@ -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.
+3
View File
@@ -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.
+7 -1
View File
@@ -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",
+66
View File
@@ -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