From 2bba6288bfbc9cfd4e512cfb05aadedc5437da38 Mon Sep 17 00:00:00 2001 From: Baverne Date: Wed, 23 Jul 2025 10:25:26 +0200 Subject: [PATCH] WAnVideoVacePipe 1 --- README.md | 171 ++++++++++++++++- __pycache__/nodes.cpython-37.pyc | Bin 19865 -> 28499 bytes nodes.py | 319 ++++++++++++++++++++++++++++++- 3 files changed, 487 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 87b6b47..8756bba 100644 --- a/README.md +++ b/README.md @@ -326,4 +326,173 @@ The TiledWan Video Sampler Simple node can be found in the "TiledWan" category i - Use TeaCache nodes to create cache_args rather than trying to build manually - Same seed + same parameters = identical output to original node - Connect argument objects (cache_args, slg_args, etc.) rather than trying to configure manually -- Monitor console output to verify feature usage and configuration \ No newline at end of file +- Monitor console output to verify feature usage and configuration + +### WanVideo VACE Pipeline +A complete, production-ready WanVideo pipeline that encapsulates multiple WanVideo components into a single, easy-to-use node. This is the ultimate WanVideo generation solution. + +**Pipeline Components:** +- **WanVideoTeaCache** → cache_args → **WanVideoSampler** +- **WanVideoVACEEncode** → image_embeds → **WanVideoSampler** +- **WanVideoExperimentalArgs** → experimental_args → **WanVideoSampler** +- **WanVideoSampler** → samples → **WanVideoDecode** +- **WanVideoDecode** → final video output + +**Key Features:** +- **Complete Pipeline**: End-to-end video generation in a single node +- **Intelligent Connections**: Automatic parameter routing between internal components +- **Full Parameter Access**: All component parameters exposed except internal connections +- **Production Ready**: Optimized for real-world video generation workflows +- **Debug-Friendly**: Comprehensive logging for each pipeline stage + +**Inputs:** +**Required Pipeline Inputs:** +- `model`: WANVIDEOMODEL - The WanVideo model for generation +- `vae`: WANVAE - VAE for encoding/decoding operations + +**Core Sampling Parameters:** +- `steps`: INT - Number of sampling steps (default: 30) +- `cfg`: FLOAT - Classifier-free guidance scale (default: 6.0, range: 0-30) +- `shift`: FLOAT - Shift parameter for sampling (default: 5.0, range: 0-1000) +- `seed`: INT - Random seed for reproducibility (default: 0) +- `scheduler`: COMBO - Sampling scheduler (default: "unipc") + +**VACE Encoding Parameters:** +- `vace_width`: INT - Video width (default: 832, step: 8) +- `vace_height`: INT - Video height (default: 480, step: 8) +- `vace_num_frames`: INT - Number of frames (default: 81, step: 4) +- `vace_strength`: FLOAT - VACE strength (default: 1.0, range: 0-10) +- `vace_start_percent`: FLOAT - VACE start percentage (default: 0.0) +- `vace_end_percent`: FLOAT - VACE end percentage (default: 1.0) + +**TeaCache Parameters:** +- `teacache_rel_l1_thresh`: FLOAT - L1 threshold for cache (default: 0.3) +- `teacache_start_step`: INT - Cache start step (default: 1) +- `teacache_end_step`: INT - Cache end step (default: -1) +- `teacache_use_coefficients`: BOOLEAN - Use cache coefficients (default: True) +- `teacache_cache_device`: COMBO - Cache device ("main_device", "offload_device") +- `teacache_mode`: COMBO - Cache mode ("e", "e0") + +**Experimental Features Parameters:** +- `exp_video_attention_split_steps`: STRING - Video attention split steps +- `exp_cfg_zero_star`: BOOLEAN - Enable CFG zero star +- `exp_use_zero_init`: BOOLEAN - Use zero initialization +- `exp_zero_star_steps`: INT - Zero star steps count +- `exp_use_fresca`: BOOLEAN - Enable Fresca optimization +- `exp_fresca_scale_low`: FLOAT - Fresca low scale (default: 1.0) +- `exp_fresca_scale_high`: FLOAT - Fresca high scale (default: 1.25) +- `exp_fresca_freq_cutoff`: INT - Fresca frequency cutoff (default: 20) + +**Decode Parameters:** +- `decode_enable_vae_tiling`: BOOLEAN - Enable VAE tiling (default: False) +- `decode_tile_x`: INT - Tile width (default: 272) +- `decode_tile_y`: INT - Tile height (default: 272) +- `decode_tile_stride_x`: INT - Tile stride X (default: 144) +- `decode_tile_stride_y`: INT - Tile stride Y (default: 128) + +**Pipeline Control:** +- `enable_teacache`: BOOLEAN - Enable TeaCache optimization (default: True) +- `enable_experimental`: BOOLEAN - Enable experimental features (default: False) + +**Optional Advanced Inputs:** +- `text_embeds`: WANVIDEOTEXTEMBEDS - Text conditioning +- `samples`: LATENT - Input latent samples for img2img +- `riflex_freq_index`: INT - Riflex frequency index +- `denoise_strength`: FLOAT - Denoising strength (default: 1.0) +- `force_offload`: BOOLEAN - Force model offloading (default: True) +- `batched_cfg`: BOOLEAN - Use batched CFG (default: False) +- `rope_function`: COMBO - RoPE function ("default", "comfy") - Default: "comfy" + +**Optional Component Inputs:** +- `feta_args`: FETAARGS - FETA optimization arguments +- `context_options`: CONTEXTOPTIONS - Context handling options +- `loop_args`: LOOPARGS - Loop generation arguments +- `sigmas`: SIGMAS - Custom noise schedule +- `unianimate_poses`: UNIANIMATE_POSES - UniAnimate pose data +- `fantasytalking_embeds`: FANTASYTALKING_EMBEDS - Fantasy talking embeddings +- `uni3c_embeds`: UNI3C_EMBEDS - Uni3C embeddings +- `multitalk_embeds`: MULTITALK_EMBEDS - MultiTalk embeddings +- `freeinit_args`: FREEINIT_ARGS - FreeInit arguments + +**External Overrides:** +- `external_slg_args`: SLGARGS - Pre-built SLG arguments (overrides internal SLG) + +**VACE Optional Inputs:** +- `vace_input_frames`: IMAGE - Input frames for VACE +- `vace_ref_images`: IMAGE - Reference images for VACE +- `vace_input_masks`: MASK - Input masks for VACE +- `vace_tiled_vae`: BOOLEAN - Use tiled VAE in VACE + +**Decode Optional Inputs:** +- `decode_normalization`: COMBO - Normalization method ("default", "minmax") + +**Outputs:** +- `video`: IMAGE - Final generated video frames +- `latents`: LATENT - Generated latent samples (for further processing) + +**Pipeline Flow:** +1. **TeaCache Setup** (if enabled): Creates cache arguments for acceleration +2. **Experimental Setup** (if enabled): Configures advanced experimental features +3. **VACE Encoding**: Processes input parameters into image embeddings +4. **WanVideo Sampling**: Generates latent samples using all configured optimizations +5. **Video Decoding**: Converts latents to final video frames + +**Usage:** +The WanVideo VACE Pipeline node can be found in the "TiledWan" category in the ComfyUI node browser. + +1. **Connect Core Inputs**: Connect your WanVideo model and VAE +2. **Configure Generation**: Set steps, CFG, shift, seed, and video dimensions +3. **Enable Optimizations**: + - Keep `enable_teacache=True` for faster generation + - Set `enable_experimental=True` for cutting-edge features +4. **Fine-tune Components**: Adjust VACE, TeaCache, and decode parameters as needed +5. **Optional Enhancements**: Connect text embeddings, input frames, or external SLG args +6. **Run Pipeline**: Execute complete video generation in one step + +**Console Output includes:** +- **Pipeline Overview**: Total parameters and enabled components +- **Import Status**: WanVideo package loading confirmation +- **Step-by-Step Progress**: Detailed progress for each pipeline stage +- **Component Configuration**: Settings for TeaCache, VACE, experimental features +- **Sampling Details**: Model, embeddings, and parameter information +- **Decode Information**: VAE settings and output characteristics +- **Error Handling**: Comprehensive error reporting with full traceback + +**Advantages over Individual Nodes:** +- **Simplified Workflow**: Single node replaces 5+ individual nodes +- **Optimized Connections**: No manual parameter routing required +- **Reduced Complexity**: Fewer connections and potential error points +- **Better Performance**: Optimized internal data flow +- **Easier Debugging**: Centralized logging and error handling +- **Production Ready**: Designed for real-world video generation + +**Use Cases:** +- **Production Video Generation**: Complete solution for high-quality video creation +- **Rapid Prototyping**: Quick testing of WanVideo capabilities +- **Batch Processing**: Efficient generation of multiple videos +- **Research and Development**: Easy experimentation with WanVideo features +- **Educational**: Learn complete WanVideo workflow in one node +- **Integration**: Simple integration into larger ComfyUI workflows + +**Performance Tips:** +- Enable TeaCache for 2-3x speed improvement with minimal quality loss +- Use VAE tiling if running out of VRAM during decode +- Start with experimental features disabled, enable gradually +- Monitor console output for optimal parameter tuning +- Use appropriate video dimensions for your GPU memory +- Consider batch size vs. quality trade-offs + +**Internal Connections (Handled Automatically):** +- TeaCache args → WanVideoSampler cache_args +- VACE embeds → WanVideoSampler image_embeds +- Experimental args → WanVideoSampler experimental_args +- Sampler output → Decode input samples +- All internal routing handled transparently + +**Tips:** +- This node provides the complete WanVideo experience in a single, easy-to-use package +- All the power of the individual WanVideo nodes with simplified workflow +- Perfect for users who want complete WanVideo functionality without complex node routing +- Internal connections are optimized and error-proof +- Comprehensive debugging output helps troubleshoot any issues +- Designed for both beginners and advanced users \ No newline at end of file diff --git a/__pycache__/nodes.cpython-37.pyc b/__pycache__/nodes.cpython-37.pyc index 551f49292b814bd27a392bfdf6cf90e1e86dc4fd..b734e1ecf972e9113cb0ccfcf323f7ee4fcb13ee 100644 GIT binary patch delta 8882 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 aJqP7&h18zqtB%y$_-yVdB`qVBCH$9`)7dKk delta 1133 zcma)*OH30{6ozLgErqsPL=5poqQ<5!Fj!=Tv;|5nluB%oFfnOrXIh$cT5_jY(M5xa z3E&g1s5}(k8WjQS0}MX#QR2$@SYTpIT0@WjEDDeR)5(ox4sxyqjF<%V%8ctbhahc6Ktxi2C>LO%uQT}dD;j~$6%&2PX95%DV zR%3Qq+_gKL7SwVp%?_8@+2AtUt8EUe+fq|zslb97nhoWtTw7CTciFHlrO}b1-*B6u zt=$=CU<`0oyt?>Ddh7@!&qPkZ*Ic&TL^>fOU5E|@Mf4*25GMh1 zz0*e04VjCa!$LpeEaDWPk_=#YnqguLIgH_X#0A7f#3jUK#1+I<#5I6^6){jAma8Azm&B0*V+Ghq6bRa6r8LojVd0cIEE#oJ8LG`78~yj9r) zbv;W4;_c-na>FY;@Fn6kz~9@0Ys^Rzn8AiMZPd$1vJYEGB0jU7Wn(Ejw^1EJ3?oJm zcK}lgVIRDw5{aWSh`5Wmhc#8bC$uZT3t^|-N*&=1x5iU}y{<+NS2gYZf0DAcRT20TRN4U4{(f@b(1O3BxaTQRGM;2`K0 jJt2=@5QR{L_J!8NwJ$>T>?XQ8yfP=0#?F3}^7-fwuA(os diff --git a/nodes.py b/nodes.py index bb33007..d7bf176 100644 --- a/nodes.py +++ b/nodes.py @@ -694,6 +694,319 @@ class TiledWanVideoSLGSimple: return (dummy_slg,) +class WanVideoVACEpipe: + """ + Complete WanVideo pipeline that encapsulates multiple WanVideo nodes: + - WanVideoTeaCache -> cache_args + - WanVideoVACEEncode -> image_embeds + - WanVideoExperimentalArgs -> experimental_args + - WanVideoSampler (original, not TiledWan wrapper) + - WanVideoDecode -> final video output + + This node provides a complete video generation pipeline in a single node + with full access to all parameters except internal connections. + """ + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(cls): + """ + Complete pipeline inputs combining all WanVideo nodes + """ + return { + "required": { + # Core pipeline inputs + "model": ("WANVIDEOMODEL",), + "vae": ("WANVAE",), + + # WanVideoSampler core inputs + "steps": ("INT", {"default": 30, "min": 1}), + "cfg": ("FLOAT", {"default": 6.0, "min": 0.0, "max": 30.0, "step": 0.01}), + "shift": ("FLOAT", {"default": 5.0, "min": 0.0, "max": 1000.0, "step": 0.01}), + "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), + "scheduler": (["unipc", "unipc/beta", "dpm++", "dpm++/beta","dpm++_sde", "dpm++_sde/beta", "euler", "euler/beta", "euler/accvideo", "deis", "lcm", "lcm/beta", "flowmatch_causvid", "flowmatch_distill", "multitalk"], + {"default": 'unipc'}), + + # WanVideoVACEEncode inputs + "vace_width": ("INT", {"default": 832, "min": 64, "max": 8096, "step": 8}), + "vace_height": ("INT", {"default": 480, "min": 64, "max": 8096, "step": 8}), + "vace_num_frames": ("INT", {"default": 81, "min": 1, "max": 10000, "step": 4}), + "vace_strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}), + "vace_start_percent": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}), + "vace_end_percent": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), + + # WanVideoTeaCache inputs + "teacache_rel_l1_thresh": ("FLOAT", {"default": 0.3, "min": 0.0, "max": 1.0, "step": 0.001}), + "teacache_start_step": ("INT", {"default": 1, "min": 0, "max": 9999, "step": 1}), + "teacache_end_step": ("INT", {"default": -1, "min": -1, "max": 9999, "step": 1}), + "teacache_use_coefficients": ("BOOLEAN", {"default": True}), + "teacache_cache_device": (["main_device", "offload_device"], {"default": "offload_device"}), + "teacache_mode": (["e", "e0"], {"default": "e"}), + + # WanVideoExperimentalArgs inputs + "exp_video_attention_split_steps": ("STRING", {"default": ""}), + "exp_cfg_zero_star": ("BOOLEAN", {"default": False}), + "exp_use_zero_init": ("BOOLEAN", {"default": False}), + "exp_zero_star_steps": ("INT", {"default": 0, "min": 0}), + "exp_use_fresca": ("BOOLEAN", {"default": False}), + "exp_fresca_scale_low": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}), + "exp_fresca_scale_high": ("FLOAT", {"default": 1.25, "min": 0.0, "max": 10.0, "step": 0.01}), + "exp_fresca_freq_cutoff": ("INT", {"default": 20, "min": 0, "max": 10000, "step": 1}), + + # WanVideoDecode inputs + "decode_enable_vae_tiling": ("BOOLEAN", {"default": False}), + "decode_tile_x": ("INT", {"default": 272, "min": 40, "max": 2048, "step": 8}), + "decode_tile_y": ("INT", {"default": 272, "min": 40, "max": 2048, "step": 8}), + "decode_tile_stride_x": ("INT", {"default": 144, "min": 32, "max": 2040, "step": 8}), + "decode_tile_stride_y": ("INT", {"default": 128, "min": 32, "max": 2040, "step": 8}), + + # Enable/disable pipeline components + "enable_teacache": ("BOOLEAN", {"default": True}), + "enable_experimental": ("BOOLEAN", {"default": False}), + }, + "optional": { + # WanVideoSampler optional inputs + "text_embeds": ("WANVIDEOTEXTEMBEDS",), + "samples": ("LATENT",), + "riflex_freq_index": ("INT", {"default": 0, "min": 0, "max": 1000, "step": 1}), + "denoise_strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), + "force_offload": ("BOOLEAN", {"default": True}), + "batched_cfg": ("BOOLEAN", {"default": False}), + "rope_function": (["default", "comfy"], {"default": "comfy"}), + + # WanVideoSampler advanced optional inputs + "feta_args": ("FETAARGS",), + "context_options": ("CONTEXTOPTIONS",), + "loop_args": ("LOOPARGS",), + "sigmas": ("SIGMAS",), + "unianimate_poses": ("UNIANIMATE_POSES",), + "fantasytalking_embeds": ("FANTASYTALKING_EMBEDS",), + "uni3c_embeds": ("UNI3C_EMBEDS",), + "multitalk_embeds": ("MULTITALK_EMBEDS",), + "freeinit_args": ("FREEINIT_ARGS",), + + # External pre-built arguments (override internal ones if provided) + "external_slg_args": ("SLGARGS",), + + # WanVideoVACEEncode optional inputs + "vace_input_frames": ("IMAGE",), + "vace_ref_images": ("IMAGE",), + "vace_input_masks": ("MASK",), + "vace_tiled_vae": ("BOOLEAN", {"default": False}), + + # WanVideoDecode optional inputs + "decode_normalization": (["default", "minmax"], {"default": "default"}), + }, + } + + RETURN_TYPES = ("IMAGE", "LATENT") + RETURN_NAMES = ("video", "latents") + FUNCTION = "process_wanvideo_pipeline" + OUTPUT_NODE = True + CATEGORY = "TiledWan" + + def process_wanvideo_pipeline(self, **kwargs): + """ + Execute the complete WanVideo pipeline by chaining all nodes + """ + + print("\n" + "="*80) + print(" WANVIDEO VACE PIPELINE") + print("="*80) + print("🚀 Starting complete WanVideo VACE pipeline...") + print(f"📊 Total parameters received: {len(kwargs)}") + + try: + # Import all WanVideo nodes we need + import sys + import os + import importlib + + custom_nodes_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "ComfyUI-WanVideoWrapper") + if custom_nodes_path not in sys.path: + sys.path.append(custom_nodes_path) + print(f"📁 Added to sys.path: {custom_nodes_path}") + + # Add parent directory to sys.path and import normally + parent_path = os.path.dirname(custom_nodes_path) + if parent_path not in sys.path: + sys.path.insert(0, parent_path) + print(f"📁 Added parent to sys.path: {parent_path}") + + # Import the package normally to handle relative imports + package_name = os.path.basename(custom_nodes_path) # "ComfyUI-WanVideoWrapper" + print(f"🔄 Importing WanVideo package: {package_name}") + wanvideo_package = importlib.import_module(f"{package_name}.nodes") + + WanVideoSampler = wanvideo_package.WanVideoSampler + WanVideoTeaCache = wanvideo_package.WanVideoTeaCache + WanVideoVACEEncode = wanvideo_package.WanVideoVACEEncode + WanVideoExperimentalArgs = wanvideo_package.WanVideoExperimentalArgs + WanVideoDecode = wanvideo_package.WanVideoDecode + print("✅ All WanVideo nodes imported successfully!") + + # Step 1: Create TeaCache arguments (if enabled) + cache_args = None + if kwargs.get("enable_teacache", True): + print("📦 Step 1: Building TeaCache arguments...") + cache_device = kwargs.get("teacache_cache_device", "offload_device") + if cache_device == "main_device": + import comfy.model_management as mm + cache_device = mm.get_torch_device() + else: + import comfy.model_management as mm + cache_device = mm.unet_offload_device() + + cache_args = { + "cache_type": "TeaCache", + "rel_l1_thresh": kwargs.get("teacache_rel_l1_thresh", 0.3), + "start_step": kwargs.get("teacache_start_step", 1), + "end_step": kwargs.get("teacache_end_step", -1), + "cache_device": cache_device, + "use_coefficients": kwargs.get("teacache_use_coefficients", True), + "mode": kwargs.get("teacache_mode", "e"), + } + print(f"✅ TeaCache args: {cache_args}") + else: + print("⏭️ Step 1: TeaCache disabled, skipping...") + + # Step 2: Create Experimental arguments (if enabled) + experimental_args = None + if kwargs.get("enable_experimental", False): + print("📦 Step 2: Building Experimental arguments...") + exp_node = WanVideoExperimentalArgs() + experimental_args = exp_node.process( + video_attention_split_steps=kwargs.get("exp_video_attention_split_steps", ""), + cfg_zero_star=kwargs.get("exp_cfg_zero_star", False), + use_zero_init=kwargs.get("exp_use_zero_init", False), + zero_star_steps=kwargs.get("exp_zero_star_steps", 0), + use_fresca=kwargs.get("exp_use_fresca", False), + fresca_scale_low=kwargs.get("exp_fresca_scale_low", 1.0), + fresca_scale_high=kwargs.get("exp_fresca_scale_high", 1.25), + fresca_freq_cutoff=kwargs.get("exp_fresca_freq_cutoff", 20) + )[0] + print(f"✅ Experimental args: {experimental_args}") + else: + print("⏭️ Step 2: Experimental features disabled, skipping...") + + # Step 3: Create VACE embeds + print("📦 Step 3: Creating VACE embeds...") + vace_node = WanVideoVACEEncode() + vace_embeds = vace_node.process( + vae=kwargs["vae"], + width=kwargs.get("vace_width", 832), + height=kwargs.get("vace_height", 480), + num_frames=kwargs.get("vace_num_frames", 81), + strength=kwargs.get("vace_strength", 1.0), + vace_start_percent=kwargs.get("vace_start_percent", 0.0), + vace_end_percent=kwargs.get("vace_end_percent", 1.0), + input_frames=kwargs.get("vace_input_frames"), + ref_images=kwargs.get("vace_ref_images"), + input_masks=kwargs.get("vace_input_masks"), + tiled_vae=kwargs.get("vace_tiled_vae", False) + )[0] + print(f"✅ VACE embeds created: {type(vace_embeds)}") + + # Step 4: Run WanVideoSampler (original node, not our wrapper) + print("🎯 Step 4: Running WanVideoSampler...") + print(f" • Model: {type(kwargs['model'])}") + print(f" • VACE embeds: {type(vace_embeds)}") + print(f" • Steps: {kwargs.get('steps', 30)}") + print(f" • CFG: {kwargs.get('cfg', 6.0)}") + print(f" • Shift: {kwargs.get('shift', 5.0)}") + print(f" • Seed: {kwargs.get('seed', 0)}") + print(f" • Scheduler: {kwargs.get('scheduler', 'unipc')}") + print(f" • Rope function: {kwargs.get('rope_function', 'comfy')}") + print(f" • TeaCache enabled: {'Yes' if cache_args else 'No'}") + print(f" • Experimental enabled: {'Yes' if experimental_args else 'No'}") + print(f" • External SLG args: {'Yes' if kwargs.get('external_slg_args') else 'No'}") + + sampler_node = WanVideoSampler() + latent_samples = sampler_node.process( + model=kwargs["model"], + image_embeds=vace_embeds, # VACE embeds -> image_embeds + steps=kwargs.get("steps", 30), + cfg=kwargs.get("cfg", 6.0), + shift=kwargs.get("shift", 5.0), + seed=kwargs.get("seed", 0), + scheduler=kwargs.get("scheduler", "unipc"), + riflex_freq_index=kwargs.get("riflex_freq_index", 0), + text_embeds=kwargs.get("text_embeds"), + samples=kwargs.get("samples"), + denoise_strength=kwargs.get("denoise_strength", 1.0), + force_offload=kwargs.get("force_offload", True), + + # Pipeline connections + cache_args=cache_args, # TeaCache args -> cache_args + slg_args=kwargs.get("external_slg_args"), # SLG args -> slg_args + experimental_args=experimental_args, # Experimental args -> experimental_args + + # Other WanVideoSampler arguments + feta_args=kwargs.get("feta_args"), + context_options=kwargs.get("context_options"), + flowedit_args=None, + batched_cfg=kwargs.get("batched_cfg", False), + rope_function=kwargs.get("rope_function", "comfy"), + loop_args=kwargs.get("loop_args"), + sigmas=kwargs.get("sigmas"), + unianimate_poses=kwargs.get("unianimate_poses"), + fantasytalking_embeds=kwargs.get("fantasytalking_embeds"), + uni3c_embeds=kwargs.get("uni3c_embeds"), + multitalk_embeds=kwargs.get("multitalk_embeds"), + freeinit_args=kwargs.get("freeinit_args") + )[0] + + print(f"✅ WanVideoSampler completed!") + print(f" • Output type: {type(latent_samples)}") + if hasattr(latent_samples, 'get') and 'samples' in latent_samples: + print(f" • Latent shape: {latent_samples['samples'].shape}") + + # Step 5: Decode latents to video + print("🎬 Step 5: Decoding latents to video...") + print(f" • VAE: {type(kwargs['vae'])}") + print(f" • Latents: {type(latent_samples)}") + print(f" • Enable VAE tiling: {kwargs.get('decode_enable_vae_tiling', False)}") + print(f" • Tile size: {kwargs.get('decode_tile_x', 272)}x{kwargs.get('decode_tile_y', 272)}") + print(f" • Normalization: {kwargs.get('decode_normalization', 'default')}") + + decode_node = WanVideoDecode() + video_output = decode_node.decode( + vae=kwargs["vae"], + samples=latent_samples, # Sampler samples -> decode samples + enable_vae_tiling=kwargs.get("decode_enable_vae_tiling", False), + tile_x=kwargs.get("decode_tile_x", 272), + tile_y=kwargs.get("decode_tile_y", 272), + tile_stride_x=kwargs.get("decode_tile_stride_x", 144), + tile_stride_y=kwargs.get("decode_tile_stride_y", 128), + normalization=kwargs.get("decode_normalization", "default") + )[0] + + print(f"✅ Video decoding completed!") + print(f" • Video output type: {type(video_output)}") + if hasattr(video_output, 'shape'): + print(f" • Video shape: {video_output.shape}") + + print("🎉 Complete WanVideo VACE pipeline finished successfully!") + print("="*80 + "\n") + + return (video_output, latent_samples) + + except Exception as e: + import traceback + print(f"❌ Error in WanVideo VACE pipeline: {str(e)}") + print(f"📋 Full traceback:") + print(traceback.format_exc()) + print("="*80 + "\n") + + # Return dummy outputs in case of error + dummy_video = torch.zeros((1, 64, 64, 3)) # Dummy video frame + dummy_latent = {"samples": torch.zeros((1, 16, 10, 8, 8))} # Dummy latent + + return (dummy_video, dummy_latent) + + # A dictionary that contains all nodes you want to export with their names # NOTE: names should be globally unique NODE_CLASS_MAPPINGS = { @@ -701,7 +1014,8 @@ NODE_CLASS_MAPPINGS = { "TiledWanImageStatistics": ImageStatistics, "TiledWanMaskStatistics": MaskStatistics, "TiledWanVideoSamplerSimple": TiledWanVideoSamplerSimple, - "TiledWanVideoSLGSimple": TiledWanVideoSLGSimple + "TiledWanVideoSLGSimple": TiledWanVideoSLGSimple, + "WanVideoVACEpipe": WanVideoVACEpipe } # A dictionary that contains the friendly/humanly readable titles for the nodes @@ -710,5 +1024,6 @@ NODE_DISPLAY_NAME_MAPPINGS = { "TiledWanImageStatistics": "TiledWan Image Statistics", "TiledWanMaskStatistics": "TiledWan Mask Statistics", "TiledWanVideoSamplerSimple": "TiledWan Video Sampler Simple", - "TiledWanVideoSLGSimple": "TiledWan Video SLG Simple" + "TiledWanVideoSLGSimple": "TiledWan Video SLG Simple", + "WanVideoVACEpipe": "WanVideo VACE Pipeline" }