Files
fblissjr-ComfyUI-WanSeamles…/nodes.py
T
2025-03-16 10:12:43 -05:00

192 lines
6.8 KiB
Python

# WanSeamlessFlow/nodes.py
import numpy as np
import torch
import comfy.model_management as mm
from typing import List, Dict, Any, Tuple, Optional
from .blending import blend_embeddings
from .utils.optimization import optimize_embedding_order, compute_transition_cost_matrix
from .visualization import create_transition_visualization
class WanSmartBlend:
"""
Optimize text embeddings for seamless transitions between context windows.
This node takes multiple text embeddings and:
1. Optionally reorders them using nearest-neighbor optimization
2. Adds blend parameters for smooth transitions
"""
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text_embeds": ("WANVIDEOTEXTEMBEDS",),
"blend_width": ("INT", {
"default": 8, "min": 0, "max": 32, "step": 1,
"tooltip": "Width of transition zone in frames (latent space)"
}),
"blend_method": (
["linear", "smooth", "ease_in", "ease_out", "sine", "circ", "bounce"],
{
"default": "smooth",
"tooltip": "Interpolation curve between prompts"
}
),
},
"optional": {
"optimize_order": ("BOOLEAN", {
"default": True,
"tooltip": "Optimize embedding order to minimize semantic distance"
}),
"verbosity": ("INT", {
"default": 1, "min": 0, "max": 3, "step": 1,
"tooltip": "0: None, 1: Basic, 2: Detailed, 3: Debug"
}),
}
}
RETURN_TYPES = ("WANVIDEOTEXTEMBEDS",)
RETURN_NAMES = ("text_embeds",)
FUNCTION = "process"
CATEGORY = "WanSeamlessFlow"
DESCRIPTION = "Prepares text embeddings for smooth transitions between context windows"
def process(self,
text_embeds: Dict[str, Any],
blend_width: int,
blend_method: str,
optimize_order: bool = True,
verbosity: int = 1) -> Tuple[Dict[str, Any]]:
"""
Process text embeddings for optimal transitions.
Args:
text_embeds: Dictionary containing prompt embeddings
blend_width: Width of transition zone in frames
blend_method: Type of interpolation curve
optimize_order: Whether to optimize embedding order
verbosity: Level of debug information
Returns:
Enhanced text embeddings with blend parameters
"""
# Create a deep copy to avoid modifying original
result = {}
for k, v in text_embeds.items():
if isinstance(v, list) and len(v) > 0 and isinstance(v[0], torch.Tensor):
result[k] = [t.clone() for t in v]
elif isinstance(v, torch.Tensor):
result[k] = v.clone()
else:
result[k] = v
# Skip optimization for single embedding
if len(result["prompt_embeds"]) <= 1 or not optimize_order:
if verbosity > 0 and len(result["prompt_embeds"]) <= 1:
print("WanSmartBlend: Only one prompt, skipping optimization")
# Still add blend parameters for interface consistency
result["blend_width"] = blend_width
result["blend_method"] = blend_method
result["verbosity"] = verbosity
return (result,)
# Log the operation
if verbosity > 0:
print(f"WanSmartBlend: Optimizing {len(result['prompt_embeds'])} embeddings with blend width {blend_width}")
# Compute cost matrix for visualization
if verbosity > 1:
cost_matrix = compute_transition_cost_matrix(result["prompt_embeds"])
print("\nTransition costs between prompts:")
for i in range(len(cost_matrix)):
print(f" Prompt {i}: " + " ".join(f"{cost:.2f}" for cost in cost_matrix[i]))
# Optimize embedding order
if optimize_order and len(result["prompt_embeds"]) > 1:
order = optimize_embedding_order(result["prompt_embeds"])
# Apply the optimized ordering
result["prompt_embeds"] = [result["prompt_embeds"][i] for i in order]
# Log the final order
if verbosity > 0:
print(f"WanSmartBlend: Optimized prompt order: {order}")
# Add blend parameters to the result
result["blend_width"] = blend_width
result["blend_method"] = blend_method
result["verbosity"] = verbosity
return (result,)
class WanBlendVisualize:
"""
Diagnostic node to visualize the transition points between prompts.
"""
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text_embeds": ("WANVIDEOTEXTEMBEDS",),
"num_frames": ("INT", {
"default": 81, "min": 1, "max": 1000, "step": 1,
"tooltip": "Total number of frames in the video"
}),
"show_blend_zones": ("BOOLEAN", {
"default": True,
"tooltip": "Highlight the blend zones"
}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("blend_info",)
FUNCTION = "process"
CATEGORY = "WanSeamlessFlow"
DESCRIPTION = "Generates a visualization of prompt transitions"
def process(self,
text_embeds: Dict[str, Any],
num_frames: int,
show_blend_zones: bool) -> Tuple[str]:
"""
Visualize prompt transitions in a textual format.
Args:
text_embeds: Dictionary containing prompt embeddings
num_frames: Total number of frames
show_blend_zones: Whether to highlight blend zones
Returns:
Textual visualization of transitions
"""
blend_width = text_embeds.get("blend_width", 0)
blend_method = text_embeds.get("blend_method", "linear")
num_prompts = len(text_embeds["prompt_embeds"])
# Generate visualization
visualization = create_transition_visualization(
num_frames=num_frames,
num_prompts=num_prompts,
blend_width=blend_width,
blend_method=blend_method,
show_blend_zones=show_blend_zones
)
return (visualization,)
# Node mapping for ComfyUI
NODE_CLASS_MAPPINGS = {
"WanSmartBlend": WanSmartBlend,
"WanBlendVisualize": WanBlendVisualize,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"WanSmartBlend": "Wan Smart Blend",
"WanBlendVisualize": "Wan Blend Visualize",
}