commit d1e9f7141a170488b1bb3c159f9e5fdc4d26a74b Author: KBRASK Date: Wed Aug 13 16:09:35 2025 +0800 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..0de293a --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# Stand-In Official Preprocessor ComfyUI Nodes +

+ Logo + Stand-In +

+ +[![Project Page](https://img.shields.io/badge/Project_Page-www.stand--in.tech-green)](https://www.stand-in.tech) +[![Main Repo](https://img.shields.io/badge/Main_Repository-Stand--In-blue)](https://github.com/WeChatCV/Stand-In) + +> 🧩 Only images processed with this official preprocessor can fully unleash the power of **Stand-In**. + +--- + +This repository provides a **temporary** ComfyUI node implementation of the Stand-In preprocessor, aiming to correct the misunderstanding of Stand-In’s preprocessing logic in [ComfyUI-WanVideoWrapper](https://github.com/kijai/ComfyUI-WanVideoWrapper). + +We **strongly recommend** using the workflows provided in this repo to ensure proper compatibility and the best identity-preserving performance. + +> **Note**: This is a **temporary node**. Features such as KV cache support and advanced attention mechanisms are **not yet implemented**. We are actively developing the **official full-featured ComfyUI nodes** for Stand-In. + + +## ⚠️ Important Usage Tips + +> **Prompt Writing Tip:** +> If you do **not** wish to alter the subject's facial features, simply use **"a man"** or **"a woman"** without adding extra descriptions of their appearance. +> Prompts support both **Chinese** and **English** input. +> The prompt is intended for generating **frontal, medium-to-close-up videos**. + +> **Input Image Recommendation:** +> For best results, use a **high-resolution frontal face image**. +> There are **no restrictions** on resolution or file extension, as our **built-in preprocessing pipeline** will handle them automatically. + +--- +We are also actively developing a more flexible version of Stand-In. + +--- + +## 🌐 Project Links + +- 📘 **Main Repository**: [WeChatCV/Stand-In](https://github.com/WeChatCV/Stand-In) +- 🏠 **Project Page**: [www.stand-in.tech](https://www.stand-in.tech) + +--- + +## 🚀 Installation +Clone this repository into the `custom_nodes` directory of your ComfyUI installation: + +```bash +git clone https://github.com/WeChatCV/Stand-In_Preprocessor_ComfyUI.git +cd Stand-In_Preprocessor_ComfyUI +pip install -r requirements.txt diff --git a/Stand-In.png b/Stand-In.png new file mode 100755 index 0000000..735741a Binary files /dev/null and b/Stand-In.png differ diff --git a/Stand-In_preprocessor.py b/Stand-In_preprocessor.py new file mode 100644 index 0000000..c329c37 --- /dev/null +++ b/Stand-In_preprocessor.py @@ -0,0 +1,200 @@ +import os +import cv2 +import requests +import torch +import numpy as np +import PIL.Image +import PIL.ImageOps +from insightface.app import FaceAnalysis +from facexlib.parsing import init_parsing_model +from torchvision.transforms.functional import normalize +from typing import Union, Optional +import folder_paths +from huggingface_hub import snapshot_download + +LOADED_PROCESSORS = {} + +def set_extra_config_model_path(extra_config_models_dir_key, models_dir_name: str): + models_dir_default = os.path.join(folder_paths.models_dir, models_dir_name) + if extra_config_models_dir_key not in folder_paths.folder_names_and_paths: + folder_paths.folder_names_and_paths[extra_config_models_dir_key] = ( + [os.path.join(folder_paths.models_dir, models_dir_name)], + folder_paths.supported_pt_extensions, + ) + else: + if not os.path.exists(models_dir_default): + os.makedirs(models_dir_default, exist_ok=True) + folder_paths.add_model_folder_path(extra_config_models_dir_key, models_dir_default, is_default=True) + +set_extra_config_model_path("insightface", "insightface") + +def _img2tensor(img: np.ndarray, bgr2rgb: bool = True) -> torch.Tensor: + if bgr2rgb: + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + img = img.astype(np.float32) / 255.0 + img = np.transpose(img, (2, 0, 1)) + return torch.from_numpy(img) + +def _pad_to_square(img: np.ndarray, pad_color: int = 255) -> np.ndarray: + h, w, _ = img.shape + if h == w: + return img + + if h > w: + pad_size = (h - w) // 2 + padded_img = cv2.copyMakeBorder( + img, 0, 0, pad_size, h - w - pad_size, cv2.BORDER_CONSTANT, value=[pad_color] * 3, + ) + else: + pad_size = (w - h) // 2 + padded_img = cv2.copyMakeBorder( + img, pad_size, w - h - pad_size, 0, 0, cv2.BORDER_CONSTANT, value=[pad_color] * 3, + ) + return padded_img + +def tensor_to_cv2_img(tensor: torch.Tensor) -> np.ndarray: + img_np = tensor.squeeze(0).cpu().numpy() + img_np = (img_np * 255).astype(np.uint8) + img_bgr = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR) + return img_bgr + +def cv2_img_to_tensor(img: np.ndarray) -> torch.Tensor: + img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + img_rgb = img_rgb.astype(np.float32) / 255.0 + return torch.from_numpy(img_rgb).unsqueeze(0) + + +class FaceProcessorLoader: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "antelopev2_path": ("STRING", {"default": "models/insightface"}) + } + } + + RETURN_TYPES = ("FACE_PROCESSOR",) + RETURN_NAMES = ("face_processor",) + FUNCTION = "load_processor" + CATEGORY = "Stand-In" + + def load_processor(self, antelopev2_path="models/insightface"): + if "face_processor" in LOADED_PROCESSORS: + print("Reusing cached FaceProcessor models.") + return (LOADED_PROCESSORS["face_processor"],) + antelopev2_path = folder_paths.get_folder_paths("insightface")[0] + print("Initializing FaceProcessor models...") + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + providers = ["CUDAExecutionProvider"] if device.type == "cuda" else ["CPUExecutionProvider"] + + if not os.path.exists(antelopev2_path): + os.makedirs(antelopev2_path) + print(f"Created insightface model directory at: {antelopev2_path}") + try: + print("Attempting to load FaceAnalysis model from local files...") + app = FaceAnalysis(name="antelopev2", root=antelopev2_path, providers=providers) + except Exception as e: + print(f"Failed to load local FaceAnalysis model: {e}") + if snapshot_download is None: + raise ImportError("huggingface_hub is not installed. Please install it with 'pip install huggingface_hub' to enable automatic model downloading.") from e + + print("Attempting to download model from Hugging Face...") + download_target_path = os.path.join(antelopev2_path, "models", "antelopev2") + snapshot_download( + repo_id="DIAMONIK7777/antelopev2", + local_dir=download_target_path, + ) + print("Model downloaded. Retrying to load FaceAnalysis model...") + app = FaceAnalysis(name="antelopev2", root=antelopev2_path, providers=providers) + + app.prepare(ctx_id=0, det_size=(640, 640)) + + parsing_model = init_parsing_model(model_name="bisenet", device=device) + parsing_model.eval() + + processor_tuple = (app, parsing_model, device) + LOADED_PROCESSORS["face_processor"] = processor_tuple + + print("FaceProcessor models initialized and cached successfully.") + + return (processor_tuple,) + + + +class ApplyFaceProcessor: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "face_processor": ("FACE_PROCESSOR",), + "image": ("IMAGE",), + "resize_to": ("INT", {"default": 512, "min": 64, "max": 2048, "step": 64}), + "border_thresh": ("INT", {"default": 10, "min": 0, "max": 100, "step": 1}), + "face_crop_scale": ("FLOAT", {"default": 1.5, "min": 1.0, "max": 3.0, "step": 0.1}), + } + } + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "apply_processing" + CATEGORY = "FaceUtils" + + def apply_processing(self, face_processor, image, resize_to, border_thresh, face_crop_scale): + app, parsing_model, device = face_processor + + frame = tensor_to_cv2_img(image) + + faces = app.get(frame) + h, w, _ = frame.shape + image_to_process = None + + if not faces: + print("[Warning] No face detected. Using the whole image, padded to square.") + image_to_process = _pad_to_square(frame, pad_color=255) + else: + largest_face = max(faces, key=lambda f: (f.bbox[2] - f.bbox[0]) * (f.bbox[3] - f.bbox[1])) + x1, y1, x2, y2 = map(int, largest_face.bbox) + + is_close_to_border = (x1 <= border_thresh and y1 <= border_thresh and + x2 >= w - border_thresh and y2 >= h - border_thresh) + + if is_close_to_border: + print("[Info] Face is close to border, padding original image to square.") + image_to_process = _pad_to_square(frame, pad_color=255) + else: + cx, cy = (x1 + x2) // 2, (y1 + y2) // 2 + side = int(max(x2 - x1, y2 - y1) * face_crop_scale) + half = side // 2 + + left, top = max(cx - half, 0), max(cy - half, 0) + right, bottom = min(cx + half, w), min(cy + half, h) + + cropped_face = frame[top:bottom, left:right] + image_to_process = _pad_to_square(cropped_face, pad_color=255) + + image_resized = cv2.resize(image_to_process, (resize_to, resize_to), interpolation=cv2.INTER_AREA) + + face_tensor = _img2tensor(image_resized, bgr2rgb=True).unsqueeze(0).to(device) + with torch.no_grad(): + normalized_face = normalize(face_tensor, [0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) + parsing_out = parsing_model(normalized_face)[0] + parsing_mask = parsing_out.argmax(dim=1, keepdim=True) + + mask = (parsing_mask.squeeze().cpu().numpy() == 0).astype(np.uint8) + white_background = np.ones_like(image_resized, dtype=np.uint8) * 255 + mask_3channel = cv2.cvtColor(mask * 255, cv2.COLOR_GRAY2BGR) + result_img_bgr = np.where(mask_3channel == 255, white_background, image_resized) + + result_tensor = cv2_img_to_tensor(result_img_bgr) + + return (result_tensor,) + + +NODE_CLASS_MAPPINGS = { + "FaceProcessorLoader": FaceProcessorLoader, + "ApplyFaceProcessor": ApplyFaceProcessor +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "FaceProcessorLoader": "Stand-In Processor Loader", + "ApplyFaceProcessor": "Apply Stand-In Processor" +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5c7088d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +insightface==0.7.3 +huggingface_hub==0.31.1 +facexlib==0.3.0 +onnxruntime-gpu==1.22.0 \ No newline at end of file diff --git a/wanvideo_Stand-In_reference_example.json b/wanvideo_Stand-In_reference_example.json new file mode 100644 index 0000000..e995d73 --- /dev/null +++ b/wanvideo_Stand-In_reference_example.json @@ -0,0 +1,1785 @@ +{ + "id": "206247b6-9fec-4ed2-8927-e4f388c674d4", + "revision": 0, + "last_node_id": 129, + "last_link_id": 229, + "nodes": [ + { + "id": 50, + "type": "CLIPTextEncode", + "pos": [ + 493.1703796386719, + 1356.8651123046875 + ], + "size": [ + 400, + 200 + ], + "flags": {}, + "order": 18, + "mode": 2, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 53 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "slot_index": 0, + "links": [ + 55 + ] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.26", + "Node name for S&R": "CLIPTextEncode" + }, + "widgets_values": [ + "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走" + ] + }, + { + "id": 49, + "type": "CLIPTextEncode", + "pos": [ + 493.1703796386719, + 1106.8651123046875 + ], + "size": [ + 400, + 200 + ], + "flags": {}, + "order": 17, + "mode": 2, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 52 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "slot_index": 0, + "links": [ + 54 + ] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.26", + "Node name for S&R": "CLIPTextEncode" + }, + "widgets_values": [ + "high quality nature video featuring a red panda balancing on a bamboo stem while a bird lands on it's head, on the background there is a waterfall" + ] + }, + { + "id": 36, + "type": "Note", + "pos": [ + 160, + -1010 + ], + "size": [ + 374.3061828613281, + 171.9547576904297 + ], + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "fp8_fast seems to cause huge quality degradation\n\nfp_16_fast enables \"Full FP16 Accmumulation in FP16 GEMMs\" feature available in the very latest pytorch nightly, this is around 20% speed boost. \n\nSageattn if you have it installed can be used for almost double inference speed" + ], + "color": "#432", + "bgcolor": "#653" + }, + { + "id": 33, + "type": "Note", + "pos": [ + 170, + -1150 + ], + "size": [ + 359.0753479003906, + 88 + ], + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "Models:\nhttps://huggingface.co/Kijai/WanVideo_comfy/tree/main" + ], + "color": "#432", + "bgcolor": "#653" + }, + { + "id": 51, + "type": "Note", + "pos": [ + 163.1707763671875, + 936.8648071289062 + ], + "size": [ + 253.16725158691406, + 88 + ], + "flags": {}, + "order": 2, + "mode": 2, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "You can also use native ComfyUI text encoding with these nodes instead of the original, the models are node specific and can't otherwise be mixed." + ], + "color": "#432", + "bgcolor": "#653" + }, + { + "id": 48, + "type": "CLIPLoader", + "pos": [ + 133.1708221435547, + 1106.8651123046875 + ], + "size": [ + 315, + 106 + ], + "flags": {}, + "order": 3, + "mode": 2, + "inputs": [], + "outputs": [ + { + "name": "CLIP", + "type": "CLIP", + "slot_index": 0, + "links": [ + 52, + 53 + ] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.26", + "Node name for S&R": "CLIPLoader" + }, + "widgets_values": [ + "t5\\t5xxl_fp8_e4m3fn_scaled.safetensors", + "wan", + "default" + ] + }, + { + "id": 70, + "type": "WanVideoSetBlockSwap", + "pos": [ + 823.8463134765625, + -766.5842895507812 + ], + "size": [ + 201.76815795898438, + 46 + ], + "flags": {}, + "order": 24, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "WANVIDEOMODEL", + "link": 90 + }, + { + "name": "block_swap_args", + "shape": 7, + "type": "BLOCKSWAPARGS", + "link": 92 + } + ], + "outputs": [ + { + "name": "model", + "type": "WANVIDEOMODEL", + "links": [ + 107 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "5406a72f62adf4a31a8a0a0e4923cc5288399652", + "Node name for S&R": "WanVideoSetBlockSwap" + }, + "widgets_values": [], + "color": "#223", + "bgcolor": "#335" + }, + { + "id": 27, + "type": "WanVideoSampler", + "pos": [ + 1434.9656982421875, + -536.9714965820312 + ], + "size": [ + 315, + 873.39453125 + ], + "flags": {}, + "order": 29, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "WANVIDEOMODEL", + "link": 108 + }, + { + "name": "image_embeds", + "type": "WANVIDIMAGE_EMBEDS", + "link": 172 + }, + { + "name": "text_embeds", + "shape": 7, + "type": "WANVIDEOTEXTEMBEDS", + "link": 30 + }, + { + "name": "samples", + "shape": 7, + "type": "LATENT", + "link": null + }, + { + "name": "feta_args", + "shape": 7, + "type": "FETAARGS", + "link": null + }, + { + "name": "context_options", + "shape": 7, + "type": "WANVIDCONTEXT", + "link": null + }, + { + "name": "cache_args", + "shape": 7, + "type": "CACHEARGS", + "link": null + }, + { + "name": "flowedit_args", + "shape": 7, + "type": "FLOWEDITARGS", + "link": null + }, + { + "name": "slg_args", + "shape": 7, + "type": "SLGARGS", + "link": null + }, + { + "name": "loop_args", + "shape": 7, + "type": "LOOPARGS", + "link": null + }, + { + "name": "experimental_args", + "shape": 7, + "type": "EXPERIMENTALARGS", + "link": null + }, + { + "name": "sigmas", + "shape": 7, + "type": "SIGMAS", + "link": null + }, + { + "name": "unianimate_poses", + "shape": 7, + "type": "UNIANIMATE_POSE", + "link": null + }, + { + "name": "fantasytalking_embeds", + "shape": 7, + "type": "FANTASYTALKING_EMBEDS", + "link": null + }, + { + "name": "uni3c_embeds", + "shape": 7, + "type": "UNI3C_EMBEDS", + "link": null + }, + { + "name": "multitalk_embeds", + "shape": 7, + "type": "MULTITALK_EMBEDS", + "link": null + }, + { + "name": "freeinit_args", + "shape": 7, + "type": "FREEINITARGS", + "link": null + } + ], + "outputs": [ + { + "name": "samples", + "type": "LATENT", + "slot_index": 0, + "links": [ + 33 + ] + }, + { + "name": "denoised_samples", + "type": "LATENT", + "links": null + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50", + "Node name for S&R": "WanVideoSampler" + }, + "widgets_values": [ + 4, + 1, + 5, + 44, + "fixed", + true, + "dpm++_sde", + 0, + 1, + "", + "comfy", + 0, + -1, + false + ] + }, + { + "id": 35, + "type": "WanVideoTorchCompileSettings", + "pos": [ + -276.8500671386719, + -1050.6326904296875 + ], + "size": [ + 390.5999755859375, + 202 + ], + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "torch_compile_args", + "type": "WANCOMPILEARGS", + "slot_index": 0, + "links": [ + 211 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50", + "Node name for S&R": "WanVideoTorchCompileSettings" + }, + "widgets_values": [ + "inductor", + false, + "default", + false, + 64, + true, + 128 + ], + "color": "#223", + "bgcolor": "#335" + }, + { + "id": 28, + "type": "WanVideoDecode", + "pos": [ + 1446.94677734375, + -808.8124389648438 + ], + "size": [ + 315, + 198 + ], + "flags": {}, + "order": 30, + "mode": 0, + "inputs": [ + { + "name": "vae", + "type": "WANVAE", + "link": 43 + }, + { + "name": "samples", + "type": "LATENT", + "link": 33 + } + ], + "outputs": [ + { + "name": "images", + "type": "IMAGE", + "slot_index": 0, + "links": [ + 218 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50", + "Node name for S&R": "WanVideoDecode" + }, + "widgets_values": [ + false, + 272, + 272, + 144, + 128, + "default" + ], + "color": "#322", + "bgcolor": "#533" + }, + { + "id": 39, + "type": "WanVideoBlockSwap", + "pos": [ + 709.6087646484375, + -658.9224853515625 + ], + "size": [ + 315, + 202 + ], + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "block_swap_args", + "type": "BLOCKSWAPARGS", + "slot_index": 0, + "links": [ + 92 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50", + "Node name for S&R": "WanVideoBlockSwap" + }, + "widgets_values": [ + 15, + false, + false, + true, + 0, + 1, + false + ], + "color": "#223", + "bgcolor": "#335" + }, + { + "id": 42, + "type": "Note", + "pos": [ + 684.2587890625, + -1059.630615234375 + ], + "size": [ + 325.1150207519531, + 196.76773071289062 + ], + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "Adjust the blocks to swap based on your VRAM, this is a tradeoff between speed and memory usage.\n\nAlternatively there's option to use VRAM management introduced in DiffSynt-Studios. This is usually slower, but saves even more VRAM compared to BlockSwap\n\nFurther VRAM savings are from torch.compile or alternatively using the chunked rope option in the WanVideoSampler -node" + ], + "color": "#432", + "bgcolor": "#653" + }, + { + "id": 79, + "type": "WanVideoSetLoRAs", + "pos": [ + 1133.248291015625, + -698.7440795898438 + ], + "size": [ + 239.93698120117188, + 46 + ], + "flags": {}, + "order": 27, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "WANVIDEOMODEL", + "link": 107 + }, + { + "name": "lora", + "shape": 7, + "type": "WANVIDLORA", + "link": 210 + } + ], + "outputs": [ + { + "name": "model", + "type": "WANVIDEOMODEL", + "links": [ + 108 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "7c93aea182a0d7084bfbc18ae36f039ea3845e73", + "Node name for S&R": "WanVideoSetLoRAs" + }, + "widgets_values": [], + "color": "#223", + "bgcolor": "#335" + }, + { + "id": 122, + "type": "ImageConcatMulti", + "pos": [ + 1837.2718505859375, + -568.9346313476562 + ], + "size": [ + 270, + 150 + ], + "flags": {}, + "order": 31, + "mode": 0, + "inputs": [ + { + "name": "image_1", + "type": "IMAGE", + "link": 218 + }, + { + "name": "image_2", + "type": "IMAGE", + "link": 229 + } + ], + "outputs": [ + { + "name": "images", + "type": "IMAGE", + "links": [ + 217 + ] + } + ], + "properties": { + "cnr_id": "comfyui-kjnodes", + "ver": "87d0cf42db7d59992daba4d58a83655b5b359f44" + }, + "widgets_values": [ + 2, + "left", + true, + null + ] + }, + { + "id": 103, + "type": "WanVideoEmptyEmbeds", + "pos": [ + 622.5388793945312, + 137.8038330078125 + ], + "size": [ + 272.431640625, + 126 + ], + "flags": {}, + "order": 19, + "mode": 0, + "inputs": [ + { + "name": "control_embeds", + "shape": 7, + "type": "WANVIDIMAGE_EMBEDS", + "link": null + }, + { + "name": "extra_latents", + "shape": 7, + "type": "LATENT", + "link": null + }, + { + "name": "width", + "type": "INT", + "widget": { + "name": "width" + }, + "link": 220 + }, + { + "name": "height", + "type": "INT", + "widget": { + "name": "height" + }, + "link": 221 + } + ], + "outputs": [ + { + "name": "image_embeds", + "type": "WANVIDIMAGE_EMBEDS", + "links": [ + 171 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "06863fe2d283e89ba2386260ad2700557dda1897", + "Node name for S&R": "WanVideoEmptyEmbeds" + }, + "widgets_values": [ + 832, + 480, + 81 + ] + }, + { + "id": 123, + "type": "PrimitiveNode", + "pos": [ + -225.1419219970703, + -412.62811279296875 + ], + "size": [ + 210, + 82 + ], + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "INT", + "type": "INT", + "widget": { + "name": "width" + }, + "links": [ + 220 + ] + } + ], + "title": "width", + "properties": { + "Run widget replace on values": false + }, + "widgets_values": [ + 832, + "fixed" + ], + "color": "#2a363b", + "bgcolor": "#3f5159" + }, + { + "id": 124, + "type": "PrimitiveNode", + "pos": [ + -226.0428009033203, + -278.3983154296875 + ], + "size": [ + 210, + 82 + ], + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "INT", + "type": "INT", + "widget": { + "name": "height" + }, + "links": [ + 221 + ] + } + ], + "title": "height", + "properties": { + "Run widget replace on values": false + }, + "widgets_values": [ + 480, + "fixed" + ], + "color": "#2a363b", + "bgcolor": "#3f5159" + }, + { + "id": 104, + "type": "WanVideoEncode", + "pos": [ + 193.28677368164062, + -85.77310180664062 + ], + "size": [ + 270, + 242 + ], + "flags": {}, + "order": 26, + "mode": 0, + "inputs": [ + { + "name": "vae", + "type": "WANVAE", + "link": 175 + }, + { + "name": "image", + "type": "IMAGE", + "link": 228 + }, + { + "name": "mask", + "shape": 7, + "type": "MASK", + "link": null + } + ], + "outputs": [ + { + "name": "samples", + "type": "LATENT", + "links": [ + 174 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "06863fe2d283e89ba2386260ad2700557dda1897", + "Node name for S&R": "WanVideoEncode" + }, + "widgets_values": [ + false, + 272, + 272, + 144, + 128, + 0, + 1 + ] + }, + { + "id": 38, + "type": "WanVideoVAELoader", + "pos": [ + 183.16864013671875, + -261.20465087890625 + ], + "size": [ + 372.7727966308594, + 82 + ], + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "compile_args", + "shape": 7, + "type": "WANCOMPILEARGS", + "link": null + } + ], + "outputs": [ + { + "name": "vae", + "type": "WANVAE", + "slot_index": 0, + "links": [ + 43, + 175 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50", + "Node name for S&R": "WanVideoVAELoader" + }, + "widgets_values": [ + "Wan2.1_VAE.pth", + "bf16" + ], + "color": "#322", + "bgcolor": "#533" + }, + { + "id": 69, + "type": "WanVideoLoraSelect", + "pos": [ + -470.2064208984375, + -736.2723388671875 + ], + "size": [ + 583.5029907226562, + 200 + ], + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "prev_lora", + "shape": 7, + "type": "WANVIDLORA", + "link": null + }, + { + "name": "blocks", + "shape": 7, + "type": "SELECTEDBLOCKS", + "link": null + } + ], + "outputs": [ + { + "name": "lora", + "type": "WANVIDLORA", + "links": [ + 170 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "6b9565ed6307168c45770ec08517d7df65b61e3f", + "Node name for S&R": "WanVideoLoraSelect" + }, + "widgets_values": [ + "Stand-In_wan2.1_T2V_14B_ver1.0.ckpt", + 1, + false, + false + ] + }, + { + "id": 71, + "type": "WanVideoLoraSelect", + "pos": [ + 1039.67724609375, + -1149.5599365234375 + ], + "size": [ + 583.5029907226562, + 176 + ], + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "prev_lora", + "shape": 7, + "type": "WANVIDLORA", + "link": null + }, + { + "name": "blocks", + "shape": 7, + "type": "SELECTEDBLOCKS", + "link": null + } + ], + "outputs": [ + { + "name": "lora", + "type": "WANVIDLORA", + "links": [ + 210 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "6b9565ed6307168c45770ec08517d7df65b61e3f", + "Node name for S&R": "WanVideoLoraSelect" + }, + "widgets_values": [ + "lightx2v_T2V_14B_cfg_step_distill_v2_lora_rank64_bf16.safetensors", + 1, + false, + false + ], + "color": "#223", + "bgcolor": "#335" + }, + { + "id": 102, + "type": "WanVideoAddStandInLatent", + "pos": [ + 515.3641357421875, + -37.543235778808594 + ], + "size": [ + 246.94578552246094, + 57.857322692871094 + ], + "flags": {}, + "order": 28, + "mode": 0, + "inputs": [ + { + "name": "embeds", + "type": "WANVIDIMAGE_EMBEDS", + "link": 171 + }, + { + "name": "ip_image_latent", + "type": "LATENT", + "link": 174 + } + ], + "outputs": [ + { + "name": "image_embeds", + "type": "WANVIDIMAGE_EMBEDS", + "links": [ + 172 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "06863fe2d283e89ba2386260ad2700557dda1897", + "Node name for S&R": "WanVideoAddStandInLatent" + }, + "widgets_values": [] + }, + { + "id": 11, + "type": "LoadWanVideoT5TextEncoder", + "pos": [ + 172.5333709716797, + -444.4674987792969 + ], + "size": [ + 377.1661376953125, + 130 + ], + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "wan_t5_model", + "type": "WANTEXTENCODER", + "slot_index": 0, + "links": [ + 15 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50", + "Node name for S&R": "LoadWanVideoT5TextEncoder" + }, + "widgets_values": [ + "models_t5_umt5-xxl-enc-bf16.pth", + "bf16", + "offload_device", + "disabled" + ], + "color": "#332922", + "bgcolor": "#593930" + }, + { + "id": 22, + "type": "WanVideoModelLoader", + "pos": [ + 150, + -780 + ], + "size": [ + 535.5307006835938, + 274 + ], + "flags": {}, + "order": 20, + "mode": 0, + "inputs": [ + { + "name": "compile_args", + "shape": 7, + "type": "WANCOMPILEARGS", + "link": 211 + }, + { + "name": "block_swap_args", + "shape": 7, + "type": "BLOCKSWAPARGS", + "link": null + }, + { + "name": "lora", + "shape": 7, + "type": "WANVIDLORA", + "link": 170 + }, + { + "name": "vram_management_args", + "shape": 7, + "type": "VRAM_MANAGEMENTARGS", + "link": null + }, + { + "name": "vace_model", + "shape": 7, + "type": "VACEPATH", + "link": null + }, + { + "name": "fantasytalking_model", + "shape": 7, + "type": "FANTASYTALKINGMODEL", + "link": null + }, + { + "name": "multitalk_model", + "shape": 7, + "type": "MULTITALKMODEL", + "link": null + } + ], + "outputs": [ + { + "name": "model", + "type": "WANVIDEOMODEL", + "slot_index": 0, + "links": [ + 79, + 90 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50", + "Node name for S&R": "WanVideoModelLoader" + }, + "widgets_values": [ + "Wan2_1-T2V-14B_fp8_e4m3fn.safetensors", + "fp16_fast", + "fp8_e4m3fn_scaled", + "offload_device", + "sdpa" + ], + "color": "#223", + "bgcolor": "#335" + }, + { + "id": 16, + "type": "WanVideoTextEncode", + "pos": [ + 936.4089965820312, + -35.84267807006836 + ], + "size": [ + 475.7987976074219, + 355.67169189453125 + ], + "flags": {}, + "order": 23, + "mode": 0, + "inputs": [ + { + "name": "t5", + "shape": 7, + "type": "WANTEXTENCODER", + "link": 15 + }, + { + "name": "model_to_offload", + "shape": 7, + "type": "WANVIDEOMODEL", + "link": 79 + } + ], + "outputs": [ + { + "name": "text_embeds", + "type": "WANVIDEOTEXTEMBEDS", + "slot_index": 0, + "links": [ + 30 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50", + "Node name for S&R": "WanVideoTextEncode" + }, + "widgets_values": [ + "一位男性舒适地坐在书桌前,正对着镜头,仿佛在与屏幕前的亲友对话。他的眼神专注而温柔,嘴角带着自然的笑意。背景是他精心布置的个人空间,墙上贴着照片和一张世界地图,传达出一种亲密而现代的沟通感。", + "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走", + true, + false, + "gpu" + ], + "color": "#332922", + "bgcolor": "#593930" + }, + { + "id": 74, + "type": "VHS_VideoCombine", + "pos": [ + 2258.452392578125, + -658.4154663085938 + ], + "size": [ + 959.076171875, + 691.564453125 + ], + "flags": {}, + "order": 32, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 217 + }, + { + "name": "audio", + "shape": 7, + "type": "AUDIO", + "link": null + }, + { + "name": "meta_batch", + "shape": 7, + "type": "VHS_BatchManager", + "link": null + }, + { + "name": "vae", + "shape": 7, + "type": "VAE", + "link": null + } + ], + "outputs": [ + { + "name": "Filenames", + "type": "VHS_FILENAMES", + "links": null + } + ], + "properties": { + "cnr_id": "comfyui-videohelpersuite", + "ver": "0a75c7958fe320efcb052f1d9f8451fd20c730a8", + "Node name for S&R": "VHS_VideoCombine" + }, + "widgets_values": { + "frame_rate": 16, + "loop_count": 0, + "filename_prefix": "WanVideoWrapper_T2V_Stand_In", + "format": "video/h264-mp4", + "pix_fmt": "yuv420p", + "crf": 19, + "save_metadata": true, + "trim_to_audio": false, + "pingpong": false, + "save_output": false, + "videopreview": { + "hidden": false, + "paused": false, + "params": { + "filename": "WanVideoWrapper_T2V_Stand_In_00001.mp4", + "subfolder": "", + "type": "temp", + "format": "video/h264-mp4", + "frame_rate": 16, + "workflow": "WanVideoWrapper_T2V_Stand_In_00001.png", + "fullpath": "/FirstIntelligence/home/bowen/ComfyUI/temp/WanVideoWrapper_T2V_Stand_In_00001.mp4" + } + } + } + }, + { + "id": 46, + "type": "WanVideoTextEmbedBridge", + "pos": [ + 943.1697387695312, + 1096.8651123046875 + ], + "size": [ + 315, + 46 + ], + "flags": { + "collapsed": true + }, + "order": 22, + "mode": 2, + "inputs": [ + { + "name": "positive", + "type": "CONDITIONING", + "link": 54 + }, + { + "name": "negative", + "shape": 7, + "type": "CONDITIONING", + "link": 55 + } + ], + "outputs": [ + { + "name": "text_embeds", + "type": "WANVIDEOTEXTEMBEDS", + "links": null + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50", + "Node name for S&R": "WanVideoTextEmbedBridge" + }, + "widgets_values": [] + }, + { + "id": 128, + "type": "ApplyFaceProcessor", + "pos": [ + -297.2541198730469, + -77.13932037353516 + ], + "size": [ + 270, + 126 + ], + "flags": {}, + "order": 21, + "mode": 0, + "inputs": [ + { + "name": "face_processor", + "type": "FACE_PROCESSOR", + "link": 223 + }, + { + "name": "image", + "type": "IMAGE", + "link": 226 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 227, + 228, + 229 + ] + } + ], + "properties": { + "Node name for S&R": "ApplyFaceProcessor" + }, + "widgets_values": [ + 512, + 10, + 1.5 + ] + }, + { + "id": 127, + "type": "FaceProcessorLoader", + "pos": [ + -294.2811279296875, + 107.27786254882812 + ], + "size": [ + 270, + 58 + ], + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "face_processor", + "type": "FACE_PROCESSOR", + "links": [ + 223 + ] + } + ], + "properties": { + "Node name for S&R": "FaceProcessorLoader" + }, + "widgets_values": [ + "models/insightface" + ] + }, + { + "id": 126, + "type": "MarkdownNote", + "pos": [ + -653.9163818359375, + -382.01556396484375 + ], + "size": [ + 362.6117858886719, + 143.0945281982422 + ], + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "LoRA link:\n\n[https://huggingface.co/BowenXue/Stand-In](https://huggingface.co/BowenXue/Stand-In)\n\nThis LoRA is not the traditional kind and it HAS TO connect to the model loader directly." + ], + "color": "#432", + "bgcolor": "#653" + }, + { + "id": 121, + "type": "PreviewImage", + "pos": [ + 37.458839416503906, + -72.97832489013672 + ], + "size": [ + 140, + 246 + ], + "flags": {}, + "order": 25, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 227 + } + ], + "outputs": [], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.49", + "Node name for S&R": "PreviewImage" + }, + "widgets_values": [] + }, + { + "id": 58, + "type": "LoadImage", + "pos": [ + -737.1319580078125, + -174.04302978515625 + ], + "size": [ + 413.10479736328125, + 498.3180847167969 + ], + "flags": {}, + "order": 15, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 226 + ] + }, + { + "name": "MASK", + "type": "MASK", + "links": [] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.26", + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "clipspace/clipspace-mask-379138.7999999998.png [input]", + "image" + ], + "color": "#2a363b", + "bgcolor": "#3f5159" + }, + { + "id": 129, + "type": "MarkdownNote", + "pos": [ + 791.3861694335938, + -356.8863830566406 + ], + "size": [ + 362.6117858886719, + 143.0945281982422 + ], + "flags": {}, + "order": 16, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "Prompt Writing Tip: If you do not wish to alter the subject's facial features, simply use \"a man\" or \"a woman\" without adding extra descriptions of their appearance. Prompts support both Chinese and English input. The prompt is intended for generating frontal, medium-to-close-up videos.\n\nInput Image Recommendation: For best results, use a high-resolution frontal face image. There are no restrictions on resolution or file extension, as our built-in preprocessing pipeline will handle them automatically.\n\n[https://github.com/WeChatCV/Stand-In](https://github.com/WeChatCV/Stand-In)" + ], + "color": "#322", + "bgcolor": "#533" + } + ], + "links": [ + [ + 15, + 11, + 0, + 16, + 0, + "WANTEXTENCODER" + ], + [ + 30, + 16, + 0, + 27, + 2, + "WANVIDEOTEXTEMBEDS" + ], + [ + 33, + 27, + 0, + 28, + 1, + "LATENT" + ], + [ + 43, + 38, + 0, + 28, + 0, + "VAE" + ], + [ + 52, + 48, + 0, + 49, + 0, + "CLIP" + ], + [ + 53, + 48, + 0, + 50, + 0, + "CLIP" + ], + [ + 54, + 49, + 0, + 46, + 0, + "CONDITIONING" + ], + [ + 55, + 50, + 0, + 46, + 1, + "CONDITIONING" + ], + [ + 79, + 22, + 0, + 16, + 1, + "WANVIDEOMODEL" + ], + [ + 90, + 22, + 0, + 70, + 0, + "WANVIDEOMODEL" + ], + [ + 92, + 39, + 0, + 70, + 1, + "BLOCKSWAPARGS" + ], + [ + 107, + 70, + 0, + 79, + 0, + "WANVIDEOMODEL" + ], + [ + 108, + 79, + 0, + 27, + 0, + "WANVIDEOMODEL" + ], + [ + 170, + 69, + 0, + 22, + 2, + "WANVIDLORA" + ], + [ + 171, + 103, + 0, + 102, + 0, + "WANVIDIMAGE_EMBEDS" + ], + [ + 172, + 102, + 0, + 27, + 1, + "WANVIDIMAGE_EMBEDS" + ], + [ + 174, + 104, + 0, + 102, + 1, + "LATENT" + ], + [ + 175, + 38, + 0, + 104, + 0, + "WANVAE" + ], + [ + 210, + 71, + 0, + 79, + 1, + "WANVIDLORA" + ], + [ + 211, + 35, + 0, + 22, + 0, + "WANCOMPILEARGS" + ], + [ + 217, + 122, + 0, + 74, + 0, + "IMAGE" + ], + [ + 218, + 28, + 0, + 122, + 0, + "IMAGE" + ], + [ + 220, + 123, + 0, + 103, + 2, + "INT" + ], + [ + 221, + 124, + 0, + 103, + 3, + "INT" + ], + [ + 223, + 127, + 0, + 128, + 0, + "FACE_PROCESSOR" + ], + [ + 226, + 58, + 0, + 128, + 1, + "IMAGE" + ], + [ + 227, + 128, + 0, + 121, + 0, + "IMAGE" + ], + [ + 228, + 128, + 0, + 104, + 1, + "IMAGE" + ], + [ + 229, + 128, + 0, + 122, + 1, + "IMAGE" + ] + ], + "groups": [ + { + "id": 1, + "title": "ComfyUI text encoding alternative", + "bounding": [ + 70.3548812866211, + 792.9315185546875, + 1210.621337890625, + 805.9080810546875 + ], + "color": "#3f789e", + "font_size": 24, + "flags": {} + } + ], + "config": {}, + "extra": { + "ds": { + "scale": 0.6727499949326107, + "offset": [ + 1220.5620388990717, + 479.6860694347906 + ] + }, + "frontendVersion": "1.24.4", + "node_versions": { + "ComfyUI-WanVideoWrapper": "5a2383621a05825d0d0437781afcb8552d9590fd", + "comfy-core": "0.3.26", + "ComfyUI-KJNodes": "a5bd3c86c8ed6b83c55c2d0e7a59515b15a0137f", + "ComfyUI-VideoHelperSuite": "0a75c7958fe320efcb052f1d9f8451fd20c730a8" + }, + "VHS_latentpreview": false, + "VHS_latentpreviewrate": 0, + "VHS_MetadataImage": true, + "VHS_KeepIntermediate": true + }, + "version": 0.4 +} \ No newline at end of file