diff --git a/nodes.py b/nodes.py index a09a60a..271b374 100644 --- a/nodes.py +++ b/nodes.py @@ -1618,6 +1618,8 @@ class WanVideoVACEEncode: "height": ("INT", {"default": 480, "min": 64, "max": 29048, "step": 8, "tooltip": "Height of the image to encode"}), "num_frames": ("INT", {"default": 81, "min": 1, "max": 10000, "step": 4, "tooltip": "Number of frames to encode"}), "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, "tooltip": "Start percent of the steps to apply VACE"}), + "vace_end_percent": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "tooltip": "End percent of the steps to apply VACE"}), }, "optional": { "input_frames": ("IMAGE",), @@ -1631,7 +1633,7 @@ class WanVideoVACEEncode: FUNCTION = "process" CATEGORY = "WanVideoWrapper" - def process(self, vae, width, height, num_frames, strength, input_frames=None, ref_images=None, input_masks=None): + def process(self, vae, width, height, num_frames, strength, vace_start_percent, vace_end_percent, input_frames=None, ref_images=None, input_masks=None): self.device = mm.get_torch_device() offload_device = mm.unet_offload_device() @@ -1693,7 +1695,9 @@ class WanVideoVACEEncode: "vace_scale": strength, "has_ref": ref_images is not None, "num_frames": num_frames, - "target_shape": target_shape + "target_shape": target_shape, + "vace_start_percent": vace_start_percent, + "vace_end_percent": vace_end_percent, } return (vace_input,) @@ -2001,6 +2005,8 @@ class WanVideoSampler: has_ref = image_embeds.get("has_ref", False) vace_context = image_embeds.get("vace_context", None) vace_scale = image_embeds.get("vace_scale", None) + vace_start_percent = image_embeds.get("vace_start_percent", 0.0) + vace_end_percent = image_embeds.get("vace_end_percent", 1.0) noise = torch.randn( target_shape[0], @@ -2293,6 +2299,12 @@ class WanVideoSampler: patcher.model.is_patched = True else: image_cond_input = image_cond + + if vace_context is not None: + vace_context_input = vace_context + if not (vace_start_percent <= current_step_percentage <= vace_end_percent) or \ + (vace_end_percent > 0 and idx == 0 and current_step_percentage >= vace_start_percent): + vace_context_input = None base_params = { 'seq_len': seq_len, @@ -2302,7 +2314,7 @@ class WanVideoSampler: 'current_step': idx, 'y': [image_cond_input] if image_cond_input is not None else None, 'control_lora_enabled': control_lora_enabled, - 'vace_context': vace_context, + 'vace_context': vace_context_input if vace_context is not None else None, 'vace_scale': vace_scale, } diff --git a/pyproject.toml b/pyproject.toml index 6fb087d..826f964 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "ComfyUI-WanVideoWrapper" description = "ComfyUI diffusers wrapper nodes for WanVideo" -version = "1.1.1" +version = "1.1.2" license = {file = "LICENSE"} dependencies = ["accelerate >= 1.2.1", "diffusers >= 0.32.0", "ftfy"] diff --git a/wanvideo/modules/model.py b/wanvideo/modules/model.py index f1ae5f9..7b861ea 100644 --- a/wanvideo/modules/model.py +++ b/wanvideo/modules/model.py @@ -556,8 +556,11 @@ class BaseWanAttentionBlock(WanAttentionBlock): super().__init__(cross_attn_type, dim, ffn_dim, num_heads, window_size, qk_norm, cross_attn_norm, eps, attention_mode) self.block_id = block_id - def forward(self, x, vace_hints, vace_context_scale=1.0, **kwargs): + def forward(self, x, vace_hints=None, vace_context_scale=1.0, **kwargs): x = super().forward(x, **kwargs) + if vace_hints is None: + return x + if self.block_id is not None: x = x + vace_hints[self.block_id] * vace_context_scale return x @@ -1023,7 +1026,7 @@ class WanModel(ModelMixin, ConfigMixin): current_step=current_step, video_attention_split_steps=self.video_attention_split_steps ) - + if vace_context is not None: vace_hints = self.forward_vace(x, vace_context, seq_len, kwargs) vace_context_scale = vace_scale