first commit
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
__pycache__
|
||||
.DS_Store
|
||||
*.cache
|
||||
*.ini
|
||||
*.bak
|
||||
.vscode/
|
||||
.idea/
|
||||
uni/
|
||||
custom_presets/**
|
||||
workflows/**
|
||||
node.tar.gz
|
||||
py/
|
||||
front/
|
||||
prompts/
|
||||
web/dev/**
|
||||
web/stable/**
|
||||
web/wass/**
|
||||
dist/
|
||||
.pyarmor/
|
||||
config.yaml
|
||||
*.bat
|
||||
*.log
|
||||
*.bak
|
||||
build_cloud.sh
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
Enhanced the comfyui savevideo node to support previewing and saving videos containing alpha channels.
|
||||
|
||||
<img width="100%" height="auto" alt="Image" src="https://github-production-user-asset-6210df.s3.amazonaws.com/73304135/497659951-46496759-daf4-4749-9644-b7e795560a69.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVCODYLSA53PQK4ZA%2F20251006%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20251006T061801Z&X-Amz-Expires=300&X-Amz-Signature=69ccad19ceb69edb1d89359b0cdf9c5717c546a4abd3c1f1b90e40f61259686c&X-Amz-SignedHeaders=host" />
|
||||
|
||||
### 🔨Wan-Alpha Video Usage
|
||||
|
||||
1. Download models
|
||||
- The Wan DiT base model: [wan2.1_t2v_14B_fp16.safetensors](https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/blob/main/split_files/diffusion_models/wan2.1_t2v_14B_fp16.safetensors)
|
||||
- The Wan text encoder: [umt5_xxl_fp8_e4m3fn_scaled.safetensors](https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/blob/main/split_files/text_encoders/umt5_xxl_fp8_e4m3fn_scaled.safetensors)
|
||||
- The LightX2V model: [lightx2v_T2V_14B_cfg_step_distill_v2_lora_rank64_bf16.safetensors](https://huggingface.co/Kijai/WanVideo_comfy/blob/main/Lightx2v/lightx2v_T2V_14B_cfg_step_distill_v2_lora_rank64_bf16.safetensors)
|
||||
- RGBA Dora: [epoch-13-1500_changed.safetensors](https://huggingface.co/htdong/Wan-Alpha_ComfyUI/blob/main/epoch-13-1500_changed.safetensors)
|
||||
- RGB VAE Decoder: [wan_alpha_2.1_vae_rgb_channel.safetensors.safetensors](https://huggingface.co/htdong/Wan-Alpha_ComfyUI/blob/main/wan_alpha_2.1_vae_rgb_channel.safetensors.safetensors)
|
||||
- Alpha VAE Decoder: [wan_alpha_2.1_vae_alpha_channel.safetensors.safetensors](https://huggingface.co/htdong/Wan-Alpha_ComfyUI/blob/main/wan_alpha_2.1_vae_alpha_channel.safetensors.safetensors)
|
||||
|
||||
2. Copy the files into the `ComfyUI/models` folder and organize them as follows:
|
||||
|
||||
```
|
||||
ComfyUI/models
|
||||
├── diffusion_models
|
||||
│ └── wan2.1_t2v_14B_fp16.safetensors
|
||||
├── loras
|
||||
│ ├── epoch-13-1500_changed.safetensors
|
||||
│ └── lightx2v_T2V_14B_cfg_step_distill_v2_lora_rank64_bf16.safetensors
|
||||
├── text_encoders
|
||||
│ └── umt5_xxl_fp8_e4m3fn_scaled.safetensors
|
||||
├── vae
|
||||
│ ├── wan_alpha_2.1_vae_alpha_channel.safetensors.safetensors
|
||||
│ └── wan_alpha_2.1_vae_rgb_channel.safetensors.safetensors
|
||||
```
|
||||
|
||||
3. Copy this repo or [SaveVideoRGBA.py](SaveVideoRGBA.py) into the `ComfyUI/custom_nodes` folder.
|
||||
|
||||
|
||||
## 🤝 Acknowledgements
|
||||
|
||||
- [Wan-Alpha](https://github.com/WeChatCV/Wan-Alpha) for the alpha video generate
|
||||
- [ComfyUI](https://github.com/comfyanonymous/ComfyUI) for the node workflow framework
|
||||
@@ -0,0 +1,287 @@
|
||||
from __future__ import annotations
|
||||
from typing_extensions import override
|
||||
from typing import Optional
|
||||
from fractions import Fraction
|
||||
from enum import Enum
|
||||
import io
|
||||
import json
|
||||
import math
|
||||
import av
|
||||
import os
|
||||
import random
|
||||
import folder_paths
|
||||
from comfy_api.latest._input import AudioInput, VideoInput
|
||||
from comfy_api.latest import ComfyExtension, io, ui
|
||||
from comfy_api.util import VideoComponents
|
||||
|
||||
class SaveVideoRGBA(io.ComfyNode):
|
||||
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
return io.Schema(
|
||||
node_id="SaveVideoRGBA",
|
||||
display_name="Save Video (RGBA)",
|
||||
category="image/animation",
|
||||
inputs=[
|
||||
io.Image.Input("images"),
|
||||
io.Float.Input("fps", default=24.0, min=1.0, max=120.0, step=1.0),
|
||||
io.String.Input("filename_prefix", default="video/ComfyUI", tooltip="The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes."),
|
||||
io.Boolean.Input("only_preview", default=False),
|
||||
io.Audio.Input("audio", optional=True),
|
||||
],
|
||||
outputs=[
|
||||
# io.Video.Output("VIDEO")
|
||||
],
|
||||
hidden=[io.Hidden.unique_id],
|
||||
is_output_node=True
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(self, images, fps, filename_prefix, only_preview, audio=None, **kwargs):
|
||||
|
||||
B, H, W, C = images.shape
|
||||
has_alpha = C == 4
|
||||
|
||||
video = RGBAVideoFromComponents(
|
||||
VideoComponents(
|
||||
images=images,
|
||||
audio=audio,
|
||||
frame_rate=Fraction(fps),
|
||||
)
|
||||
)
|
||||
|
||||
width, height = video.get_dimensions()
|
||||
results = list()
|
||||
|
||||
# 预览
|
||||
if only_preview or has_alpha:
|
||||
output_dir = folder_paths.get_temp_directory()
|
||||
prefix_append = "ComfyUI_temp_" + ''.join(random.choice("abcdefghijklmnopqrstupvxyz") for x in range(5))
|
||||
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(
|
||||
prefix_append,
|
||||
output_dir,
|
||||
width,
|
||||
height
|
||||
)
|
||||
format = 'webm' if has_alpha else 'auto'
|
||||
file = f"{filename}_{counter:05}_.{RGBAVideoContainer.get_extension(format)}"
|
||||
video.save_to(
|
||||
path=os.path.join(full_output_folder, file),
|
||||
format=format,
|
||||
codec='auto',
|
||||
metadata=None,
|
||||
)
|
||||
|
||||
results.append(ui.SavedResult(file, subfolder, io.FolderType.temp))
|
||||
counter += 1
|
||||
|
||||
# 保存
|
||||
if not only_preview:
|
||||
output_dir = folder_paths.get_output_directory()
|
||||
|
||||
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(
|
||||
filename_prefix,
|
||||
output_dir,
|
||||
width,
|
||||
height
|
||||
)
|
||||
format = 'mov' if has_alpha else 'auto'
|
||||
codec = 'prores_ks' if has_alpha else 'auto'
|
||||
file = f"{filename}_{counter:05}_.{RGBAVideoContainer.get_extension(format)}"
|
||||
video.save_to(
|
||||
path=os.path.join(full_output_folder, file),
|
||||
format=format,
|
||||
codec=codec,
|
||||
metadata=None,
|
||||
)
|
||||
|
||||
if not has_alpha:
|
||||
results.append(ui.SavedResult(file, subfolder, io.FolderType.output))
|
||||
counter += 1
|
||||
|
||||
return io.NodeOutput(ui=ui.PreviewVideo(results))
|
||||
|
||||
class NodeExtension(ComfyExtension):
|
||||
@override
|
||||
async def get_node_list(self) -> list[type[io.ComfyNode]]:
|
||||
return [
|
||||
SaveVideoRGBA
|
||||
]
|
||||
|
||||
async def comfy_entrypoint() -> NodeExtension:
|
||||
return NodeExtension()
|
||||
|
||||
|
||||
|
||||
class RGBAVideoCodec(str, Enum):
|
||||
AUTO = "auto"
|
||||
H264 = "h264" # H.264 codec, no alpha channel
|
||||
VP9 = "libvpx-vp9" # VP9 codec, supports alpha channel
|
||||
PRORES = "prores_ks" # ProRes 4444, supports alpha channel
|
||||
|
||||
@classmethod
|
||||
def as_input(cls) -> list[str]:
|
||||
"""
|
||||
Returns a list of codec names that can be used as node input.
|
||||
"""
|
||||
return [member.value for member in cls]
|
||||
|
||||
class RGBAVideoContainer(str, Enum):
|
||||
AUTO = "auto"
|
||||
MP4 = "mp4" # MP4 container
|
||||
WEBM = "webm" # WebM container, supports VP9 with alpha channel
|
||||
MOV = "mov" # QuickTime MOV, supports ProRes with alpha channel
|
||||
|
||||
@classmethod
|
||||
def as_input(cls) -> list[str]:
|
||||
"""
|
||||
Returns a list of codec names that can be used as node input.
|
||||
"""
|
||||
return [member.value for member in cls]
|
||||
|
||||
@classmethod
|
||||
def get_extension(cls, value) -> str:
|
||||
"""
|
||||
Returns the file extension for the container.
|
||||
"""
|
||||
if isinstance(value, str):
|
||||
value = cls(value)
|
||||
if value == RGBAVideoContainer.AUTO:
|
||||
return "mp4"
|
||||
elif value == RGBAVideoContainer.MP4:
|
||||
return "mp4"
|
||||
elif value == RGBAVideoContainer.WEBM:
|
||||
return "webm"
|
||||
elif value == RGBAVideoContainer.MOV:
|
||||
return "mov"
|
||||
return ""
|
||||
|
||||
class RGBAVideoFromComponents(VideoInput):
|
||||
|
||||
def __init__(self, components: VideoComponents):
|
||||
self.__components = components
|
||||
|
||||
def get_components(self) -> VideoComponents:
|
||||
return VideoComponents(
|
||||
images=self.__components.images,
|
||||
audio=self.__components.audio,
|
||||
frame_rate=self.__components.frame_rate
|
||||
)
|
||||
|
||||
def save_to(
|
||||
self,
|
||||
path: str,
|
||||
format: RGBAVideoContainer = RGBAVideoContainer.AUTO,
|
||||
codec: RGBAVideoCodec = RGBAVideoCodec.AUTO,
|
||||
metadata: Optional[dict] = None
|
||||
):
|
||||
# Check if images have alpha channel (4 channels)
|
||||
has_alpha = self.__components.images.shape[-1] == 4 if len(self.__components.images.shape) == 4 else False
|
||||
|
||||
# Determine format and codec based on alpha channel
|
||||
if has_alpha:
|
||||
# For alpha channel support, use webm container with vp9 codec
|
||||
if format == RGBAVideoContainer.AUTO:
|
||||
format = RGBAVideoContainer.WEBM.value
|
||||
if codec == RGBAVideoCodec.AUTO:
|
||||
codec = RGBAVideoCodec.VP9.value
|
||||
# Ensure format is string for comparison
|
||||
format_str = format.value if isinstance(format, RGBAVideoContainer) else format
|
||||
codec_str = codec.value if isinstance(codec, RGBAVideoCodec) else codec
|
||||
if format_str not in ['webm', 'mov']:
|
||||
raise ValueError("Only WEBM and MOV formats support alpha channel")
|
||||
else:
|
||||
# Ensure format and codec are strings for comparison
|
||||
format_str = format.value if isinstance(format, RGBAVideoContainer) else format
|
||||
codec_str = codec.value if isinstance(codec, RGBAVideoCodec) else codec
|
||||
if format != RGBAVideoContainer.AUTO and format_str not in ['mp4', 'webm', 'mov']:
|
||||
raise ValueError("Supported formats: MP4, WEBM, MOV")
|
||||
if codec != RGBAVideoCodec.AUTO and codec_str not in ['h264', 'libvpx-vp9', 'prores_ks']:
|
||||
raise ValueError("Supported codecs: H264, VP9, ProRes")
|
||||
|
||||
# Set default codec if AUTO
|
||||
if codec == RGBAVideoCodec.AUTO:
|
||||
codec = RGBAVideoCodec.H264.value
|
||||
codec_str = codec
|
||||
|
||||
# Ensure codec_str is defined
|
||||
if 'codec_str' not in locals():
|
||||
codec_str = codec.value if isinstance(codec, RGBAVideoCodec) else codec
|
||||
|
||||
# Prepare options based on format
|
||||
options = {}
|
||||
if format_str in ['mp4', 'mov']:
|
||||
options['movflags'] = 'use_metadata_tags'
|
||||
|
||||
# Determine the format string for av.open
|
||||
output_format = None if format == RGBAVideoContainer.AUTO else format_str
|
||||
|
||||
with av.open(path, mode='w', format=output_format, options=options) as output:
|
||||
# Add metadata before writing any streams
|
||||
if metadata is not None:
|
||||
for key, value in metadata.items():
|
||||
output.metadata[key] = json.dumps(value)
|
||||
|
||||
frame_rate = Fraction(round(self.__components.frame_rate * 1000), 1000)
|
||||
|
||||
# Create a video stream
|
||||
video_stream = output.add_stream(codec_str, rate=frame_rate)
|
||||
video_stream.width = self.__components.images.shape[2]
|
||||
video_stream.height = self.__components.images.shape[1]
|
||||
|
||||
# Set pixel format based on codec and alpha channel
|
||||
if has_alpha:
|
||||
if codec_str in ['libvpx-vp9']:
|
||||
video_stream.pix_fmt = 'yuva420p' # VP9 with alpha
|
||||
elif codec_str in ['prores_ks']:
|
||||
video_stream.pix_fmt = 'yuva444p10le' # ProRes 4444
|
||||
else:
|
||||
video_stream.pix_fmt = 'yuva420p' # Default alpha format
|
||||
else:
|
||||
if codec_str in ['h264']:
|
||||
video_stream.pix_fmt = 'yuv420p'
|
||||
elif codec_str in ['libvpx-vp9']:
|
||||
video_stream.pix_fmt = 'yuv420p'
|
||||
else:
|
||||
video_stream.pix_fmt = 'yuv420p'
|
||||
|
||||
# Create an audio stream
|
||||
audio_sample_rate = 1
|
||||
audio_stream: Optional[av.AudioStream] = None
|
||||
if self.__components.audio:
|
||||
audio_sample_rate = int(self.__components.audio['sample_rate'])
|
||||
audio_codec = 'libopus' if format_str == 'webm' else 'aac'
|
||||
audio_stream = output.add_stream(audio_codec, rate=audio_sample_rate)
|
||||
|
||||
# Encode video
|
||||
for i, frame in enumerate(self.__components.images):
|
||||
img = (frame * 255).clamp(0, 255).byte().cpu().numpy()
|
||||
|
||||
if has_alpha:
|
||||
# Create frame with alpha channel (H, W, 4)
|
||||
frame = av.VideoFrame.from_ndarray(img, format='rgba')
|
||||
frame = frame.reformat(format=video_stream.pix_fmt)
|
||||
else:
|
||||
# Create frame without alpha channel (H, W, 3)
|
||||
frame = av.VideoFrame.from_ndarray(img, format='rgb24')
|
||||
frame = frame.reformat(format=video_stream.pix_fmt)
|
||||
|
||||
packet = video_stream.encode(frame)
|
||||
output.mux(packet)
|
||||
|
||||
# Flush video
|
||||
packet = video_stream.encode(None)
|
||||
output.mux(packet)
|
||||
|
||||
if audio_stream and self.__components.audio:
|
||||
waveform = self.__components.audio['waveform']
|
||||
waveform = waveform[:, :,
|
||||
:math.ceil((audio_sample_rate / frame_rate) * self.__components.images.shape[0])]
|
||||
frame = av.AudioFrame.from_ndarray(waveform.movedim(2, 1).reshape(1, -1).float().numpy(), format='flt',
|
||||
layout='mono' if waveform.shape[1] == 1 else 'stereo')
|
||||
frame.sample_rate = audio_sample_rate
|
||||
frame.pts = 0
|
||||
output.mux(audio_stream.encode(frame))
|
||||
|
||||
# Flush encoder
|
||||
output.mux(audio_stream.encode(None))
|
||||
@@ -0,0 +1 @@
|
||||
from .SaveVideoRGBA import *
|
||||
@@ -0,0 +1,833 @@
|
||||
{
|
||||
"id": "c265fdcc-11cd-4a1d-9a0d-bc37c45667d6",
|
||||
"revision": 0,
|
||||
"last_node_id": 79,
|
||||
"last_link_id": 164,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 38,
|
||||
"type": "CLIPLoader",
|
||||
"pos": [
|
||||
-117.83563995361328,
|
||||
294.0386047363281
|
||||
],
|
||||
"size": [
|
||||
390,
|
||||
106
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
117,
|
||||
118
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Load Text Encoder",
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPLoader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"umt5_xxl_fp8_e4m3fn_scaled.safetensors",
|
||||
"wan",
|
||||
"default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 40,
|
||||
"type": "EmptyHunyuanLatentVideo",
|
||||
"pos": [
|
||||
463.4875793457031,
|
||||
657.9263305664062
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
130
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
91
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyHunyuanLatentVideo"
|
||||
},
|
||||
"widgets_values": [
|
||||
832,
|
||||
480,
|
||||
33,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
863,
|
||||
187
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
262
|
||||
],
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 95
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 46
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 52
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 91
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
35,
|
||||
108
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
129212191626761,
|
||||
"randomize",
|
||||
4,
|
||||
1,
|
||||
"uni_pc",
|
||||
"simple",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 48,
|
||||
"type": "ModelSamplingSD3",
|
||||
"pos": [
|
||||
572.943359375,
|
||||
51.24325180053711
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 144
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
95
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "ModelSamplingSD3"
|
||||
},
|
||||
"widgets_values": [
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
365.5584411621094,
|
||||
198.10687255859375
|
||||
],
|
||||
"size": [
|
||||
422.84503173828125,
|
||||
164.31304931640625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 118
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
46
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "CLIP Text Encode (Positive Prompt)",
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"Medium shot. A little girl holds a bubble wand and blows out colorful bubbles that float and pop in the air. The background of this video is transparent. Realistic style."
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 51,
|
||||
"type": "VAELoader",
|
||||
"pos": [
|
||||
867.8726196289062,
|
||||
522.9005126953125
|
||||
],
|
||||
"size": [
|
||||
306.36004638671875,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
107
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAELoader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"wan_alpha_2.1_vae_alpha_channel.safetensors.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 39,
|
||||
"type": "VAELoader",
|
||||
"pos": [
|
||||
873.0031127929688,
|
||||
51.24325180053711
|
||||
],
|
||||
"size": [
|
||||
306.36004638671875,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
76
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAELoader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"wan_alpha_2.1_vae_rgb_channel.safetensors.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 37,
|
||||
"type": "UNETLoader",
|
||||
"pos": [
|
||||
-415.37969970703125,
|
||||
51.24325180053711
|
||||
],
|
||||
"size": [
|
||||
346.7470703125,
|
||||
82
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
142
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Load Wan 2.1 t2v 14B",
|
||||
"properties": {
|
||||
"Node name for S&R": "UNETLoader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"wan2.1_t2v_14B_fp16.safetensors",
|
||||
"default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 65,
|
||||
"type": "LoraLoaderModelOnly",
|
||||
"pos": [
|
||||
267.7607421875,
|
||||
51.24325180053711
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
82
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 143
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
144
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoraLoaderModelOnly"
|
||||
},
|
||||
"widgets_values": [
|
||||
"epoch-13-1500_changed.safetensors",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 59,
|
||||
"type": "LoraLoaderModelOnly",
|
||||
"pos": [
|
||||
-38.43362045288086,
|
||||
51.24325180053711
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
82
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 142
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
143
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoraLoaderModelOnly"
|
||||
},
|
||||
"widgets_values": [
|
||||
"lightx2v_T2V_14B_cfg_step_distill_v2_lora_rank64_bf16.safetensors",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
359.2072448730469,
|
||||
406.81744384765625
|
||||
],
|
||||
"size": [
|
||||
425.27801513671875,
|
||||
180.6060791015625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 117
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
52
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "CLIP Text Encode (Negative Prompt) Useless s",
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
""
|
||||
],
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 52,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1220.6512451171875,
|
||||
530.7353515625
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 12,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 108
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 107
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
163
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Alpha VAE Decode",
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1220.984130859375,
|
||||
51.24325180053711
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 11,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 35
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 76
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"slot_index": 0,
|
||||
"links": [
|
||||
164
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "RGB VAE Decode",
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 74,
|
||||
"type": "JoinImageWithAlpha",
|
||||
"pos": [
|
||||
1464.0049568109648,
|
||||
205.78294262667404
|
||||
],
|
||||
"size": [
|
||||
180.52341319729067,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 15,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 164
|
||||
},
|
||||
{
|
||||
"name": "alpha",
|
||||
"type": "MASK",
|
||||
"link": 158
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
162
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "JoinImageWithAlpha"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 75,
|
||||
"type": "InvertMask",
|
||||
"pos": [
|
||||
1488,
|
||||
374.66456757897765
|
||||
],
|
||||
"size": [
|
||||
140,
|
||||
26
|
||||
],
|
||||
"flags": {},
|
||||
"order": 14,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 159
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
158
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "InvertMask"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 76,
|
||||
"type": "ImageToMask",
|
||||
"pos": [
|
||||
1465.4226047466786,
|
||||
482.26601727075456
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 13,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 163
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
159
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "ImageToMask"
|
||||
},
|
||||
"widgets_values": [
|
||||
"red"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 79,
|
||||
"type": "SaveVideoRGBA",
|
||||
"pos": [
|
||||
1720.5411964998127,
|
||||
51.24325180053711
|
||||
],
|
||||
"size": [
|
||||
441.01432163205754,
|
||||
896.260567585984
|
||||
],
|
||||
"flags": {},
|
||||
"order": 16,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 162
|
||||
},
|
||||
{
|
||||
"name": "audio",
|
||||
"shape": 7,
|
||||
"type": "AUDIO",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VIDEO",
|
||||
"type": "VIDEO",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SaveVideoRGBA"
|
||||
},
|
||||
"widgets_values": [
|
||||
24,
|
||||
"video/ComfyUI",
|
||||
false
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
35,
|
||||
3,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
46,
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
52,
|
||||
7,
|
||||
0,
|
||||
3,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
76,
|
||||
39,
|
||||
0,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
91,
|
||||
40,
|
||||
0,
|
||||
3,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
95,
|
||||
48,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
107,
|
||||
51,
|
||||
0,
|
||||
52,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
108,
|
||||
3,
|
||||
0,
|
||||
52,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
117,
|
||||
38,
|
||||
0,
|
||||
7,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
118,
|
||||
38,
|
||||
0,
|
||||
6,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
142,
|
||||
37,
|
||||
0,
|
||||
59,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
143,
|
||||
59,
|
||||
0,
|
||||
65,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
144,
|
||||
65,
|
||||
0,
|
||||
48,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
158,
|
||||
75,
|
||||
0,
|
||||
74,
|
||||
1,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
159,
|
||||
76,
|
||||
0,
|
||||
75,
|
||||
0,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
162,
|
||||
74,
|
||||
0,
|
||||
79,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
163,
|
||||
52,
|
||||
0,
|
||||
76,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
164,
|
||||
8,
|
||||
0,
|
||||
74,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.5949345628810089,
|
||||
"offset": [
|
||||
657.1153588041857,
|
||||
464.13758186017674
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.28.6",
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0,
|
||||
"VHS_MetadataImage": true,
|
||||
"VHS_KeepIntermediate": true
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
Reference in New Issue
Block a user