Compare commits

..
Author SHA1 Message Date
bennykok 2cfdd0b3f5 chore: add log 2024-08-28 19:29:22 -07:00
bennykok 9c06cc666c fix node meta 2024-08-25 09:32:11 -07:00
bennykok 710917d507 fix: remove content length 2024-08-24 23:59:40 -07:00
bennykok 16f4312c9e fix: upload file acl 2024-08-24 23:13:33 -07:00
bennykok 20801f4d3f fix: include upload time 2024-08-24 20:25:55 -07:00
bennykok ba2f942b29 fix: log file error log 2024-08-24 17:52:24 -07:00
bennykok 0dfa83f486 Merge branch 'public-main' into benny/upload-test 2024-08-24 17:38:50 -07:00
bennykok 5954092f25 fix: size 2024-08-22 11:48:47 -07:00
bennykok a2990ca833 chore: log more test for upload file debug 2024-08-21 22:29:55 -07:00
bennykok d673c4a00b fix 2024-08-21 21:43:29 -07:00
52 changed files with 962 additions and 9193 deletions
+2 -6
View File
@@ -7,19 +7,15 @@ on:
paths:
- "pyproject.toml"
permissions:
issues: write
jobs:
publish-node:
name: Publish Custom Node to registry
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'BennyKok' }}
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Publish Custom Node
uses: Comfy-Org/publish-node-action@v1
uses: Comfy-Org/publish-node-action@main
with:
## Add your own personal access token to your Github Repository secrets and reference it here.
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
+1 -2
View File
@@ -1,3 +1,2 @@
__pycache__
.DS_Store
file-hash-cache.json
.DS_Store
+4 -3
View File
@@ -2,9 +2,6 @@
Open source comfyui deployment platform, a `vercel` for generative workflow infra. (serverless hosted gpu with vertical intergation with comfyui)
> [!NOTE]
> Im looking for creative hacker to join ComfyDeploy's core team! DM me on [twitter](https://x.com/BennyKokMusic)
Join [Discord](https://discord.gg/EEYcQmdYZw) to chat more or visit [Comfy Deploy](https://comfydeploy.com/) to get started!
Check out our latest [nextjs starter kit](https://github.com/BennyKok/comfyui-deploy-next-example) with Comfy Deploy
@@ -96,6 +93,10 @@ Major areas
# Self Hosting with Vercel
[![Video](https://img.mytsi.org/i/nFOG479.png)](https://www.youtube.com/watch?v=hWvsEY1cS2M)
Tutorial Created by [Ross](https://github.com/rossman22590) and [Syn](https://github.com/mortlsyn)
Build command
```
+1 -37
View File
@@ -2,9 +2,8 @@
@author: BennyKok
@title: comfyui-deploy
@nickname: Comfy Deploy
@description:
@description:
"""
import os
import sys
@@ -18,23 +17,19 @@ import requests
import folder_paths
from folder_paths import add_model_folder_path, get_filename_list, get_folder_paths
from tqdm import tqdm
import re
from . import custom_routes
# import routes
ag_path = os.path.join(os.path.dirname(__file__))
def get_python_files(path):
return [f[:-3] for f in os.listdir(path) if f.endswith(".py")]
def append_to_sys_path(path):
if path not in sys.path:
sys.path.append(path)
paths = ["comfy-nodes"]
files = []
@@ -46,45 +41,14 @@ for path in paths:
NODE_CLASS_MAPPINGS = {}
NODE_DISPLAY_NAME_MAPPINGS = {}
def split_camel_case(name):
# Split on underscores first, then split each part on camelCase
parts = []
for part in name.split("_"):
# Find all camelCase boundaries
words = re.findall("[A-Z][^A-Z]*", part)
if not words: # If no camelCase found, use the whole part
words = [part]
parts.extend(words)
return parts
# Import all the modules and append their mappings
for file in files:
module = importlib.import_module(file)
# Check if the module has explicit mappings
if hasattr(module, "NODE_CLASS_MAPPINGS"):
NODE_CLASS_MAPPINGS.update(module.NODE_CLASS_MAPPINGS)
if hasattr(module, "NODE_DISPLAY_NAME_MAPPINGS"):
NODE_DISPLAY_NAME_MAPPINGS.update(module.NODE_DISPLAY_NAME_MAPPINGS)
# Auto-discover classes with ComfyUI node attributes
for name, obj in inspect.getmembers(module):
# Check if it's a class and has the required ComfyUI node attributes
if (
inspect.isclass(obj)
and hasattr(obj, "INPUT_TYPES")
and hasattr(obj, "RETURN_TYPES")
):
# Use the class name as the key if not already in mappings
if name not in NODE_CLASS_MAPPINGS:
NODE_CLASS_MAPPINGS[name] = obj
# Create a display name by converting camelCase to Title Case with spaces
words = split_camel_case(name.replace("ComfyUIDeploy", ""))
display_name = " ".join(word.capitalize() for word in words)
# print(display_name, name)
NODE_DISPLAY_NAME_MAPPINGS[name] = display_name
WEB_DIRECTORY = "web-plugin"
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
-82
View File
@@ -1,82 +0,0 @@
import io
from folder_paths import get_annotated_filepath
class ComfyUIDeployExternalAudio:
RETURN_TYPES = ("AUDIO",)
RETURN_NAMES = ("audio",)
FUNCTION = "load_audio"
CATEGORY = "🔗ComfyDeploy"
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_audio"},
),
"audio_file": ("STRING", {"default": ""}),
},
"optional": {
"default_value": ("AUDIO",),
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{"multiline": False, "default": ""},
),
},
}
@classmethod
def VALIDATE_INPUTS(s, audio_file, **kwargs):
return True
def load_audio(
self,
input_id,
audio_file,
default_value=None,
display_name=None,
description=None,
):
try:
import torchaudio
if audio_file and audio_file != "":
if audio_file.startswith(("http://", "https://")):
# Handle URL input
try:
import requests
response = requests.get(audio_file)
audio_data = io.BytesIO(response.content)
waveform, sample_rate = torchaudio.load(audio_data)
except Exception as e:
print(f"Error loading audio from URL: {e}")
return (default_value,)
else:
# Handle local file
try:
audio_path = get_annotated_filepath(audio_file)
waveform, sample_rate = torchaudio.load(audio_path)
except Exception as e:
print(f"Error loading local audio file: {e}")
return (default_value,)
audio = {"waveform": waveform.unsqueeze(0), "sample_rate": sample_rate}
return (audio,)
else:
return (default_value,)
except ImportError as e:
print(f"Error: torchaudio not installed or cannot be imported: {e}")
return (default_value,)
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalAudio": ComfyUIDeployExternalAudio}
NODE_DISPLAY_NAME_MAPPINGS = {
"ComfyUIDeployExternalAudio": "External Audio (ComfyUI Deploy)"
}
+1 -2
View File
@@ -23,9 +23,8 @@ class ComfyUIDeployExternalBoolean:
RETURN_TYPES = ("BOOLEAN",)
RETURN_NAMES = ("bool_value",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
def run(self, input_id, default_value=None, display_name=None, description=None):
print(f"Node '{input_id}' processing with switch set to {default_value}")
+1 -2
View File
@@ -36,11 +36,10 @@ class ComfyUIDeployExternalCheckpoint:
RETURN_TYPES = (WILDCARD,)
RETURN_NAMES = ("path",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
CATEGORY = "deploy"
def run(self, input_id, default_value=None, display_name=None, description=None):
import requests
-46
View File
@@ -1,46 +0,0 @@
class AnyType(str):
def __ne__(self, __value: object) -> bool:
return False
WILDCARD = AnyType("*")
class ComfyUIDeployExternalEnum:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_enum"},
),
},
"optional": {
"default_value": (
"STRING",
{"multiline": False, "default": "", "dynamic_enum": True},
),
"options": (
"STRING",
{"multiline": True, "default": ""},
),
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{"multiline": True, "default": ""},
),
}
}
RETURN_TYPES = (WILDCARD,)
RETURN_NAMES = ("text",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
def run(self, input_id, options=None, default_value=None, display_name=None, description=None):
return [default_value]
-110
View File
@@ -1,110 +0,0 @@
import os
import io
import cv2 as cv
import numpy as np
import torch
import requests
from folder_paths import get_annotated_filepath
class ComfyUIDeployExternalEXR:
RETURN_TYPES = ("IMAGE", "MASK")
RETURN_NAMES = ("image", "mask")
FUNCTION = "load_exr"
CATEGORY = "🔗ComfyDeploy"
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_exr"},
),
"exr_file": ("STRING", {"default": ""}),
"tonemap": (["linear", "sRGB", "Reinhard"], {"default": "sRGB"}),
},
"optional": {
"default_image": ("IMAGE",),
"default_mask": ("MASK",),
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{"multiline": False, "default": ""},
),
}
}
@classmethod
def VALIDATE_INPUTS(s, exr_file, **kwargs):
return True
def sRGBtoLinear(self, npArray):
less = npArray <= 0.0404482362771082
npArray[less] = npArray[less] / 12.92
npArray[~less] = np.power((npArray[~less] + 0.055) / 1.055, 2.4)
def linearToSRGB(self, npArray):
less = npArray <= 0.0031308
npArray[less] = npArray[less] * 12.92
npArray[~less] = np.power(npArray[~less], 1/2.4) * 1.055 - 0.055
def load_exr(self, input_id, exr_file, tonemap="sRGB",
default_image=None, default_mask=None,
display_name=None, description=None):
try:
if exr_file and exr_file != "":
if exr_file.startswith(('http://', 'https://')):
# Handle URL input
response = requests.get(exr_file)
# Write to temp buffer
buffer = io.BytesIO(response.content)
nparr = np.frombuffer(buffer.getvalue(), np.uint8)
image = cv.imdecode(nparr, cv.IMREAD_UNCHANGED).astype(np.float32)
else:
# Handle local file
exr_path = get_annotated_filepath(exr_file)
image = cv.imread(exr_path, cv.IMREAD_UNCHANGED).astype(np.float32)
if len(image.shape) == 2:
image = np.repeat(image[..., np.newaxis], 3, axis=2)
# Extract RGB and flip channels
rgb = np.flip(image[:,:,:3], 2).copy()
# Apply tonemapping
if tonemap == "sRGB":
self.linearToSRGB(rgb)
rgb = np.clip(rgb, 0, 1)
elif tonemap == "Reinhard":
rgb = np.clip(rgb, 0, None)
rgb = rgb / (rgb + 1)
self.linearToSRGB(rgb)
rgb = np.clip(rgb, 0, 1)
rgb = torch.unsqueeze(torch.from_numpy(rgb), 0)
# Handle alpha/mask
mask = torch.zeros((1, image.shape[0], image.shape[1]), dtype=torch.float32)
if image.shape[2] > 3:
mask[0] = torch.from_numpy(np.clip(image[:,:,3], 0, 1))
return (rgb, mask)
else:
# Return defaults if no file provided
return (default_image, default_mask)
except Exception as e:
print(f"Error loading EXR: {str(e)}")
# Return defaults on error
return (default_image, default_mask)
NODE_CLASS_MAPPINGS = {
"ComfyUIDeployExternalEXR": ComfyUIDeployExternalEXR
}
NODE_DISPLAY_NAME_MAPPINGS = {
"ComfyUIDeployExternalEXR": "External EXR (ComfyUI Deploy)"
}
-106
View File
@@ -1,106 +0,0 @@
from PIL import Image, ImageOps
import numpy as np
import torch
import folder_paths
class AnyType(str):
def __ne__(self, __value: object) -> bool:
return False
WILDCARD = AnyType("*")
class ComfyUIDeployExternalFaceModel:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_reactor_face_model"},
),
},
"optional": {
"default_face_model_name": (
"STRING",
{"multiline": False, "default": ""},
),
"face_model_save_name": ( # if `default_face_model_name` is a link to download a file, we will attempt to save it with this name
"STRING",
{"multiline": False, "default": ""},
),
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{"multiline": True, "default": ""},
),
"face_model_url": (
"STRING",
{"multiline": False, "default": ""},
),
},
}
RETURN_TYPES = (WILDCARD,)
RETURN_NAMES = ("path",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
def run(
self,
input_id,
default_face_model_name=None,
face_model_save_name=None,
display_name=None,
description=None,
face_model_url=None,
):
import requests
import os
import uuid
if face_model_url and face_model_url.startswith("http"):
if face_model_save_name:
existing_face_models = folder_paths.get_filename_list("reactor/faces")
# Check if face_model_save_name exists in the list
if face_model_save_name in existing_face_models:
print(f"using face model: {face_model_save_name}")
return (face_model_save_name,)
else:
face_model_save_name = str(uuid.uuid4()) + ".safetensors"
print(face_model_save_name)
print(folder_paths.folder_names_and_paths["reactor/faces"][0][0])
destination_path = os.path.join(
folder_paths.folder_names_and_paths["reactor/faces"][0][0],
face_model_save_name,
)
print(destination_path)
print(
"Downloading external face model - "
+ face_model_url
+ " to "
+ destination_path
)
response = requests.get(
face_model_url,
headers={"User-Agent": "Mozilla/5.0"},
allow_redirects=True,
)
with open(destination_path, "wb") as out_file:
out_file.write(response.content)
return (face_model_save_name,)
else:
print(f"using face model: {default_face_model_name}")
return (default_face_model_name,)
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalFaceModel": ComfyUIDeployExternalFaceModel}
NODE_DISPLAY_NAME_MAPPINGS = {
"ComfyUIDeployExternalFaceModel": "External Face Model (ComfyUI Deploy)"
}
+30 -41
View File
@@ -21,55 +21,44 @@ class ComfyUIDeployExternalImage:
),
"description": (
"STRING",
{"multiline": False, "default": ""},
{"multiline": True, "default": ""},
),
"default_value_url": ("STRING", {"image_preview": True, "default": ""}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
def run(self, input_id, default_value=None, display_name=None, description=None, default_value_url=None):
FUNCTION = "run"
CATEGORY = "image"
def run(self, input_id, default_value=None, display_name=None, description=None):
image = default_value
# Try both input_id and default_value_url
urls_to_try = [url for url in [input_id, default_value_url] if url]
print(default_value_url)
for url in urls_to_try:
try:
if url.startswith('http'):
import requests
from io import BytesIO
print(f"Fetching image from url: {url}")
response = requests.get(url)
image = Image.open(BytesIO(response.content))
break
elif url.startswith(('data:image/png;base64,', 'data:image/jpeg;base64,', 'data:image/jpg;base64,')):
import base64
from io import BytesIO
print("Decoding base64 image")
base64_image = url[url.find(",")+1:]
decoded_image = base64.b64decode(base64_image)
image = Image.open(BytesIO(decoded_image))
break
except:
continue
if image is not None:
try:
image = ImageOps.exif_transpose(image)
image = image.convert("RGB")
image = np.array(image).astype(np.float32) / 255.0
image = torch.from_numpy(image)[None,]
except:
pass
return [image]
try:
if input_id.startswith('http'):
import requests
from io import BytesIO
print("Fetching image from url: ", input_id)
response = requests.get(input_id)
image = Image.open(BytesIO(response.content))
elif input_id.startswith('data:image/png;base64,') or input_id.startswith('data:image/jpeg;base64,') or input_id.startswith('data:image/jpg;base64,'):
import base64
from io import BytesIO
print("Decoding base64 image")
base64_image = input_id[input_id.find(",")+1:]
decoded_image = base64.b64decode(base64_image)
image = Image.open(BytesIO(decoded_image))
else:
raise ValueError("Invalid image url provided.")
image = ImageOps.exif_transpose(image)
image = image.convert("RGB")
image = np.array(image).astype(np.float32) / 255.0
image = torch.from_numpy(image)[None,]
return [image]
except:
return [image]
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalImage": ComfyUIDeployExternalImage}
+3 -1
View File
@@ -28,8 +28,10 @@ class ComfyUIDeployExternalImageAlpha:
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
CATEGORY = "image"
def run(self, input_id, default_value=None, display_name=None, description=None):
image = default_value
+5 -23
View File
@@ -34,37 +34,19 @@ class ComfyUIDeployExternalImageBatch:
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
def process_image(self, image):
image = ImageOps.exif_transpose(image)
image = image.convert("RGB")
image = np.array(image).astype(np.float32) / 255.0
image_tensor = torch.from_numpy(image)[None,]
return image_tensor
CATEGORY = "image"
def run(self, input_id, images=None, default_value=None, display_name=None, description=None):
import requests
import zipfile
import io
processed_images = []
try:
images_list = json.loads(images) # Assuming images is a JSON array string
print(images_list)
for img_input in images_list:
if img_input.startswith('http') and img_input.endswith('.zip'):
print("Fetching zip file from url: ", img_input)
response = requests.get(img_input)
zip_file = zipfile.ZipFile(io.BytesIO(response.content))
for file_name in zip_file.namelist():
if file_name.lower().endswith(('.png', '.jpg', '.jpeg')):
with zip_file.open(file_name) as file:
image = Image.open(file)
image = self.process_image(image)
processed_images.append(image)
elif img_input.startswith('http'):
if img_input.startswith('http'):
import requests
from io import BytesIO
print("Fetching image from url: ", img_input)
response = requests.get(img_input)
+35 -56
View File
@@ -1,4 +1,8 @@
import folder_paths
from PIL import Image, ImageOps
import numpy as np
import torch
import folder_paths
class AnyType(str):
@@ -21,10 +25,10 @@ class ComfyUIDeployExternalLora:
},
"optional": {
"default_lora_name": (folder_paths.get_filename_list("loras"),),
"lora_save_name": ( # if `default_lora_name` is a link to download a file, we will attempt to save it with this name
"lora_save_name": ( # if `default_lora_name` is a link to download a file, we will attempt to save it with this name
"STRING",
{"multiline": False, "default": ""},
),
),
"display_name": (
"STRING",
{"multiline": False, "default": ""},
@@ -37,72 +41,47 @@ class ComfyUIDeployExternalLora:
"STRING",
{"multiline": False, "default": ""},
),
"bearer_token": (
"STRING",
{"multiline": False, "default": ""},
),
},
}
RETURN_TYPES = (WILDCARD,)
RETURN_NAMES = ("path",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
def run(
self,
input_id,
default_lora_name=None,
lora_save_name=None,
display_name=None,
description=None,
lora_url=None,
bearer_token=None,
):
FUNCTION = "run"
CATEGORY = "deploy"
def run(self, input_id, default_lora_name=None, lora_save_name=None, display_name=None, description=None, lora_url=None):
import requests
import os
import uuid
if lora_url:
if lora_url.startswith("http"):
if lora_save_name:
existing_loras = folder_paths.get_filename_list("loras")
# Check if lora_save_name exists in the list
if lora_save_name in existing_loras:
print(f"using lora: {lora_save_name}")
return (lora_save_name,)
else:
lora_save_name = str(uuid.uuid4()) + ".safetensors"
print(lora_save_name)
print(folder_paths.folder_names_and_paths["loras"][0][0])
destination_path = os.path.join(
folder_paths.folder_names_and_paths["loras"][0][0], lora_save_name
)
print(destination_path)
print(
"Downloading external lora - "
+ lora_url
+ " to "
+ destination_path
)
headers = {"User-Agent": "Mozilla/5.0"}
if bearer_token:
headers["Authorization"] = f"Bearer {bearer_token}"
print("using bearer token")
response = requests.get(
lora_url,
headers=headers,
allow_redirects=True,
)
with open(destination_path, "wb") as out_file:
out_file.write(response.content)
print(f"Ext Lora loading: {lora_url} to {lora_save_name}")
return (lora_save_name,)
if lora_url and lora_url.startswith("http"):
if lora_save_name:
existing_loras = folder_paths.get_filename_list("loras")
# Check if lora_save_name exists in the list
if lora_save_name in existing_loras:
print(f"using lora: {lora_save_name}")
return (lora_save_name,)
else:
print(f"Ext Lora loading: {lora_url}")
return (lora_url,)
lora_save_name = str(uuid.uuid4()) + ".safetensors"
print(lora_save_name)
print(folder_paths.folder_names_and_paths["loras"][0][0])
destination_path = os.path.join(
folder_paths.folder_names_and_paths["loras"][0][0], lora_save_name
)
print(destination_path)
print("Downloading external lora - " + input_id + " to " + destination_path)
response = requests.get(
input_id,
headers={"User-Agent": "Mozilla/5.0"},
allow_redirects=True,
)
with open(destination_path, "wb") as out_file:
out_file.write(response.content)
return (lora_save_name,)
else:
print(f"Ext Lora loading: {default_lora_name}")
print(f"using lora: {default_lora_name}")
return (default_lora_name,)
+3 -1
View File
@@ -31,8 +31,10 @@ class ComfyUIDeployExternalNumber:
RETURN_TYPES = ("FLOAT",)
RETURN_NAMES = ("value",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
CATEGORY = "number"
def run(self, input_id, default_value=None, display_name=None, description=None):
try:
+3 -1
View File
@@ -31,8 +31,10 @@ class ComfyUIDeployExternalNumberInt:
RETURN_TYPES = ("INT",)
RETURN_NAMES = ("value",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
CATEGORY = "number"
def run(self, input_id, default_value=None, display_name=None, description=None):
if not input_id or (isinstance(input_id, str) and not input_id.strip().isdigit()):
+3 -1
View File
@@ -34,8 +34,10 @@ class ComfyUIDeployExternalNumberSlider:
RETURN_TYPES = ("FLOAT",)
RETURN_NAMES = ("value",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
CATEGORY = "number"
def run(self, input_id, default_value=None, min_value=0, max_value=1, display_name=None, description=None):
try:
-54
View File
@@ -1,54 +0,0 @@
class ComfyUIDeployExternalNumberSliderInt:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_number_slider_int"},
),
},
"optional": {
"default_value": (
"INT",
{"multiline": True, "display": "number", "min": -2147483647, "max": 2147483647, "default": 1, "step": 1},
),
"min_value": (
"INT",
{"multiline": True, "display": "number", "min": -2147483647, "max": 2147483647, "default": 0, "step": 1},
),
"max_value": (
"INT",
{"multiline": True, "display": "number", "min": -2147483647, "max": 2147483647, "default": 10, "step": 1},
),
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{"multiline": True, "default": ""},
),
}
}
RETURN_TYPES = ("INT",)
RETURN_NAMES = ("value",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
def run(self, input_id, default_value=None, min_value=0, max_value=10, display_name=None, description=None):
try:
int_value = int(round(float(input_id)))
if min_value <= int_value <= max_value:
print("my integer", int_value)
return [int_value]
else:
print("Integer out of range. Returning default value:", default_value)
return [default_value]
except (ValueError, TypeError):
print("Invalid input. Returning default value:", default_value)
return [default_value]
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalNumberSliderInt": ComfyUIDeployExternalNumberSliderInt}
NODE_DISPLAY_NAME_MAPPINGS = {"ComfyUIDeployExternalNumberSliderInt": "External Number Slider Int (ComfyUI Deploy)"}
-116
View File
@@ -1,116 +0,0 @@
import random
class ComfyUIDeployExternalSeed:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_seed"},
),
"default_value": (
"INT",
{"default": -1},
),
"min_value": (
"INT",
{"default": 1, "min": 1, "max": 999999999999999},
),
"max_value": (
"INT",
{"default": 4294967295, "min": 1, "max": 999999999999999},
),
},
"optional": {
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{
"multiline": True,
"default": 'For default value:\n"-1" (i.e. not in range): Randomize within the min and max value range. \nin range: Fixed, always the same value\n',
},
),
},
}
RETURN_TYPES = ("INT",)
RETURN_NAMES = ("seed",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
# Limits
_MAX_LIMIT = 999_999_999_999_999 # 15 digits
# Store cached seed when fixed flag is enabled
_cached_seed = None
@classmethod
def IS_CHANGED(
cls,
input_id,
min_value,
max_value,
default_value=None,
**kwargs,
):
"""Inform ComfyUI whether the node output should be considered changed.
If default_value is within range (Fixed mode), we return the inputs tuple
so the cached result is reused until the user changes something.
For Randomize mode, we force re-execution each queue.
"""
# Clamp values to allowed range for check
min_value = max(1, min_value)
max_value = min(cls._MAX_LIMIT, max_value)
# Fixed mode when default_value is within range
if (
default_value is not None
and default_value >= min_value
and default_value <= max_value
):
return (input_id, default_value)
# For Randomize (default_value is -1 or out of range) we force re-execution
import random as _rnd
return _rnd.random()
def run(
self,
input_id,
min_value: int,
max_value: int,
display_name=None,
description=None,
default_value: int = -1,
):
# Clamp values to allowed range
min_value = max(1, min_value)
max_value = min(self._MAX_LIMIT, max_value)
# Ensure limits are in correct order after clamping
if min_value > max_value:
min_value, max_value = max_value, min_value
# Fixed mode: default_value is within range
if default_value >= min_value and default_value <= max_value:
seed = int(default_value)
self._cached_seed = seed
return [seed]
# Randomize mode: default_value is -1 or out of range
seed = random.randint(min_value, max_value)
self._cached_seed = seed
return [seed]
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalSeed": ComfyUIDeployExternalSeed}
NODE_DISPLAY_NAME_MAPPINGS = {
"ComfyUIDeployExternalSeed": "External Seed (ComfyUI Deploy)"
}
-53
View File
@@ -1,53 +0,0 @@
import re
class StringFunction:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"action": (["append", "replace"], {}),
"tidy_tags": (["yes", "no"], {}),
},
"optional": {
"text_a": ("STRING", {"multiline": True, "dynamicPrompts": False}),
"text_b": ("STRING", {"multiline": True, "dynamicPrompts": False}),
"text_c": ("STRING", {"multiline": True, "dynamicPrompts": False}),
},
}
RETURN_TYPES = ("STRING",)
FUNCTION = "exec"
CATEGORY = "🔗ComfyDeploy"
OUTPUT_NODE = True
def exec(self, action, tidy_tags, text_a="", text_b="", text_c=""):
tidy_tags = tidy_tags == "yes"
out = ""
if action == "append":
out = (", " if tidy_tags else "").join(
filter(None, [text_a, text_b, text_c])
)
else:
if text_c is None:
text_c = ""
if text_b.startswith("/") and text_b.endswith("/"):
regex = text_b[1:-1]
out = re.sub(regex, text_c, text_a)
else:
out = text_a.replace(text_b, text_c)
if tidy_tags:
out = re.sub(r"\s{2,}", " ", out)
out = out.replace(" ,", ",")
out = re.sub(r",{2,}", ",", out)
out = out.strip()
return {"ui": {"text": (out,)}, "result": (out,)}
NODE_CLASS_MAPPINGS = {
"ComfyUIDeployStringCombine": StringFunction,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"ComfyUIDeployStringCombine": "String Combine (ComfyUI Deploy)",
}
+1 -1
View File
@@ -34,7 +34,7 @@ class ComfyUIDeployExternalText:
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
CATEGORY = "text"
def run(self, input_id, default_value=None, display_name=None, description=None):
return [default_value]
-46
View File
@@ -1,46 +0,0 @@
class AnyType(str):
def __ne__(self, __value: object) -> bool:
return False
WILDCARD = AnyType("*")
class ComfyUIDeployExternalTextAny:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_text"},
),
},
"optional": {
"default_value": (
"STRING",
{"multiline": True, "default": ""},
),
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{"multiline": True, "default": ""},
),
}
}
RETURN_TYPES = (WILDCARD,)
RETURN_NAMES = ("text",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
def run(self, input_id, default_value=None, display_name=None, description=None):
return [default_value]
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalTextAny": ComfyUIDeployExternalTextAny}
NODE_DISPLAY_NAME_MAPPINGS = {"ComfyUIDeployExternalTextAny": "External Text Any (ComfyUI Deploy)"}
+52
View File
@@ -0,0 +1,52 @@
import folder_paths
from PIL import Image, ImageOps
import numpy as np
import torch
import json
class ComfyUIDeployExternalTextList:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": 'input_text_list'},
),
"text": (
"STRING",
{"multiline": True, "default": "[]"},
),
},
"optional": {
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{"multiline": True, "default": ""},
),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("text",)
OUTPUT_IS_LIST = (True,)
FUNCTION = "run"
CATEGORY = "text"
def run(self, input_id, text=None, display_name=None, description=None):
text_list = []
try:
text_list = json.loads(text) # Assuming text is a JSON array string
except Exception as e:
print(f"Error processing images: {e}")
pass
return ([text_list],)
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalTextList": ComfyUIDeployExternalTextList}
NODE_DISPLAY_NAME_MAPPINGS = {"ComfyUIDeployExternalTextList": "External Text List (ComfyUI Deploy)"}
-1
View File
@@ -36,7 +36,6 @@ class ComfyUIDeployExternalVideo:
RETURN_NAMES = ("video")
FUNCTION = "load_video"
CATEGORY = "🔗ComfyDeploy"
def load_video(self, input_id, default_value):
input_dir = folder_paths.get_input_directory()
+36 -70
View File
@@ -748,64 +748,36 @@ class ComfyUIDeployExternalVideo:
file_parts = f.split(".")
if len(file_parts) > 1 and (file_parts[-1] in video_extensions):
files.append(f)
return {
"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_video"},
),
"force_rate": ("INT", {"default": 0, "min": 0, "max": 60, "step": 1}),
"force_size": (
[
"Disabled",
"Custom Height",
"Custom Width",
"Custom",
"256x?",
"?x256",
"256x256",
"512x?",
"?x512",
"512x512",
],
),
"custom_width": (
"INT",
{"default": 512, "min": 0, "max": DIMMAX, "step": 8},
),
"custom_height": (
"INT",
{"default": 512, "min": 0, "max": DIMMAX, "step": 8},
),
"frame_load_cap": (
"INT",
{"default": 0, "min": 0, "max": BIGMAX, "step": 1},
),
"skip_first_frames": (
"INT",
{"default": 0, "min": 0, "max": BIGMAX, "step": 1},
),
"select_every_nth": (
"INT",
{"default": 1, "min": 1, "max": BIGMAX, "step": 1},
),
},
"optional": {
"meta_batch": ("VHS_BatchManager",),
"vae": ("VAE",),
"default_video": (sorted(files),),
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{"multiline": True, "default": ""},
),
"default_value_url": ("STRING", {"image_preview": True, "default": ""}),
},
"hidden": {"unique_id": "UNIQUE_ID"},
}
return {"required": {
"input_id": (
"STRING",
{"multiline": False, "default": "input_video"},
),
"force_rate": ("INT", {"default": 0, "min": 0, "max": 60, "step": 1}),
"force_size": (["Disabled", "Custom Height", "Custom Width", "Custom", "256x?", "?x256", "256x256", "512x?", "?x512", "512x512"],),
"custom_width": ("INT", {"default": 512, "min": 0, "max": DIMMAX, "step": 8}),
"custom_height": ("INT", {"default": 512, "min": 0, "max": DIMMAX, "step": 8}),
"frame_load_cap": ("INT", {"default": 0, "min": 0, "max": BIGMAX, "step": 1}),
"skip_first_frames": ("INT", {"default": 0, "min": 0, "max": BIGMAX, "step": 1}),
"select_every_nth": ("INT", {"default": 1, "min": 1, "max": BIGMAX, "step": 1}),
},
"optional": {
"meta_batch": ("VHS_BatchManager",),
"vae": ("VAE",),
"default_value": (sorted(files),),
"display_name": (
"STRING",
{"multiline": False, "default": ""},
),
"description": (
"STRING",
{"multiline": True, "default": ""},
),
},
"hidden": {
"unique_id": "UNIQUE_ID"
},
}
CATEGORY = "Video Helper Suite 🎥🅥🅗🅢"
@@ -819,7 +791,6 @@ class ComfyUIDeployExternalVideo:
)
FUNCTION = "load_video"
CATEGORY = "🔗ComfyDeploy"
def load_video(self, **kwargs):
input_id = kwargs.get("input_id")
@@ -832,21 +803,16 @@ class ComfyUIDeployExternalVideo:
select_every_nth = kwargs.get("select_every_nth")
meta_batch = kwargs.get("meta_batch")
unique_id = kwargs.get("unique_id")
default_value_url = kwargs.get("default_value_url")
input_dir = folder_paths.get_input_directory()
if input_id.startswith("http") or (
default_value_url and default_value_url.startswith("http")
):
if input_id.startswith("http"):
import requests
# Use input_id if it's a URL, otherwise use default_value_url
url = input_id if input_id.startswith("http") else default_value_url
print("Fetching video from URL: ", url)
response = requests.get(url, stream=True)
print("Fetching video from URL: ", input_id)
response = requests.get(input_id, stream=True)
file_size = int(response.headers.get("Content-Length", 0))
file_extension = url.split(".")[-1].split("?")[
file_extension = input_id.split(".")[-1].split("?")[
0
] # Extract extension and handle URLs with parameters
if file_extension not in video_extensions:
@@ -868,7 +834,7 @@ class ComfyUIDeployExternalVideo:
):
out_file.write(chunk)
else:
video = kwargs.get("default_video", None)
video = kwargs.get("default_value", "")
if video is None:
raise "No default video given and no external video provided"
video_path = folder_paths.get_annotated_filepath(video.strip('"'))
-1
View File
@@ -33,7 +33,6 @@ class ComfyDeployWebscoketImageInput:
RETURN_NAMES = ("images",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
@classmethod
def VALIDATE_INPUTS(s, input_id):
-78
View File
@@ -1,78 +0,0 @@
# In file: comfyui-deploy/comfy-nodes/output_exr.py
import os
import numpy as np
import folder_paths
# Try to set up OpenCV for EXR writing.
try:
os.environ["OPENCV_IO_ENABLE_OPENEXR"] = "1"
import cv2
OPENCV_AVAILABLE = True
except ImportError:
print("Warning: OpenCV not found for ComfyDeployOutputEXR. Please add opencv-python-headless to requirements.txt")
OPENCV_AVAILABLE = False
# ALIGNED: Renamed class to match project conventions
class ComfyDeployOutputEXR:
def __init__(self):
self.output_dir = folder_paths.get_output_directory()
self.type = "output"
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"images": ("IMAGE", ),
"filename_prefix": ("STRING", {"default": "ComfyDeploy_EXR"})
},
# ADDED: Optional output_id for consistency with other ComfyDeploy nodes
"optional": {
"output_id": ("STRING", {"multiline": False, "default": "output_exr"}),
},
}
RETURN_TYPES = ()
# ALIGNED: Changed function name to 'run'
FUNCTION = "run"
OUTPUT_NODE = True
# ALIGNED: Matched the category name
CATEGORY = "🔗ComfyDeploy"
DESCRIPTION = "Saves the input images as EXR (HDR) files."
def run(self, images, filename_prefix="ComfyDeploy_EXR", output_id="output_exr"):
if not OPENCV_AVAILABLE:
raise ImportError("OpenCV is required to save EXR files. Please ensure opencv-python-headless is in requirements.txt.")
full_output_folder, filename, counter, subfolder, filename_prefix = (
folder_paths.get_save_image_path(
filename_prefix, self.output_dir, images[0].shape[1], images[0].shape[0]
)
)
results = list()
for image in images:
image_np = image.cpu().numpy()
if image_np.dtype != np.float32:
image_np = image_np.astype(np.float32)
file = f"{filename}_{counter:05}.exr"
file_path = os.path.join(full_output_folder, file)
image_np_bgr = cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR)
cv2.imwrite(file_path, image_np_bgr)
results.append({
"filename": file,
"subfolder": subfolder,
"type": self.type,
"output_id": output_id, # ADDED
})
counter += 1
return {"ui": {"images": results}}
# ALIGNED: Mappings are defined at the bottom of the node file in this project
NODE_CLASS_MAPPINGS = {"ComfyDeployOutputEXR": ComfyDeployOutputEXR}
NODE_DISPLAY_NAME_MAPPINGS = {"ComfyDeployOutputEXR": "EXR Output (ComfyDeploy)"}
-101
View File
@@ -1,101 +0,0 @@
import os
import json
import numpy as np
from PIL import Image
from PIL.PngImagePlugin import PngInfo
import folder_paths
class ComfyDeployOutputImage:
def __init__(self):
self.output_dir = folder_paths.get_output_directory()
self.type = "output"
self.prefix_append = ""
self.compress_level = 4
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"images": ("IMAGE", {"tooltip": "The images to save."}),
"filename_prefix": (
"STRING",
{
"default": "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.",
},
),
"file_type": (["png", "jpg", "webp"], {"default": "webp"}),
"quality": ("INT", {"default": 80, "min": 1, "max": 100, "step": 1}),
},
"optional": {
"output_id": (
"STRING",
{"multiline": False, "default": "output_images"},
),
},
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
}
RETURN_TYPES = ()
FUNCTION = "run"
OUTPUT_NODE = True
CATEGORY = "🔗ComfyDeploy"
DESCRIPTION = "Saves the input images to your ComfyUI output directory."
def run(
self,
images,
filename_prefix="ComfyUI",
file_type="png",
quality=80,
output_id="output_images",
prompt=None,
extra_pnginfo=None,
):
filename_prefix += self.prefix_append
full_output_folder, filename, counter, subfolder, filename_prefix = (
folder_paths.get_save_image_path(
filename_prefix, self.output_dir, images[0].shape[1], images[0].shape[0]
)
)
results = list()
for batch_number, image in enumerate(images):
i = 255.0 * image.cpu().numpy()
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
metadata = PngInfo()
if prompt is not None:
metadata.add_text("prompt", json.dumps(prompt))
if extra_pnginfo is not None:
for x in extra_pnginfo:
metadata.add_text(x, json.dumps(extra_pnginfo[x]))
filename_with_batch_num = filename.replace("%batch_num%", str(batch_number))
file = f"{filename_with_batch_num}_{counter:05}_.{file_type}"
file_path = os.path.join(full_output_folder, file)
if file_type == "png":
img.save(
file_path, pnginfo=metadata, compress_level=self.compress_level
)
elif file_type == "jpg":
img.save(file_path, quality=quality, optimize=True)
elif file_type == "webp":
img.save(file_path, quality=quality)
results.append(
{
"filename": file,
"subfolder": subfolder,
"type": self.type,
"output_id": output_id,
}
)
counter += 1
return {"ui": {"images": results}}
NODE_CLASS_MAPPINGS = {"ComfyDeployOutputImage": ComfyDeployOutputImage}
NODE_DISPLAY_NAME_MAPPINGS = {"ComfyDeployOutputImage": "Image Output (ComfyDeploy)"}
-99
View File
@@ -1,99 +0,0 @@
import os
import json
import folder_paths
class ComfyDeployOutputText:
def __init__(self):
self.output_dir = folder_paths.get_output_directory()
self.type = "output"
self.prefix_append = ""
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": (
"STRING",
{
"multiline": True,
"forceInput": True,
"tooltip": "The text to save.",
},
),
"filename_prefix": (
"STRING",
{
"default": "ComfyUI",
"tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% to include values from nodes.",
},
),
"file_type": (["txt", "json", "md"], {"default": "txt"}),
},
"optional": {
"output_id": (
"STRING",
{"multiline": False, "default": "output_text"},
),
},
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
}
RETURN_TYPES = ()
FUNCTION = "run"
OUTPUT_NODE = True
CATEGORY = "🔗ComfyDeploy"
DESCRIPTION = "Saves the input text to your ComfyUI output directory."
def run(
self,
text,
filename_prefix="ComfyUI",
file_type="txt",
output_id="output_text",
prompt=None,
extra_pnginfo=None,
):
filename_prefix += self.prefix_append
# For text, we don't need dimensions, so pass 0, 0
full_output_folder, filename, counter, subfolder, filename_prefix = (
folder_paths.get_save_image_path(filename_prefix, self.output_dir, 0, 0)
)
results = list()
# Create file path
file = f"{filename}_{counter:05}_.{file_type}"
file_path = os.path.join(full_output_folder, file)
# Save the text based on file type
if file_type == "json":
try:
# Try to save as JSON if the text is valid JSON
json_data = json.loads(text) if isinstance(text, str) else text
with open(file_path, "w", encoding="utf-8") as f:
json.dump(json_data, f, indent=2)
except json.JSONDecodeError:
# Fall back to saving as plain text if not valid JSON
with open(file_path, "w", encoding="utf-8") as f:
f.write(text)
else:
# Save as plain text for txt and md
with open(file_path, "w", encoding="utf-8") as f:
f.write(text)
results.append(
{
"filename": file,
"subfolder": subfolder,
"type": self.type,
"output_id": output_id,
}
)
return {"ui": {"text_file": results}}
NODE_CLASS_MAPPINGS = {"ComfyDeployOutputText": ComfyDeployOutputText}
NODE_DISPLAY_NAME_MAPPINGS = {"ComfyDeployOutputText": "Text Output (ComfyDeploy)"}
+3 -1
View File
@@ -33,8 +33,10 @@ class ComfyDeployWebscoketImageOutput:
RETURN_TYPES = ()
RETURN_NAMES = ("text",)
FUNCTION = "run"
CATEGORY = "🔗ComfyDeploy"
CATEGORY = "output"
@classmethod
def VALIDATE_INPUTS(s, output_id):
+437 -2115
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

-152
View File
@@ -1,152 +0,0 @@
{
"id": "ed93ac94-4f26-4ed3-a57b-73cd8f4d3494",
"revision": 0,
"last_node_id": 5,
"last_link_id": 1,
"nodes": [
{
"id": 2,
"type": "LoraLoader",
"pos": [
736.646728515625,
628.3823852539062
],
"size": [
315,
126
],
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": null
},
{
"name": "clip",
"type": "CLIP",
"link": null
},
{
"name": "lora_name",
"type": "COMBO",
"widget": {
"name": "lora_name"
},
"link": 1
}
],
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": null
},
{
"name": "CLIP",
"type": "CLIP",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "LoraLoader"
},
"widgets_values": [
"1-292.safetensors",
1,
1
]
},
{
"id": 1,
"type": "ComfyUIDeployExternalLora",
"pos": [
299.6898498535156,
624.7929077148438
],
"size": [
400,
208
],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "path",
"type": "*",
"links": [
1
]
}
],
"properties": {
"cnr_id": "comfyui-deploy",
"ver": "cd3a2ff5471828f9c840e746551592e882c05aa4",
"Node name for S&R": "ComfyUIDeployExternalLora"
},
"widgets_values": [
"input_lora",
"HyperSD\\FLUX.1\\Hyper-FLUX.1-dev-16steps-lora.safetensors",
"",
"",
"",
""
]
},
{
"id": 5,
"type": "Note",
"pos": [
302.09033203125,
401.2951965332031
],
"size": [
479.4894104003906,
161.61924743652344
],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {},
"widgets_values": [
"\"External Lora\" node will let you to use different loras from the Comfy Deploy UI or even via API.\n\n- lora_url:\n url that will be used to download your LoRA model in execution time\n\n- lora_save_name:\n when we download your model, this will be saved in your private storage, \n give it a good name :D"
],
"color": "#432",
"bgcolor": "#653"
}
],
"links": [
[
1,
1,
0,
2,
2,
"COMBO"
]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 1.167184107045006,
"offset": [
298.431389807788,
-207.58877445762934
]
},
"VHS_latentpreview": false,
"VHS_latentpreviewrate": 0,
"VHS_MetadataImage": true,
"VHS_KeepIntermediate": true
},
"version": 0.4
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 KiB

-873
View File
@@ -1,873 +0,0 @@
{
"id": "351f402b-62f2-4f62-8a5e-0b9d3510e8f9",
"revision": 0,
"last_node_id": 29,
"last_link_id": 28,
"nodes": [
{
"id": 11,
"type": "JoinImageWithAlpha",
"pos": [
814.478271484375,
419.3052062988281
],
"size": [
264.5999755859375,
46
],
"flags": {},
"order": 5,
"mode": 0,
"inputs": [
{
"name": "image",
"type": "IMAGE",
"link": 10
},
{
"name": "alpha",
"type": "MASK",
"link": 12
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
11
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "JoinImageWithAlpha"
},
"widgets_values": []
},
{
"id": 15,
"type": "PreviewImage",
"pos": [
1950,
640
],
"size": [
210,
246
],
"flags": {},
"order": 18,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 16
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "PreviewImage"
},
"widgets_values": []
},
{
"id": 10,
"type": "LoadImage",
"pos": [
467.8168640136719,
422.453857421875
],
"size": [
315,
314
],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
10
]
},
{
"name": "MASK",
"type": "MASK",
"links": [
12
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"Bob-Minion-Background-PNG-Image.png",
"image",
""
]
},
{
"id": 18,
"type": "Note",
"pos": [
460.8001708984375,
263.64251708984375
],
"size": [
379.4292297363281,
88
],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {},
"widgets_values": [
"Option 1: CREATE THE MASK FROM THE ALPHA CHANNEL (Useful for example to generate the background of an image)\n\nMake sure that you are using \"External Image Alpha\". \n"
],
"color": "#432",
"bgcolor": "#653"
},
{
"id": 21,
"type": "LoadImage",
"pos": [
469.57025146484375,
1506.3018798828125
],
"size": [
315,
314
],
"flags": {},
"order": 2,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
18
]
},
{
"name": "MASK",
"type": "MASK",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"ComfyUI_temp_otmos_00005_.png",
"image",
""
]
},
{
"id": 25,
"type": "MaskToImage",
"pos": [
1283.1668701171875,
1579.603271484375
],
"size": [
176.39999389648438,
26
],
"flags": {},
"order": 13,
"mode": 0,
"inputs": [
{
"name": "mask",
"type": "MASK",
"link": 28
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
21
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "MaskToImage"
},
"widgets_values": []
},
{
"id": 13,
"type": "SplitImageWithAlpha",
"pos": [
1602.5518798828125,
417.59869384765625
],
"size": [
277.20001220703125,
46
],
"flags": {},
"order": 11,
"mode": 0,
"inputs": [
{
"name": "image",
"type": "IMAGE",
"link": 13
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
14,
25
]
},
{
"name": "MASK",
"type": "MASK",
"links": [
15,
26
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "SplitImageWithAlpha"
},
"widgets_values": []
},
{
"id": 29,
"type": "VAEEncodeForInpaint",
"pos": [
2220.89453125,
401.0885009765625
],
"size": [
340.20001220703125,
98
],
"flags": {},
"order": 16,
"mode": 0,
"inputs": [
{
"name": "pixels",
"type": "IMAGE",
"link": 25
},
{
"name": "vae",
"type": "VAE",
"link": null
},
{
"name": "mask",
"type": "MASK",
"link": 26
}
],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "VAEEncodeForInpaint"
},
"widgets_values": [
6
]
},
{
"id": 14,
"type": "PreviewImage",
"pos": [
1950,
350
],
"size": [
210,
246
],
"flags": {},
"order": 14,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 14
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "PreviewImage"
},
"widgets_values": []
},
{
"id": 17,
"type": "MaskToImage",
"pos": [
1752.33203125,
572.061767578125
],
"size": [
176.39999389648438,
26
],
"flags": {},
"order": 15,
"mode": 0,
"inputs": [
{
"name": "mask",
"type": "MASK",
"link": 15
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
16
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "MaskToImage"
},
"widgets_values": []
},
{
"id": 27,
"type": "PreviewImage",
"pos": [
1329.2960205078125,
1132.759765625
],
"size": [
210,
246
],
"flags": {},
"order": 10,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 22
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "PreviewImage"
},
"widgets_values": []
},
{
"id": 20,
"type": "LoadImage",
"pos": [
468.1963806152344,
1128.9498291015625
],
"size": [
315,
314
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
17
]
},
{
"name": "MASK",
"type": "MASK",
"links": []
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"clipspace/clipspace-mask-1126817.300000012.png [input]",
"image",
""
]
},
{
"id": 24,
"type": "ImageToMask",
"pos": [
1255.560302734375,
1468.347900390625
],
"size": [
315,
58
],
"flags": {},
"order": 9,
"mode": 0,
"inputs": [
{
"name": "image",
"type": "IMAGE",
"link": 19
}
],
"outputs": [
{
"name": "MASK",
"type": "MASK",
"links": [
24,
28
]
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "ImageToMask"
},
"widgets_values": [
"red"
]
},
{
"id": 26,
"type": "PreviewImage",
"pos": [
1488.1925048828125,
1579.146728515625
],
"size": [
210,
246
],
"flags": {},
"order": 17,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 21
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "PreviewImage"
},
"widgets_values": []
},
{
"id": 28,
"type": "VAEEncodeForInpaint",
"pos": [
1637.603271484375,
1182.81298828125
],
"size": [
340.20001220703125,
98
],
"flags": {},
"order": 12,
"mode": 0,
"inputs": [
{
"name": "pixels",
"type": "IMAGE",
"link": 23
},
{
"name": "vae",
"type": "VAE",
"link": null
},
{
"name": "mask",
"type": "MASK",
"link": 24
}
],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.27",
"Node name for S&R": "VAEEncodeForInpaint"
},
"widgets_values": [
6
]
},
{
"id": 19,
"type": "Note",
"pos": [
467.4615173339844,
985.1439819335938
],
"size": [
379.4292297363281,
88
],
"flags": {},
"order": 4,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {},
"widgets_values": [
"Option 2: UPLOAD THE MASK AS OTHER IMAGE (useful if you require the image that is below the mask to do inpainting, in this case to generate new glasses)"
],
"color": "#432",
"bgcolor": "#653"
},
{
"id": 22,
"type": "ComfyUIDeployExternalImage",
"pos": [
910.8199462890625,
1132.306396484375
],
"size": [
390.5999755859375,
154
],
"flags": {},
"order": 7,
"mode": 0,
"inputs": [
{
"name": "default_value",
"shape": 7,
"type": "IMAGE",
"link": 17
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
22,
23
]
}
],
"properties": {
"cnr_id": "comfyui-deploy",
"ver": "cd3a2ff5471828f9c840e746551592e882c05aa4",
"Node name for S&R": "ComfyUIDeployExternalImage"
},
"widgets_values": [
"input_image",
"",
"",
"",
""
]
},
{
"id": 23,
"type": "ComfyUIDeployExternalImage",
"pos": [
843.6348876953125,
1467.8876953125
],
"size": [
390.5999755859375,
154
],
"flags": {},
"order": 6,
"mode": 0,
"inputs": [
{
"name": "default_value",
"shape": 7,
"type": "IMAGE",
"link": 18
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
19
]
}
],
"properties": {
"cnr_id": "comfyui-deploy",
"ver": "cd3a2ff5471828f9c840e746551592e882c05aa4",
"Node name for S&R": "ComfyUIDeployExternalImage"
},
"widgets_values": [
"input_image_mask",
"",
"",
"",
""
]
},
{
"id": 12,
"type": "ComfyUIDeployExternalImageAlpha",
"pos": [
1107.891357421875,
418.2679138183594
],
"size": [
466.1999816894531,
200
],
"flags": {},
"order": 8,
"mode": 0,
"inputs": [
{
"name": "default_value",
"shape": 7,
"type": "IMAGE",
"link": 11
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
13
]
}
],
"properties": {
"cnr_id": "comfyui-deploy",
"ver": "cd3a2ff5471828f9c840e746551592e882c05aa4",
"Node name for S&R": "ComfyUIDeployExternalImageAlpha"
},
"widgets_values": [
"input_image_alpha",
"",
""
]
}
],
"links": [
[
10,
10,
0,
11,
0,
"IMAGE"
],
[
11,
11,
0,
12,
0,
"IMAGE"
],
[
12,
10,
1,
11,
1,
"MASK"
],
[
13,
12,
0,
13,
0,
"IMAGE"
],
[
14,
13,
0,
14,
0,
"IMAGE"
],
[
15,
13,
1,
17,
0,
"MASK"
],
[
16,
17,
0,
15,
0,
"IMAGE"
],
[
17,
20,
0,
22,
0,
"IMAGE"
],
[
18,
21,
0,
23,
0,
"IMAGE"
],
[
19,
23,
0,
24,
0,
"IMAGE"
],
[
21,
25,
0,
26,
0,
"IMAGE"
],
[
22,
22,
0,
27,
0,
"IMAGE"
],
[
23,
22,
0,
28,
0,
"IMAGE"
],
[
24,
24,
0,
28,
2,
"MASK"
],
[
25,
13,
0,
29,
0,
"IMAGE"
],
[
26,
13,
1,
29,
2,
"MASK"
],
[
28,
24,
0,
25,
0,
"MASK"
]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 0.9646149645000013,
"offset": [
48.66905973637718,
-817.5683540167485
]
},
"VHS_latentpreview": false,
"VHS_latentpreviewrate": 0,
"VHS_MetadataImage": true,
"VHS_KeepIntermediate": true
},
"version": 0.4
}
-359
View File
@@ -1,359 +0,0 @@
{
"extra": {
"ds": {
"scale": 0.6010518407212623,
"offset": [815.5938895649746, 84.94304700477853]
},
"node_versions": {
"comfy-core": "0.3.19",
"comfyui-deploy": "b3df94d1affcf7ce05ee7eeda99989194bcd9159"
}
},
"links": [
[9, 8, 0, 9, 0, "IMAGE"],
[45, 30, 1, 6, 0, "CLIP"],
[46, 30, 2, 8, 1, "VAE"],
[47, 30, 0, 31, 0, "MODEL"],
[51, 27, 0, 31, 3, "LATENT"],
[52, 31, 0, 8, 0, "LATENT"],
[54, 30, 1, 33, 0, "CLIP"],
[55, 33, 0, 31, 2, "CONDITIONING"],
[56, 6, 0, 35, 0, "CONDITIONING"],
[57, 35, 0, 31, 1, "CONDITIONING"],
[58, 38, 0, 6, 1, "STRING"],
[59, 40, 0, 27, 0, "INT"],
[60, 39, 0, 27, 1, "INT"]
],
"nodes": [
{
"id": 6,
"pos": [384, 192],
"mode": 0,
"size": [422.8500061035156, 164.30999755859375],
"type": "CLIPTextEncode",
"color": "#232",
"flags": {},
"order": 7,
"title": "CLIP Text Encode (Positive Prompt)",
"inputs": [
{ "link": 45, "name": "clip", "type": "CLIP" },
{
"pos": [10, 36],
"link": 58,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"bgcolor": "#353",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [56],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [
"cute anime girl with massive fluffy fennec ears and a big fluffy tail blonde messy long hair blue eyes wearing a maid outfit with a long black gold leaf pattern dress and a white apron mouth open placing a fancy black forest cake with candles on top of a dinner table of an old dark Victorian mansion lit by candlelight with a bright window to the foggy forest and very expensive stuff everywhere there are paintings on the walls"
]
},
{
"id": 8,
"pos": [1151, 195],
"mode": 0,
"size": [210, 46],
"type": "VAEDecode",
"flags": {},
"order": 11,
"inputs": [
{ "link": 52, "name": "samples", "type": "LATENT" },
{ "link": 46, "name": "vae", "type": "VAE" }
],
"outputs": [
{ "name": "IMAGE", "type": "IMAGE", "links": [9], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAEDecode" },
"widgets_values": []
},
{
"id": 9,
"pos": [1375, 194],
"mode": 0,
"size": [985.2999877929688, 1060.3800048828125],
"type": "SaveImage",
"flags": {},
"order": 12,
"inputs": [{ "link": 9, "name": "images", "type": "IMAGE" }],
"outputs": [],
"properties": {},
"widgets_values": ["ComfyUI"]
},
{
"id": 31,
"pos": [816, 192],
"mode": 0,
"size": [315, 262],
"type": "KSampler",
"flags": {},
"order": 10,
"inputs": [
{ "link": 47, "name": "model", "type": "MODEL" },
{ "link": 57, "name": "positive", "type": "CONDITIONING" },
{ "link": 55, "name": "negative", "type": "CONDITIONING" },
{ "link": 51, "name": "latent_image", "type": "LATENT" }
],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [52],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "KSampler" },
"widgets_values": [
1024035737089801,
"randomize",
20,
1,
"euler",
"simple",
1
]
},
{
"id": 35,
"pos": [576, 96],
"mode": 0,
"size": [211.60000610351562, 58],
"type": "FluxGuidance",
"flags": {},
"order": 9,
"inputs": [
{ "link": 56, "name": "conditioning", "type": "CONDITIONING" }
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [57],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "FluxGuidance" },
"widgets_values": [3.5]
},
{
"id": 37,
"pos": [60, 345],
"mode": 0,
"size": [225, 88],
"type": "MarkdownNote",
"color": "#432",
"flags": {},
"order": 0,
"inputs": [],
"bgcolor": "#653",
"outputs": [],
"properties": {},
"widgets_values": [
"🛈 [Learn more about this workflow](https://comfyanonymous.github.io/ComfyUI_examples/flux/#flux-dev-1)"
]
},
{
"id": 34,
"pos": [825, 510],
"mode": 0,
"size": [282.8599853515625, 164.0800018310547],
"type": "Note",
"color": "#432",
"flags": {},
"order": 1,
"inputs": [],
"bgcolor": "#653",
"outputs": [],
"properties": { "text": "" },
"widgets_values": [
"Note that Flux dev and schnell do not have any negative prompt so CFG should be set to 1.0. Setting CFG to 1.0 means the negative prompt is ignored."
]
},
{
"id": 30,
"pos": [48, 192],
"mode": 0,
"size": [315, 98],
"type": "CheckpointLoaderSimple",
"flags": {},
"order": 2,
"inputs": [],
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [47],
"shape": 3,
"slot_index": 0
},
{
"name": "CLIP",
"type": "CLIP",
"links": [45, 54],
"shape": 3,
"slot_index": 1
},
{
"name": "VAE",
"type": "VAE",
"links": [46],
"shape": 3,
"slot_index": 2
}
],
"properties": { "Node name for S&R": "CheckpointLoaderSimple" },
"widgets_values": ["FLUX1/flux1-dev-fp8.safetensors"]
},
{
"id": 33,
"pos": [390, 400],
"mode": 0,
"size": [422.8500061035156, 164.30999755859375],
"type": "CLIPTextEncode",
"color": "#322",
"flags": { "collapsed": true },
"order": 6,
"title": "CLIP Text Encode (Negative Prompt)",
"inputs": [
{ "link": 54, "name": "clip", "type": "CLIP", "slot_index": 0 }
],
"bgcolor": "#533",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [55],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [""]
},
{
"id": 27,
"pos": [461.8629455566406, 460.2491149902344],
"mode": 0,
"size": [315, 126],
"type": "EmptySD3LatentImage",
"color": "#323",
"flags": {},
"order": 8,
"inputs": [
{
"pos": [10, 60],
"link": 59,
"name": "height",
"type": "INT",
"widget": { "name": "height" }
},
{
"pos": [10, 36],
"link": 60,
"name": "width",
"type": "INT",
"widget": { "name": "width" }
}
],
"bgcolor": "#535",
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [51],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "EmptySD3LatentImage" },
"widgets_values": [1024, 1024, 1]
},
{
"id": 38,
"pos": [-497.3238525390625, 306.5517578125],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 3,
"inputs": [],
"outputs": [{ "name": "text", "type": "STRING", "links": [58] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": [
"prompt",
"cute anime girl with massive fluffy fennec ears and a big fluffy tail blonde messy long hair blue eyes wearing a maid outfit with a long black gold leaf pattern dress and a white apron mouth open placing a fancy black forest cake with candles on top of a dinner table of an old dark Victorian mansion lit by candlelight with a bright window to the foggy forest and very expensive stuff everywhere there are paintings on the walls",
"Prompt",
"The prompt to generate an image from."
]
},
{
"id": 39,
"pos": [-507.4543762207031, 612.9552001953125],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 4,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [60], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["width", 1024, "Width", "The width of the image."]
},
{
"id": 40,
"pos": [-497.8695068359375, 864.68994140625],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 5,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [59], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["height", 1024, "Height", "The height of the image."]
}
],
"config": {},
"groups": [
{
"id": 1,
"color": "#3f789e",
"flags": {},
"title": "Input",
"bounding": [
-508.010986328125, 186.76593017578125, 453.23040771484375,
334.3218994140625
],
"font_size": 24
},
{
"id": 2,
"color": "#A88",
"flags": {},
"title": "Additional",
"bounding": [
-517.1227416992188, 537.53759765625, 644.4954223632812,
599.2609252929688
],
"font_size": 24
}
],
"version": 0.4,
"last_link_id": 60,
"last_node_id": 40
}
-423
View File
@@ -1,423 +0,0 @@
{
"extra": {
"ds": {
"scale": 0.6830134553650709,
"offset": [750.2474149300585, 120.48924647647146]
},
"node_versions": {
"comfy-core": "0.3.19",
"comfyui-deploy": "171a227856bd5f31e97828d89f83f3741004d05e"
}
},
"links": [
[9, 8, 0, 9, 0, "IMAGE"],
[10, 11, 0, 6, 0, "CLIP"],
[12, 10, 0, 8, 1, "VAE"],
[19, 16, 0, 13, 2, "SAMPLER"],
[20, 17, 0, 13, 3, "SIGMAS"],
[23, 5, 0, 13, 4, "LATENT"],
[24, 13, 0, 8, 0, "LATENT"],
[30, 22, 0, 13, 1, "GUIDER"],
[37, 25, 0, 13, 0, "NOISE"],
[38, 12, 0, 17, 0, "MODEL"],
[39, 12, 0, 22, 0, "MODEL"],
[40, 6, 0, 22, 1, "CONDITIONING"],
[41, 28, 0, 6, 1, "STRING"],
[44, 29, 0, 5, 0, "INT"],
[45, 30, 0, 5, 1, "INT"]
],
"nodes": [
{
"id": 13,
"pos": [842, 215],
"mode": 0,
"size": [355.20001220703125, 106],
"type": "SamplerCustomAdvanced",
"flags": {},
"order": 14,
"inputs": [
{ "link": 37, "name": "noise", "type": "NOISE", "slot_index": 0 },
{ "link": 30, "name": "guider", "type": "GUIDER", "slot_index": 1 },
{ "link": 19, "name": "sampler", "type": "SAMPLER", "slot_index": 2 },
{ "link": 20, "name": "sigmas", "type": "SIGMAS", "slot_index": 3 },
{
"link": 23,
"name": "latent_image",
"type": "LATENT",
"slot_index": 4
}
],
"outputs": [
{
"name": "output",
"type": "LATENT",
"links": [24],
"shape": 3,
"slot_index": 0
},
{
"name": "denoised_output",
"type": "LATENT",
"links": null,
"shape": 3
}
],
"properties": { "Node name for S&R": "SamplerCustomAdvanced" },
"widgets_values": []
},
{
"id": 8,
"pos": [1248, 192],
"mode": 0,
"size": [210, 46],
"type": "VAEDecode",
"flags": {},
"order": 15,
"inputs": [
{ "link": 24, "name": "samples", "type": "LATENT" },
{ "link": 12, "name": "vae", "type": "VAE" }
],
"outputs": [
{ "name": "IMAGE", "type": "IMAGE", "links": [9], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAEDecode" },
"widgets_values": []
},
{
"id": 22,
"pos": [559, 125],
"mode": 0,
"size": [241.79998779296875, 46],
"type": "BasicGuider",
"flags": {},
"order": 13,
"inputs": [
{ "link": 39, "name": "model", "type": "MODEL", "slot_index": 0 },
{
"link": 40,
"name": "conditioning",
"type": "CONDITIONING",
"slot_index": 1
}
],
"outputs": [
{
"name": "GUIDER",
"type": "GUIDER",
"links": [30],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "BasicGuider" },
"widgets_values": []
},
{
"id": 16,
"pos": [480, 720],
"mode": 0,
"size": [315, 58],
"type": "KSamplerSelect",
"flags": {},
"order": 0,
"inputs": [],
"outputs": [
{ "name": "SAMPLER", "type": "SAMPLER", "links": [19], "shape": 3 }
],
"properties": { "Node name for S&R": "KSamplerSelect" },
"widgets_values": ["euler"]
},
{
"id": 17,
"pos": [480, 816],
"mode": 0,
"size": [315, 106],
"type": "BasicScheduler",
"flags": {},
"order": 10,
"inputs": [
{ "link": 38, "name": "model", "type": "MODEL", "slot_index": 0 }
],
"outputs": [
{ "name": "SIGMAS", "type": "SIGMAS", "links": [20], "shape": 3 }
],
"properties": { "Node name for S&R": "BasicScheduler" },
"widgets_values": ["simple", 4, 1]
},
{
"id": 27,
"pos": [480, 960],
"mode": 0,
"size": [311.3529052734375, 131.16229248046875],
"type": "Note",
"color": "#432",
"flags": {},
"order": 1,
"inputs": [],
"bgcolor": "#653",
"outputs": [],
"properties": { "text": "" },
"widgets_values": [
"The schnell model is a distilled model that can generate a good image with only 4 steps."
]
},
{
"id": 9,
"pos": [1488, 192],
"mode": 0,
"size": [985.3012084960938, 1060.3828125],
"type": "SaveImage",
"flags": {},
"order": 16,
"inputs": [{ "link": 9, "name": "images", "type": "IMAGE" }],
"outputs": [],
"properties": {},
"widgets_values": ["ComfyUI"]
},
{
"id": 25,
"pos": [480, 587.7890625],
"mode": 0,
"size": [315, 82],
"type": "RandomNoise",
"color": "#2a363b",
"flags": {},
"order": 2,
"inputs": [],
"bgcolor": "#3f5159",
"outputs": [
{ "name": "NOISE", "type": "NOISE", "links": [37], "shape": 3 }
],
"properties": { "Node name for S&R": "RandomNoise" },
"widgets_values": [393845863554716, "randomize"]
},
{
"id": 5,
"pos": [471.7746276855469, 423.91571044921875],
"mode": 0,
"size": [315, 126],
"type": "EmptyLatentImage",
"color": "#323",
"flags": {},
"order": 12,
"inputs": [
{
"pos": [10, 36],
"link": 44,
"name": "width",
"type": "INT",
"widget": { "name": "width" }
},
{
"pos": [10, 60],
"link": 45,
"name": "height",
"type": "INT",
"widget": { "name": "height" }
}
],
"bgcolor": "#535",
"outputs": [
{ "name": "LATENT", "type": "LATENT", "links": [23], "slot_index": 0 }
],
"properties": { "Node name for S&R": "EmptyLatentImage" },
"widgets_values": [1024, 1024, 1]
},
{
"id": 26,
"pos": [41.60395812988281, 517.059326171875],
"mode": 0,
"size": [336, 288],
"type": "Note",
"color": "#432",
"flags": {},
"order": 3,
"inputs": [],
"bgcolor": "#653",
"outputs": [],
"properties": { "text": "" },
"widgets_values": [
"If you get an error in any of the nodes above make sure the files are in the correct directories.\n\nSee the top of the examples page for the links : https://comfyanonymous.github.io/ComfyUI_examples/flux/\n\nflux1-schnell.safetensors goes in: ComfyUI/models/unet/\n\nt5xxl_fp16.safetensors and clip_l.safetensors go in: ComfyUI/models/clip/\n\nae.safetensors goes in: ComfyUI/models/vae/\n\n\nTip: You can set the weight_dtype above to one of the fp8 types if you have memory issues."
]
},
{
"id": 11,
"pos": [45.584651947021484, 229.13525390625],
"mode": 0,
"size": [315, 122],
"type": "DualCLIPLoader",
"flags": {},
"order": 4,
"inputs": [],
"outputs": [
{
"name": "CLIP",
"type": "CLIP",
"links": [10],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "DualCLIPLoader" },
"widgets_values": [
"t5xxl_fp16.safetensors",
"clip_l.safetensors",
"flux",
"default"
]
},
{
"id": 12,
"pos": [45.92215347290039, 95.6536865234375],
"mode": 0,
"size": [315, 82],
"type": "UNETLoader",
"color": "#223",
"flags": { "pinned": true },
"order": 5,
"inputs": [],
"bgcolor": "#335",
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [38, 39],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "UNETLoader" },
"widgets_values": ["flux1-schnell.safetensors", "default"]
},
{
"id": 6,
"pos": [385.87054443359375, 216.75625610351562],
"mode": 0,
"size": [422.84503173828125, 164.31304931640625],
"type": "CLIPTextEncode",
"color": "#232",
"flags": {},
"order": 11,
"inputs": [
{ "link": 10, "name": "clip", "type": "CLIP" },
{
"pos": [10, 36],
"link": 41,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"bgcolor": "#353",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [40],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [
"a bottle with a beautiful rainbow galaxy inside it on top of a wooden table in the middle of a modern kitchen beside a plate of vegetables and mushrooms and a wine glasse that contains a planet earth with a plate with a half eaten apple pie on it"
]
},
{
"id": 10,
"pos": [42.45906066894531, 405.2187805175781],
"mode": 0,
"size": [315, 58],
"type": "VAELoader",
"flags": {},
"order": 6,
"inputs": [],
"outputs": [
{
"name": "VAE",
"type": "VAE",
"links": [12],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "VAELoader" },
"widgets_values": ["ae.sft"]
},
{
"id": 28,
"pos": [-620.3922119140625, 199.8013916015625],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 7,
"inputs": [],
"outputs": [{ "name": "text", "type": "STRING", "links": [41] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": [
"prompt",
"a bottle with a beautiful rainbow galaxy inside it on top of a wooden table in the middle of a modern kitchen beside a plate of vegetables and mushrooms and a wine glasse that contains a planet earth with a plate with a half eaten apple pie on it",
"Prompt",
"The prompt to generate an image from."
]
},
{
"id": 29,
"pos": [-677.4290161132812, 597.3389282226562],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 8,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [44], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["width", 1024, "Width", "The width of the image."]
},
{
"id": 30,
"pos": [-670.0703735351562, 848.3707885742188],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 9,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [45], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["height", 1024, "Height", "The height of the image."]
}
],
"config": {},
"groups": [
{
"id": 1,
"color": "#3f789e",
"flags": {},
"title": "Input",
"bounding": [
-652.184326171875, 99.11231994628906, 565.7923583984375,
362.8800354003906
],
"font_size": 24
},
{
"id": 2,
"color": "#A88",
"flags": {},
"title": "Additional",
"bounding": [
-720.3274536132812, 508.1206970214844, 703.0422973632812,
576.5584716796875
],
"font_size": 24
}
],
"version": 0.4,
"last_link_id": 45,
"last_node_id": 30
}
-482
View File
@@ -1,482 +0,0 @@
{
"extra": {
"ds": {
"scale": 0.6830134553650709,
"offset": [1030.9627343190857, 159.73178253107423]
},
"groupNodes": {},
"node_versions": {
"comfy-core": "0.3.12",
"comfyui-deploy": "b3df94d1affcf7ce05ee7eeda99989194bcd9159"
}
},
"links": [
[19, 16, 0, 13, 2, "SAMPLER"],
[20, 17, 0, 13, 3, "SIGMAS"],
[30, 22, 0, 13, 1, "GUIDER"],
[37, 25, 0, 13, 0, "NOISE"],
[129, 26, 0, 22, 1, "CONDITIONING"],
[175, 44, 0, 26, 0, "CONDITIONING"],
[180, 45, 0, 13, 4, "LATENT"],
[181, 13, 0, 8, 0, "LATENT"],
[190, 12, 0, 17, 0, "MODEL"],
[195, 67, 0, 22, 0, "MODEL"],
[205, 11, 0, 44, 0, "CLIP"],
[206, 10, 0, 8, 1, "VAE"],
[209, 12, 0, 67, 0, "MODEL"],
[210, 13, 0, 73, 0, "LATENT"],
[211, 10, 0, 73, 1, "VAE"],
[215, 73, 0, 75, 0, "IMAGE"],
[216, 78, 0, 44, 1, "STRING"],
[217, 79, 0, 45, 0, "INT"],
[218, 83, 0, 45, 1, "INT"]
],
"nodes": [
{
"id": 16,
"pos": [484, 751],
"mode": 0,
"size": [315, 58],
"type": "KSamplerSelect",
"flags": {},
"order": 0,
"inputs": [],
"outputs": [
{ "name": "SAMPLER", "type": "SAMPLER", "links": [19], "shape": 3 }
],
"properties": { "Node name for S&R": "KSamplerSelect" },
"widgets_values": ["euler"]
},
{
"id": 17,
"pos": [478, 860],
"mode": 0,
"size": [315, 106],
"type": "BasicScheduler",
"flags": {},
"order": 10,
"inputs": [
{ "link": 190, "name": "model", "type": "MODEL", "slot_index": 0 }
],
"outputs": [
{ "name": "SIGMAS", "type": "SIGMAS", "links": [20], "shape": 3 }
],
"properties": { "Node name for S&R": "BasicScheduler" },
"widgets_values": ["simple", 20, 1]
},
{
"id": 26,
"pos": [520, 100],
"mode": 0,
"size": [317.4000244140625, 58],
"type": "FluxGuidance",
"color": "#233",
"flags": {},
"order": 14,
"inputs": [
{ "link": 175, "name": "conditioning", "type": "CONDITIONING" }
],
"bgcolor": "#355",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [129],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "FluxGuidance" },
"widgets_values": [6]
},
{
"id": 45,
"pos": [475.540771484375, 432.673583984375],
"mode": 0,
"size": [315, 130],
"type": "EmptyHunyuanLatentVideo",
"flags": {},
"order": 13,
"inputs": [
{
"link": 217,
"name": "width",
"type": "INT",
"widget": { "name": "width" }
},
{
"link": 218,
"name": "height",
"type": "INT",
"widget": { "name": "height" }
}
],
"outputs": [
{ "name": "LATENT", "type": "LATENT", "links": [180], "slot_index": 0 }
],
"properties": { "Node name for S&R": "EmptyHunyuanLatentVideo" },
"widgets_values": [848, 480, 73, 1]
},
{
"id": 22,
"pos": [600, 0],
"mode": 0,
"size": [222.3482666015625, 46],
"type": "BasicGuider",
"flags": {},
"order": 15,
"inputs": [
{ "link": 195, "name": "model", "type": "MODEL", "slot_index": 0 },
{
"link": 129,
"name": "conditioning",
"type": "CONDITIONING",
"slot_index": 1
}
],
"outputs": [
{
"name": "GUIDER",
"type": "GUIDER",
"links": [30],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "BasicGuider" },
"widgets_values": []
},
{
"id": 67,
"pos": [360, 0],
"mode": 0,
"size": [210, 58],
"type": "ModelSamplingSD3",
"flags": {},
"order": 11,
"inputs": [{ "link": 209, "name": "model", "type": "MODEL" }],
"outputs": [
{ "name": "MODEL", "type": "MODEL", "links": [195], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ModelSamplingSD3" },
"widgets_values": [7]
},
{
"id": 73,
"pos": [1150, 200],
"mode": 0,
"size": [210, 150],
"type": "VAEDecodeTiled",
"flags": {},
"order": 18,
"inputs": [
{ "link": 210, "name": "samples", "type": "LATENT" },
{ "link": 211, "name": "vae", "type": "VAE" }
],
"outputs": [
{ "name": "IMAGE", "type": "IMAGE", "links": [215], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAEDecodeTiled" },
"widgets_values": [256, 64, 64, 8]
},
{
"id": 8,
"pos": [1150, 90],
"mode": 2,
"size": [210, 46],
"type": "VAEDecode",
"flags": {},
"order": 17,
"inputs": [
{ "link": 181, "name": "samples", "type": "LATENT" },
{ "link": 206, "name": "vae", "type": "VAE" }
],
"outputs": [
{ "name": "IMAGE", "type": "IMAGE", "links": [], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAEDecode" },
"widgets_values": []
},
{
"id": 77,
"pos": [0, 0],
"mode": 0,
"size": [350, 110],
"type": "Note",
"color": "#432",
"flags": {},
"order": 1,
"inputs": [],
"bgcolor": "#653",
"outputs": [],
"properties": {},
"widgets_values": [
"Select a fp8 weight_dtype if you are running out of memory."
]
},
{
"id": 13,
"pos": [860, 200],
"mode": 0,
"size": [272.3617858886719, 124.53733825683594],
"type": "SamplerCustomAdvanced",
"flags": {},
"order": 16,
"inputs": [
{ "link": 37, "name": "noise", "type": "NOISE", "slot_index": 0 },
{ "link": 30, "name": "guider", "type": "GUIDER", "slot_index": 1 },
{ "link": 19, "name": "sampler", "type": "SAMPLER", "slot_index": 2 },
{ "link": 20, "name": "sigmas", "type": "SIGMAS", "slot_index": 3 },
{
"link": 180,
"name": "latent_image",
"type": "LATENT",
"slot_index": 4
}
],
"outputs": [
{
"name": "output",
"type": "LATENT",
"links": [181, 210],
"shape": 3,
"slot_index": 0
},
{
"name": "denoised_output",
"type": "LATENT",
"links": null,
"shape": 3
}
],
"properties": { "Node name for S&R": "SamplerCustomAdvanced" },
"widgets_values": []
},
{
"id": 75,
"pos": [1410, 200],
"mode": 0,
"size": [315, 366],
"type": "SaveAnimatedWEBP",
"flags": {},
"order": 19,
"inputs": [{ "link": 215, "name": "images", "type": "IMAGE" }],
"outputs": [],
"properties": {},
"widgets_values": ["ComfyUI", 24, false, 80, "default"]
},
{
"id": 25,
"pos": [479, 618],
"mode": 0,
"size": [315, 82],
"type": "RandomNoise",
"color": "#2a363b",
"flags": {},
"order": 2,
"inputs": [],
"bgcolor": "#3f5159",
"outputs": [
{ "name": "NOISE", "type": "NOISE", "links": [37], "shape": 3 }
],
"properties": { "Node name for S&R": "RandomNoise" },
"widgets_values": [1, "randomize"]
},
{
"id": 12,
"pos": [0, 150],
"mode": 0,
"size": [350, 82],
"type": "UNETLoader",
"color": "#223",
"flags": {},
"order": 3,
"inputs": [],
"bgcolor": "#335",
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [190, 209],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "UNETLoader" },
"widgets_values": ["hunyuan_video_t2v_720p_bf16.safetensors", "default"]
},
{
"id": 10,
"pos": [0, 420],
"mode": 0,
"size": [350, 60],
"type": "VAELoader",
"flags": {},
"order": 4,
"inputs": [],
"outputs": [
{
"name": "VAE",
"type": "VAE",
"links": [206, 211],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "VAELoader" },
"widgets_values": ["hunyuan_video_vae_bf16.safetensors"]
},
{
"id": 11,
"pos": [0, 270],
"mode": 0,
"size": [350, 106],
"type": "DualCLIPLoader",
"flags": {},
"order": 5,
"inputs": [],
"outputs": [
{
"name": "CLIP",
"type": "CLIP",
"links": [205],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "DualCLIPLoader" },
"widgets_values": [
"clip_l.safetensors",
"llava_llama3_fp8_scaled.safetensors",
"hunyuan_video",
"default"
]
},
{
"id": 44,
"pos": [459.0518798828125, 226.60147094726562],
"mode": 0,
"size": [285.6000061035156, 54],
"type": "CLIPTextEncode",
"color": "#232",
"flags": {},
"order": 12,
"title": "CLIP Text Encode (Positive Prompt)",
"inputs": [
{ "link": 205, "name": "clip", "type": "CLIP" },
{
"link": 216,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"bgcolor": "#353",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [175],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [
"anime style anime girl with massive fennec ears and one big fluffy tail, she has blonde hair long hair blue eyes wearing a pink sweater and a long blue skirt walking in a beautiful outdoor scenery with snow mountains in the background"
]
},
{
"id": 83,
"pos": [-591.1870727539062, 751.6737670898438],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 6,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [218], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["height", 480, "Height", "The height of the video."]
},
{
"id": 74,
"pos": [1151.89599609375, 402.439697265625],
"mode": 0,
"size": [210, 170],
"type": "Note",
"color": "#432",
"flags": {},
"order": 7,
"inputs": [],
"bgcolor": "#653",
"outputs": [],
"properties": {},
"widgets_values": [
"Use the tiled decode node by default because most people will need it.\n\nLower the tile_size and overlap if you run out of memory."
]
},
{
"id": 78,
"pos": [-560.058837890625, 155.3986358642578],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 8,
"inputs": [],
"outputs": [{ "name": "text", "type": "STRING", "links": [216] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": [
"prompt",
"anime style anime girl with massive fennec ears and one big fluffy tail, she has blonde hair long hair blue eyes wearing a pink sweater and a long blue skirt walking in a beautiful outdoor scenery with snow mountains in the background",
"Prompt",
"The prompt to generate the video from."
]
},
{
"id": 79,
"pos": [-588.2138061523438, 493.3861389160156],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 9,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [217], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["width", 848, "Width", "The width of the video."]
}
],
"config": {},
"groups": [
{
"id": 1,
"color": "#3f789e",
"flags": {},
"title": "Input",
"bounding": [
-662.9779052734375, 14.93773078918457, 575.2218627929688,
384.41424560546875
],
"font_size": 24
},
{
"id": 2,
"color": "#b06634",
"flags": {},
"title": "Additional",
"bounding": [
-659.7621459960938, 414.3213195800781, 570.7182006835938,
594.72216796875
],
"font_size": 24
}
],
"version": 0.4,
"last_link_id": 218,
"last_node_id": 83
}
-240
View File
@@ -1,240 +0,0 @@
{
"extra": {
"ds": { "scale": 1, "offset": { "0": 0, "1": 0 } },
"node_versions": {
"comfy-core": "0.3.12",
"comfyui-deploy": "171a227856bd5f31e97828d89f83f3741004d05e"
}
},
"links": [
[1, 4, 0, 3, 0, "MODEL"],
[2, 5, 0, 3, 3, "LATENT"],
[3, 4, 1, 6, 0, "CLIP"],
[4, 6, 0, 3, 1, "CONDITIONING"],
[5, 4, 1, 7, 0, "CLIP"],
[6, 7, 0, 3, 2, "CONDITIONING"],
[7, 3, 0, 8, 0, "LATENT"],
[8, 4, 2, 8, 1, "VAE"],
[9, 8, 0, 9, 0, "IMAGE"],
[10, 12, 0, 6, 1, "STRING"],
[11, 13, 0, 7, 1, "STRING"]
],
"nodes": [
{
"id": 5,
"pos": [473, 609],
"mode": 0,
"size": [315, 106],
"type": "EmptyLatentImage",
"flags": {},
"order": 0,
"inputs": [],
"outputs": [
{ "name": "LATENT", "type": "LATENT", "links": [2], "slot_index": 0 }
],
"properties": { "Node name for S&R": "EmptyLatentImage" },
"widgets_values": [512, 512, 1]
},
{
"id": 3,
"pos": [863, 186],
"mode": 0,
"size": [315, 262],
"type": "KSampler",
"flags": {},
"order": 7,
"inputs": [
{ "link": 1, "name": "model", "type": "MODEL" },
{ "link": 4, "name": "positive", "type": "CONDITIONING" },
{ "link": 6, "name": "negative", "type": "CONDITIONING" },
{ "link": 2, "name": "latent_image", "type": "LATENT" }
],
"outputs": [
{ "name": "LATENT", "type": "LATENT", "links": [7], "slot_index": 0 }
],
"properties": { "Node name for S&R": "KSampler" },
"widgets_values": [
156680208700286,
"randomize",
20,
8,
"euler",
"normal",
1
]
},
{
"id": 8,
"pos": [1209, 188],
"mode": 0,
"size": [210, 46],
"type": "VAEDecode",
"flags": {},
"order": 8,
"inputs": [
{ "link": 7, "name": "samples", "type": "LATENT" },
{ "link": 8, "name": "vae", "type": "VAE" }
],
"outputs": [
{ "name": "IMAGE", "type": "IMAGE", "links": [9], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAEDecode" },
"widgets_values": []
},
{
"id": 9,
"pos": [1451, 189],
"mode": 0,
"size": [210, 58],
"type": "SaveImage",
"flags": {},
"order": 9,
"inputs": [{ "link": 9, "name": "images", "type": "IMAGE" }],
"outputs": [],
"properties": {},
"widgets_values": ["ComfyUI"]
},
{
"id": 4,
"pos": [26, 474],
"mode": 0,
"size": [315, 98],
"type": "CheckpointLoaderSimple",
"flags": {},
"order": 1,
"inputs": [],
"outputs": [
{ "name": "MODEL", "type": "MODEL", "links": [1], "slot_index": 0 },
{ "name": "CLIP", "type": "CLIP", "links": [3, 5], "slot_index": 1 },
{ "name": "VAE", "type": "VAE", "links": [8], "slot_index": 2 }
],
"properties": { "Node name for S&R": "CheckpointLoaderSimple" },
"widgets_values": ["v1-5-pruned-emaonly.ckpt"]
},
{
"id": 6,
"pos": [415, 186],
"mode": 0,
"size": [422.84503173828125, 164.31304931640625],
"type": "CLIPTextEncode",
"flags": {},
"order": 6,
"inputs": [
{ "link": 3, "name": "clip", "type": "CLIP" },
{
"link": 10,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [4],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
]
},
{
"id": 7,
"pos": [413, 389],
"mode": 0,
"size": [425.27801513671875, 180.6060791015625],
"type": "CLIPTextEncode",
"flags": {},
"order": 5,
"inputs": [
{ "link": 5, "name": "clip", "type": "CLIP" },
{
"link": 11,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [6],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": ["text, watermark"]
},
{
"id": 13,
"pos": [-70, -60],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 2,
"inputs": [],
"outputs": [
{
"name": "text",
"type": "STRING",
"links": [11],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": ["negative_prompt", "text, watermark", "", ""]
},
{
"id": 12,
"pos": [-72, 193],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 3,
"inputs": [],
"outputs": [
{
"name": "text",
"type": "STRING",
"links": [10],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": [
"positive_prompt",
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,",
"",
""
]
},
{
"id": 14,
"pos": [419, 23],
"mode": 0,
"size": [210, 96],
"type": "ComfyDeploy",
"color": "#432",
"flags": {},
"order": 4,
"inputs": [],
"bgcolor": "#653",
"outputs": [],
"properties": { "version": "", "workflow_id": "", "workflow_name": "" },
"widgets_values": ["", "", "1"]
}
],
"config": {},
"groups": [],
"version": 0.4,
"last_link_id": 11,
"last_node_id": 14
}
-409
View File
@@ -1,409 +0,0 @@
{
"extra": {
"ds": {
"scale": 0.620921323059155,
"offset": [1535.1422819333457, 285.0502099350181]
},
"node_versions": {
"comfy-core": "0.3.12",
"comfyui-deploy": "171a227856bd5f31e97828d89f83f3741004d05e"
}
},
"links": [
[7, 3, 0, 8, 0, "LATENT"],
[21, 16, 0, 3, 1, "CONDITIONING"],
[51, 8, 0, 9, 0, "IMAGE"],
[53, 4, 2, 8, 1, "VAE"],
[80, 40, 0, 3, 2, "CONDITIONING"],
[99, 4, 0, 3, 0, "MODEL"],
[100, 53, 0, 3, 3, "LATENT"],
[103, 43, 0, 16, 0, "CLIP"],
[104, 43, 0, 40, 0, "CLIP"],
[105, 54, 0, 16, 1, "STRING"],
[106, 55, 0, 40, 1, "STRING"],
[107, 56, 0, 53, 0, "INT"],
[108, 57, 0, 53, 1, "INT"]
],
"nodes": [
{
"id": 8,
"pos": [1200, 96],
"mode": 0,
"size": [210, 46],
"type": "VAEDecode",
"flags": {},
"order": 14,
"inputs": [
{ "link": 7, "name": "samples", "type": "LATENT" },
{ "link": 53, "name": "vae", "type": "VAE", "slot_index": 1 }
],
"outputs": [
{ "name": "IMAGE", "type": "IMAGE", "links": [51], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAEDecode" },
"widgets_values": []
},
{
"id": 9,
"pos": [1440, 96],
"mode": 0,
"size": [952.5112915039062, 1007.9328002929688],
"type": "SaveImage",
"flags": {},
"order": 15,
"inputs": [
{ "link": 51, "name": "images", "type": "IMAGE", "slot_index": 0 }
],
"outputs": [],
"properties": {},
"widgets_values": ["ComfyUI"]
},
{
"id": 53,
"pos": [480, 576],
"mode": 0,
"size": [315, 106],
"type": "EmptySD3LatentImage",
"flags": {},
"order": 10,
"inputs": [
{
"link": 107,
"name": "width",
"type": "INT",
"widget": { "name": "width" }
},
{
"link": 108,
"name": "height",
"type": "INT",
"widget": { "name": "height" }
}
],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [100],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "EmptySD3LatentImage" },
"widgets_values": [1024, 1024, 1]
},
{
"id": 50,
"pos": [-384, 144],
"mode": 0,
"size": [223.34756469726562, 254.37765502929688],
"type": "Note",
"color": "#432",
"flags": {},
"order": 0,
"inputs": [],
"bgcolor": "#653",
"outputs": [],
"properties": { "text": "" },
"widgets_values": [
"SD3 supports different text encoder configurations, you can see how to load them here.\n\n\nMake sure to put these files:\nclip_g.safetensors\nclip_l.safetensors\nt5xxl_fp16.safetensors\n\n\nIn the ComfyUI/models/clip directory"
]
},
{
"id": 41,
"pos": [-96, 0],
"mode": 0,
"size": [315, 82],
"type": "CLIPLoader",
"flags": {},
"order": 1,
"inputs": [],
"outputs": [
{
"name": "CLIP",
"type": "CLIP",
"links": [],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPLoader" },
"widgets_values": ["t5xxl_fp16.safetensors", "sd3", "default"]
},
{
"id": 4,
"pos": [-96, 480],
"mode": 0,
"size": [384.75592041015625, 98],
"type": "CheckpointLoaderSimple",
"flags": {},
"order": 2,
"inputs": [],
"outputs": [
{ "name": "MODEL", "type": "MODEL", "links": [99], "slot_index": 0 },
{ "name": "CLIP", "type": "CLIP", "links": [], "slot_index": 1 },
{ "name": "VAE", "type": "VAE", "links": [53], "slot_index": 2 }
],
"properties": { "Node name for S&R": "CheckpointLoaderSimple" },
"widgets_values": ["sd3.5_large.safetensors"]
},
{
"id": 3,
"pos": [864, 96],
"mode": 0,
"size": [315, 474],
"type": "KSampler",
"flags": {},
"order": 13,
"inputs": [
{ "link": 99, "name": "model", "type": "MODEL", "slot_index": 0 },
{ "link": 21, "name": "positive", "type": "CONDITIONING" },
{ "link": 80, "name": "negative", "type": "CONDITIONING" },
{ "link": 100, "name": "latent_image", "type": "LATENT" }
],
"outputs": [
{ "name": "LATENT", "type": "LATENT", "links": [7], "slot_index": 0 }
],
"properties": { "Node name for S&R": "KSampler" },
"widgets_values": [
797639488625463,
"randomize",
20,
5.45,
"euler",
"sgm_uniform",
1
]
},
{
"id": 51,
"pos": [-96, 624],
"mode": 0,
"size": [384, 192],
"type": "Note",
"color": "#432",
"flags": {},
"order": 3,
"inputs": [],
"bgcolor": "#653",
"outputs": [],
"properties": { "text": "" },
"widgets_values": [
"sd3.5_large.safetensors and sd3.5_medium.safetensors are files that do not contain any CLIP/text encoder weights so you need to load them separately.\n\nThey go in the ComfyUI/models/checkpoints directory."
]
},
{
"id": 43,
"pos": [-96, 288],
"mode": 0,
"size": [315, 106],
"type": "TripleCLIPLoader",
"flags": {},
"order": 4,
"inputs": [],
"outputs": [
{
"name": "CLIP",
"type": "CLIP",
"links": [103, 104],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "TripleCLIPLoader" },
"widgets_values": [
"clip_l.safetensors",
"clip_g.safetensors",
"t5xxl_fp16.safetensors"
]
},
{
"id": 42,
"pos": [-96, 144],
"mode": 0,
"size": [315, 106],
"type": "DualCLIPLoader",
"flags": {},
"order": 5,
"inputs": [],
"outputs": [
{
"name": "CLIP",
"type": "CLIP",
"links": [],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "DualCLIPLoader" },
"widgets_values": [
"clip_l.safetensors",
"clip_g.safetensors",
"sd3",
"default"
]
},
{
"id": 40,
"pos": [399.0046081542969, 337.009765625],
"mode": 0,
"size": [397.45977783203125, 151.2898406982422],
"type": "CLIPTextEncode",
"color": "#322",
"flags": {},
"order": 11,
"title": "Negative Prompt",
"inputs": [
{ "link": 104, "name": "clip", "type": "CLIP" },
{
"link": 106,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"bgcolor": "#533",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [80],
"shape": 3,
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [""]
},
{
"id": 16,
"pos": [398.5880432128906, 108.27188110351562],
"mode": 0,
"size": [397.21484375, 158.671875],
"type": "CLIPTextEncode",
"color": "#232",
"flags": {},
"order": 12,
"title": "Positive Prompt",
"inputs": [
{ "link": 103, "name": "clip", "type": "CLIP" },
{
"link": 105,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"bgcolor": "#353",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [21],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [
"a bottle with a rainbow galaxy inside it on top of a wooden table on a snowy mountain top with the ocean and clouds in the background with a shot glass beside containing darkness beside a snow sculpture in the shape of a fox"
]
},
{
"id": 57,
"pos": [-1015.1683349609375, 980.396240234375],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 6,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [108], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["height", 1024, "Height", "The height of the image. "]
},
{
"id": 56,
"pos": [-1014.532470703125, 732.8568725585938],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 7,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [107], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["width", 1024, "Width", "The width of the image. "]
},
{
"id": 55,
"pos": [-1010.8035278320312, 487.404052734375],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 8,
"inputs": [],
"outputs": [{ "name": "text", "type": "STRING", "links": [106] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": ["negative_prompt", "", "Negative Prompt", ""]
},
{
"id": 54,
"pos": [-1059.1072998046875, 127.12823486328125],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 9,
"inputs": [],
"outputs": [{ "name": "text", "type": "STRING", "links": [105] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": [
"prompt",
"a bottle with a rainbow galaxy inside it on top of a wooden table on a snowy mountain top with the ocean and clouds in the background with a shot glass beside containing darkness beside a snow sculpture in the shape of a fox",
"Prompt",
"The prompt to generate an image from."
]
}
],
"config": {},
"groups": [
{
"id": 1,
"color": "#3f789e",
"flags": {},
"title": "Different Text Encoder Configurations",
"bounding": [-144, -96, 480, 528],
"font_size": 24
},
{
"id": 2,
"color": "#b06634",
"flags": {},
"title": "Additional",
"bounding": [
-1194.5233154296875, 388.3871154785156, 722.5393676757812,
824.6746215820312
],
"font_size": 24
},
{
"id": 3,
"color": "#3f789e",
"flags": {},
"title": "Input",
"bounding": [
-1148.487060546875, 30.449382781982422, 552.3358764648438,
329.3829040527344
],
"font_size": 24
}
],
"version": 0.4,
"last_link_id": 108,
"last_node_id": 57
}
-452
View File
@@ -1,452 +0,0 @@
{
"extra": {
"ds": {
"scale": 0.6934334949441662,
"offset": [276.7941771713029, -7.923387380923855]
},
"node_versions": {
"comfy-core": "0.3.18",
"comfyui-deploy": "b3df94d1affcf7ce05ee7eeda99989194bcd9159"
}
},
"links": [
[35, 3, 0, 8, 0, "LATENT"],
[56, 8, 0, 28, 0, "IMAGE"],
[74, 38, 0, 6, 0, "CLIP"],
[75, 38, 0, 7, 0, "CLIP"],
[76, 39, 0, 8, 1, "VAE"],
[93, 8, 0, 47, 0, "IMAGE"],
[94, 49, 0, 51, 0, "CLIP_VISION"],
[97, 6, 0, 50, 0, "CONDITIONING"],
[98, 7, 0, 50, 1, "CONDITIONING"],
[99, 39, 0, 50, 2, "VAE"],
[101, 50, 0, 3, 1, "CONDITIONING"],
[102, 50, 1, 3, 2, "CONDITIONING"],
[103, 50, 2, 3, 3, "LATENT"],
[107, 51, 0, 50, 3, "CLIP_VISION_OUTPUT"],
[110, 37, 0, 54, 0, "MODEL"],
[111, 54, 0, 3, 0, "MODEL"],
[112, 55, 0, 6, 1, "STRING"],
[113, 56, 0, 7, 1, "STRING"],
[115, 57, 0, 50, 4, "IMAGE"],
[116, 57, 0, 51, 1, "IMAGE"],
[117, 58, 0, 50, 5, "INT"],
[118, 59, 0, 50, 6, "INT"]
],
"nodes": [
{
"id": 8,
"pos": [1210, 190],
"mode": 0,
"size": [210, 46],
"type": "VAEDecode",
"flags": {},
"order": 15,
"inputs": [
{ "link": 35, "name": "samples", "type": "LATENT" },
{ "link": 76, "name": "vae", "type": "VAE" }
],
"outputs": [
{ "name": "IMAGE", "type": "IMAGE", "links": [56, 93], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAEDecode" },
"widgets_values": []
},
{
"id": 39,
"pos": [866.3932495117188, 499.18597412109375],
"mode": 0,
"size": [306.36004638671875, 58],
"type": "VAELoader",
"flags": {},
"order": 0,
"inputs": [],
"outputs": [
{ "name": "VAE", "type": "VAE", "links": [76, 99], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAELoader" },
"widgets_values": ["wan_2.1_vae.safetensors"]
},
{
"id": 28,
"pos": [1460, 190],
"mode": 0,
"size": [870.8511352539062, 643.7430419921875],
"type": "SaveAnimatedWEBP",
"flags": {},
"order": 16,
"inputs": [{ "link": 56, "name": "images", "type": "IMAGE" }],
"outputs": [],
"properties": {},
"widgets_values": ["ComfyUI", 16, false, 90, "default", ""]
},
{
"id": 47,
"pos": [2367.213134765625, 193.6114959716797],
"mode": 4,
"size": [315, 130],
"type": "SaveWEBM",
"flags": {},
"order": 17,
"inputs": [{ "link": 93, "name": "images", "type": "IMAGE" }],
"outputs": [],
"properties": { "Node name for S&R": "SaveWEBM" },
"widgets_values": ["ComfyUI", "vp9", 24, 32]
},
{
"id": 50,
"pos": [673.0507202148438, 627.272705078125],
"mode": 0,
"size": [342.5999755859375, 250],
"type": "WanImageToVideo",
"flags": {},
"order": 13,
"inputs": [
{ "link": 97, "name": "positive", "type": "CONDITIONING" },
{ "link": 98, "name": "negative", "type": "CONDITIONING" },
{ "link": 99, "name": "vae", "type": "VAE" },
{
"link": 107,
"name": "clip_vision_output",
"type": "CLIP_VISION_OUTPUT",
"shape": 7
},
{ "link": 115, "name": "start_image", "type": "IMAGE", "shape": 7 },
{
"pos": [10, 116],
"link": 117,
"name": "width",
"type": "INT",
"widget": { "name": "width" }
},
{
"pos": [10, 140],
"link": 118,
"name": "height",
"type": "INT",
"widget": { "name": "height" }
}
],
"outputs": [
{
"name": "positive",
"type": "CONDITIONING",
"links": [101],
"slot_index": 0
},
{
"name": "negative",
"type": "CONDITIONING",
"links": [102],
"slot_index": 1
},
{ "name": "latent", "type": "LATENT", "links": [103], "slot_index": 2 }
],
"properties": { "Node name for S&R": "WanImageToVideo" },
"widgets_values": [512, 512, 33, 1]
},
{
"id": 3,
"pos": [863, 187],
"mode": 0,
"size": [315, 262],
"type": "KSampler",
"flags": {},
"order": 14,
"inputs": [
{ "link": 111, "name": "model", "type": "MODEL" },
{ "link": 101, "name": "positive", "type": "CONDITIONING" },
{ "link": 102, "name": "negative", "type": "CONDITIONING" },
{ "link": 103, "name": "latent_image", "type": "LATENT" }
],
"outputs": [
{ "name": "LATENT", "type": "LATENT", "links": [35], "slot_index": 0 }
],
"properties": { "Node name for S&R": "KSampler" },
"widgets_values": [
55104841546759,
"randomize",
20,
6,
"uni_pc",
"simple",
1
]
},
{
"id": 51,
"pos": [360, 640],
"mode": 0,
"size": [253.60000610351562, 78],
"type": "CLIPVisionEncode",
"flags": {},
"order": 12,
"inputs": [
{ "link": 94, "name": "clip_vision", "type": "CLIP_VISION" },
{ "link": 116, "name": "image", "type": "IMAGE" }
],
"outputs": [
{
"name": "CLIP_VISION_OUTPUT",
"type": "CLIP_VISION_OUTPUT",
"links": [107],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPVisionEncode" },
"widgets_values": ["none"]
},
{
"id": 54,
"pos": [510, 70],
"mode": 0,
"size": [315, 58],
"type": "ModelSamplingSD3",
"flags": {},
"order": 9,
"inputs": [{ "link": 110, "name": "model", "type": "MODEL" }],
"outputs": [
{ "name": "MODEL", "type": "MODEL", "links": [111], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ModelSamplingSD3" },
"widgets_values": [8]
},
{
"id": 6,
"pos": [415, 186],
"mode": 0,
"size": [422.84503173828125, 164.31304931640625],
"type": "CLIPTextEncode",
"color": "#232",
"flags": {},
"order": 10,
"title": "CLIP Text Encode (Positive Prompt)",
"inputs": [
{ "link": 74, "name": "clip", "type": "CLIP" },
{
"pos": [10, 36],
"link": 112,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"bgcolor": "#353",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [97],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [
"a cute anime girl with massive fennec ears and a big fluffy tail wearing a maid outfit turning around"
]
},
{
"id": 55,
"pos": [-672.6411743164062, 140.167724609375],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 1,
"inputs": [],
"outputs": [{ "name": "text", "type": "STRING", "links": [112] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": [
"positive_prompt",
"a cute anime girl with massive fennec ears and a big fluffy tail wearing a maid outfit turning around",
"Prompt",
"The text prompt to guide video generation."
]
},
{
"id": 57,
"pos": [-664.3828125, 405.5113525390625],
"mode": 0,
"size": [390.5999755859375, 366],
"type": "ComfyUIDeployExternalImage",
"flags": {},
"order": 2,
"inputs": [
{ "link": null, "name": "default_value", "type": "IMAGE", "shape": 7 }
],
"outputs": [{ "name": "image", "type": "IMAGE", "links": [115, 116] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalImage" },
"widgets_values": [
"image_url",
"Image Url",
"URL of the input image.",
"https://comfy-deploy-output.s3.us-east-2.amazonaws.com/assets/img_GZMJYXDnLbYjWybu.png",
""
]
},
{
"id": 56,
"pos": [-674.42333984375, 953.0498046875],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 3,
"inputs": [],
"outputs": [{ "name": "text", "type": "STRING", "links": [113] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": [
"negative_prompt",
"色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走",
"Negative Prompt",
"The negative prompt to use. Use it to address details that you don't want in the video. This could be colors, objects, scenery and even the small details (e.g. moustache, blurry, low resolution). "
]
},
{
"id": 58,
"pos": [-668.314453125, 1208.204833984375],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 4,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [117], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["width", 512, "Width", "The width of the video. "]
},
{
"id": 59,
"pos": [-665.8831787109375, 1461.255126953125],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 5,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [118], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["height", 512, "Height", "The Height of the video."]
},
{
"id": 37,
"pos": [-3.3700287342071533, 81.69654846191406],
"mode": 0,
"size": [346.7470703125, 82],
"type": "UNETLoader",
"flags": {},
"order": 6,
"inputs": [],
"outputs": [
{ "name": "MODEL", "type": "MODEL", "links": [110], "slot_index": 0 }
],
"properties": { "Node name for S&R": "UNETLoader" },
"widgets_values": ["wan2.1_i2v_480p_14B_bf16.safetensors", "default"]
},
{
"id": 38,
"pos": [-3.7316977977752686, 230.76495361328125],
"mode": 0,
"size": [390, 98],
"type": "CLIPLoader",
"flags": {},
"order": 7,
"inputs": [],
"outputs": [
{ "name": "CLIP", "type": "CLIP", "links": [74, 75], "slot_index": 0 }
],
"properties": { "Node name for S&R": "CLIPLoader" },
"widgets_values": [
"umt5_xxl_fp8_e4m3fn_scaled.safetensors",
"wan",
"default"
]
},
{
"id": 49,
"pos": [16.57183265686035, 640.22314453125],
"mode": 0,
"size": [315, 58],
"type": "CLIPVisionLoader",
"flags": {},
"order": 8,
"inputs": [],
"outputs": [
{
"name": "CLIP_VISION",
"type": "CLIP_VISION",
"links": [94],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPVisionLoader" },
"widgets_values": ["clip_vision_h.safetensors"]
},
{
"id": 7,
"pos": [414.1811828613281, 393.8824768066406],
"mode": 0,
"size": [425.27801513671875, 180.6060791015625],
"type": "CLIPTextEncode",
"color": "#322",
"flags": {},
"order": 11,
"title": "CLIP Text Encode (Negative Prompt)",
"inputs": [
{ "link": 75, "name": "clip", "type": "CLIP" },
{
"pos": [10, 36],
"link": 113,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"bgcolor": "#533",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [98],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [
"色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走"
]
}
],
"config": {},
"groups": [
{
"id": 1,
"color": "#3f789e",
"flags": {},
"title": "Input",
"bounding": [
-708.2940063476562, 47.549102783203125, 617.7969360351562,
761.303955078125
],
"font_size": 24
},
{
"id": 2,
"color": "#b06634",
"flags": {},
"title": "Additional",
"bounding": [
-703.6196899414062, 861.310791015625, 625.998779296875,
845.0675048828125
],
"font_size": 24
}
],
"version": 0.4,
"last_link_id": 118,
"last_node_id": 59
}
-452
View File
@@ -1,452 +0,0 @@
{
"extra": {
"ds": {
"scale": 0.6303940863128795,
"offset": [-209.31226203277674, -32.62073943929215]
},
"node_versions": {
"comfy-core": "0.3.18",
"comfyui-deploy": "b3df94d1affcf7ce05ee7eeda99989194bcd9159"
}
},
"links": [
[1, 6, 0, 1, 0, "LATENT"],
[2, 2, 0, 1, 1, "VAE"],
[3, 1, 0, 3, 0, "IMAGE"],
[4, 1, 0, 4, 0, "IMAGE"],
[5, 9, 0, 5, 0, "CONDITIONING"],
[6, 18, 0, 5, 1, "CONDITIONING"],
[7, 2, 0, 5, 2, "VAE"],
[8, 7, 0, 5, 3, "CLIP_VISION_OUTPUT"],
[9, 11, 0, 5, 4, "IMAGE"],
[10, 13, 0, 5, 5, "INT"],
[11, 14, 0, 5, 6, "INT"],
[12, 8, 0, 6, 0, "MODEL"],
[13, 5, 0, 6, 1, "CONDITIONING"],
[14, 5, 1, 6, 2, "CONDITIONING"],
[15, 5, 2, 6, 3, "LATENT"],
[16, 17, 0, 7, 0, "CLIP_VISION"],
[17, 11, 0, 7, 1, "IMAGE"],
[18, 15, 0, 8, 0, "MODEL"],
[19, 16, 0, 9, 0, "CLIP"],
[20, 10, 0, 9, 1, "STRING"],
[21, 16, 0, 18, 0, "CLIP"],
[22, 12, 0, 18, 1, "STRING"]
],
"nodes": [
{
"id": 1,
"pos": [1823.98876953125, 702.6244506835938],
"mode": 0,
"size": [210, 46],
"type": "VAEDecode",
"flags": {},
"order": 15,
"inputs": [
{ "link": 1, "name": "samples", "type": "LATENT" },
{ "link": 2, "name": "vae", "type": "VAE" }
],
"outputs": [
{ "name": "IMAGE", "type": "IMAGE", "links": [3, 4], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAEDecode" },
"widgets_values": []
},
{
"id": 2,
"pos": [1480.382080078125, 1011.8104248046875],
"mode": 0,
"size": [306.36004638671875, 58],
"type": "VAELoader",
"flags": {},
"order": 0,
"inputs": [],
"outputs": [
{ "name": "VAE", "type": "VAE", "links": [2, 7], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAELoader" },
"widgets_values": ["wan_2.1_vae.safetensors"]
},
{
"id": 3,
"pos": [2073.98876953125, 702.6244506835938],
"mode": 0,
"size": [870.8511352539062, 643.7430419921875],
"type": "SaveAnimatedWEBP",
"flags": {},
"order": 16,
"inputs": [{ "link": 3, "name": "images", "type": "IMAGE" }],
"outputs": [],
"properties": {},
"widgets_values": ["ComfyUI", 16, false, 90, "default", ""]
},
{
"id": 4,
"pos": [2981.201904296875, 706.2359008789062],
"mode": 4,
"size": [315, 130],
"type": "SaveWEBM",
"flags": {},
"order": 17,
"inputs": [{ "link": 4, "name": "images", "type": "IMAGE" }],
"outputs": [],
"properties": { "Node name for S&R": "SaveWEBM" },
"widgets_values": ["ComfyUI", "vp9", 24, 32]
},
{
"id": 5,
"pos": [1287.03955078125, 1139.8970947265625],
"mode": 0,
"size": [342.5999755859375, 250],
"type": "WanImageToVideo",
"flags": {},
"order": 13,
"inputs": [
{ "link": 5, "name": "positive", "type": "CONDITIONING" },
{ "link": 6, "name": "negative", "type": "CONDITIONING" },
{ "link": 7, "name": "vae", "type": "VAE" },
{
"link": 8,
"name": "clip_vision_output",
"type": "CLIP_VISION_OUTPUT",
"shape": 7
},
{ "link": 9, "name": "start_image", "type": "IMAGE", "shape": 7 },
{
"pos": [10, 116],
"link": 10,
"name": "width",
"type": "INT",
"widget": { "name": "width" }
},
{
"pos": [10, 140],
"link": 11,
"name": "height",
"type": "INT",
"widget": { "name": "height" }
}
],
"outputs": [
{
"name": "positive",
"type": "CONDITIONING",
"links": [13],
"slot_index": 0
},
{
"name": "negative",
"type": "CONDITIONING",
"links": [14],
"slot_index": 1
},
{ "name": "latent", "type": "LATENT", "links": [15], "slot_index": 2 }
],
"properties": { "Node name for S&R": "WanImageToVideo" },
"widgets_values": [512, 512, 33, 1]
},
{
"id": 6,
"pos": [1476.98876953125, 699.6244506835938],
"mode": 0,
"size": [315, 262],
"type": "KSampler",
"flags": {},
"order": 14,
"inputs": [
{ "link": 12, "name": "model", "type": "MODEL" },
{ "link": 13, "name": "positive", "type": "CONDITIONING" },
{ "link": 14, "name": "negative", "type": "CONDITIONING" },
{ "link": 15, "name": "latent_image", "type": "LATENT" }
],
"outputs": [
{ "name": "LATENT", "type": "LATENT", "links": [1], "slot_index": 0 }
],
"properties": { "Node name for S&R": "KSampler" },
"widgets_values": [
625624384968868,
"randomize",
20,
6,
"uni_pc",
"simple",
1
]
},
{
"id": 7,
"pos": [973.98876953125, 1152.6243896484375],
"mode": 0,
"size": [253.60000610351562, 78],
"type": "CLIPVisionEncode",
"flags": {},
"order": 10,
"inputs": [
{ "link": 16, "name": "clip_vision", "type": "CLIP_VISION" },
{ "link": 17, "name": "image", "type": "IMAGE" }
],
"outputs": [
{
"name": "CLIP_VISION_OUTPUT",
"type": "CLIP_VISION_OUTPUT",
"links": [8],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPVisionEncode" },
"widgets_values": ["none"]
},
{
"id": 8,
"pos": [1123.98876953125, 582.6244506835938],
"mode": 0,
"size": [315, 58],
"type": "ModelSamplingSD3",
"flags": {},
"order": 11,
"inputs": [{ "link": 18, "name": "model", "type": "MODEL" }],
"outputs": [
{ "name": "MODEL", "type": "MODEL", "links": [12], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ModelSamplingSD3" },
"widgets_values": [8]
},
{
"id": 9,
"pos": [1028.98876953125, 698.6244506835938],
"mode": 0,
"size": [422.84503173828125, 164.31304931640625],
"type": "CLIPTextEncode",
"color": "#232",
"flags": {},
"order": 12,
"title": "CLIP Text Encode (Positive Prompt)",
"inputs": [
{ "link": 19, "name": "clip", "type": "CLIP" },
{
"pos": [10, 36],
"link": 20,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"bgcolor": "#353",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [5],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [
"a cute anime girl with massive fennec ears and a big fluffy tail wearing a maid outfit turning around"
]
},
{
"id": 11,
"pos": [-50.3940315246582, 918.1358032226562],
"mode": 0,
"size": [390.5999755859375, 366],
"type": "ComfyUIDeployExternalImage",
"flags": {},
"order": 1,
"inputs": [
{ "link": null, "name": "default_value", "type": "IMAGE", "shape": 7 }
],
"outputs": [{ "name": "image", "type": "IMAGE", "links": [9, 17] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalImage" },
"widgets_values": [
"image_url",
"Image Url",
"URL of the input image.",
"https://comfy-deploy-output.s3.us-east-2.amazonaws.com/assets/img_GZMJYXDnLbYjWybu.png",
""
]
},
{
"id": 12,
"pos": [-60.4345588684082, 1465.6741943359375],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 2,
"inputs": [],
"outputs": [{ "name": "text", "type": "STRING", "links": [22] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": [
"negative_prompt",
"色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走",
"Negative Prompt",
"The negative prompt to use. Use it to address details that you don't want in the video. This could be colors, objects, scenery and even the small details (e.g. moustache, blurry, low resolution). "
]
},
{
"id": 13,
"pos": [-54.3256721496582, 1720.8292236328125],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 3,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [10], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["width", 512, "Width", "The width of the video. "]
},
{
"id": 14,
"pos": [-51.8943977355957, 1973.8795166015625],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 4,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [11], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["height", 512, "Height", "The Height of the video."]
},
{
"id": 16,
"pos": [610.257080078125, 743.389404296875],
"mode": 0,
"size": [390, 98],
"type": "CLIPLoader",
"flags": {},
"order": 5,
"inputs": [],
"outputs": [
{ "name": "CLIP", "type": "CLIP", "links": [19, 21], "slot_index": 0 }
],
"properties": { "Node name for S&R": "CLIPLoader" },
"widgets_values": [
"umt5_xxl_fp8_e4m3fn_scaled.safetensors",
"wan",
"default"
]
},
{
"id": 17,
"pos": [630.5606079101562, 1152.8475341796875],
"mode": 0,
"size": [315, 58],
"type": "CLIPVisionLoader",
"flags": {},
"order": 6,
"inputs": [],
"outputs": [
{
"name": "CLIP_VISION",
"type": "CLIP_VISION",
"links": [16],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPVisionLoader" },
"widgets_values": ["clip_vision_h.safetensors"]
},
{
"id": 18,
"pos": [1028.169921875, 906.5068969726562],
"mode": 0,
"size": [425.27801513671875, 180.6060791015625],
"type": "CLIPTextEncode",
"color": "#322",
"flags": {},
"order": 9,
"title": "CLIP Text Encode (Negative Prompt)",
"inputs": [
{ "link": 21, "name": "clip", "type": "CLIP" },
{
"pos": [10, 36],
"link": 22,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"bgcolor": "#533",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [6],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [
"色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走"
]
},
{
"id": 15,
"pos": [610.6187744140625, 594.3209838867188],
"mode": 0,
"size": [346.7470703125, 82],
"type": "UNETLoader",
"flags": {},
"order": 7,
"inputs": [],
"outputs": [
{ "name": "MODEL", "type": "MODEL", "links": [18], "slot_index": 0 }
],
"properties": { "Node name for S&R": "UNETLoader" },
"widgets_values": ["wan2.1_i2v_720p_14B_bf16.safetensors", "default"]
},
{
"id": 10,
"pos": [-60.696964263916016, 649.5515747070312],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 8,
"inputs": [],
"outputs": [{ "name": "text", "type": "STRING", "links": [20] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": [
"positive_prompt",
"a cute anime girl with massive fennec ears and a big fluffy tail wearing a maid outfit running towards front happily",
"Prompt",
"The text prompt to guide video generation."
]
}
],
"config": {},
"groups": [
{
"id": 1,
"color": "#3f789e",
"flags": {},
"title": "Input",
"bounding": [
-94.30522155761719, 560.1735229492188, 617.7969360351562,
761.303955078125
],
"font_size": 24
},
{
"id": 2,
"color": "#b06634",
"flags": {},
"title": "Additional",
"bounding": [
-89.63090515136719, 1373.9351806640625, 625.998779296875,
845.0675048828125
],
"font_size": 24
}
],
"version": 0.4,
"last_link_id": 22,
"last_node_id": 18
}
-359
View File
@@ -1,359 +0,0 @@
{
"extra": {
"ds": {
"scale": 0.8390545288824369,
"offset": [814.3725295729478, -347.90757575249455]
},
"node_versions": {
"comfy-core": "0.3.18",
"comfyui-deploy": "b3df94d1affcf7ce05ee7eeda99989194bcd9159"
}
},
"links": [
[35, 3, 0, 8, 0, "LATENT"],
[46, 6, 0, 3, 1, "CONDITIONING"],
[52, 7, 0, 3, 2, "CONDITIONING"],
[56, 8, 0, 28, 0, "IMAGE"],
[74, 38, 0, 6, 0, "CLIP"],
[75, 38, 0, 7, 0, "CLIP"],
[76, 39, 0, 8, 1, "VAE"],
[91, 40, 0, 3, 3, "LATENT"],
[93, 8, 0, 47, 0, "IMAGE"],
[94, 37, 0, 48, 0, "MODEL"],
[95, 48, 0, 3, 0, "MODEL"],
[96, 49, 0, 6, 1, "STRING"],
[97, 50, 0, 7, 1, "STRING"],
[99, 52, 0, 40, 1, "INT"],
[100, 51, 0, 40, 0, "INT"]
],
"nodes": [
{
"id": 8,
"pos": [1210, 190],
"mode": 0,
"size": [210, 46],
"type": "VAEDecode",
"flags": {},
"order": 12,
"inputs": [
{ "link": 35, "name": "samples", "type": "LATENT" },
{ "link": 76, "name": "vae", "type": "VAE" }
],
"outputs": [
{ "name": "IMAGE", "type": "IMAGE", "links": [56, 93], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAEDecode" },
"widgets_values": []
},
{
"id": 39,
"pos": [866.3932495117188, 499.18597412109375],
"mode": 0,
"size": [306.36004638671875, 58],
"type": "VAELoader",
"flags": {},
"order": 0,
"inputs": [],
"outputs": [
{ "name": "VAE", "type": "VAE", "links": [76], "slot_index": 0 }
],
"properties": { "Node name for S&R": "VAELoader" },
"widgets_values": ["wan_2.1_vae.safetensors"]
},
{
"id": 47,
"pos": [2367.213134765625, 193.6114959716797],
"mode": 4,
"size": [315, 130],
"type": "SaveWEBM",
"flags": {},
"order": 14,
"inputs": [{ "link": 93, "name": "images", "type": "IMAGE" }],
"outputs": [],
"properties": { "Node name for S&R": "SaveWEBM" },
"widgets_values": ["ComfyUI", "vp9", 24, 32]
},
{
"id": 3,
"pos": [863, 187],
"mode": 0,
"size": [315, 262],
"type": "KSampler",
"flags": {},
"order": 11,
"inputs": [
{ "link": 95, "name": "model", "type": "MODEL" },
{ "link": 46, "name": "positive", "type": "CONDITIONING" },
{ "link": 52, "name": "negative", "type": "CONDITIONING" },
{ "link": 91, "name": "latent_image", "type": "LATENT" }
],
"outputs": [
{ "name": "LATENT", "type": "LATENT", "links": [35], "slot_index": 0 }
],
"properties": { "Node name for S&R": "KSampler" },
"widgets_values": [
577746309562741,
"randomize",
30,
6,
"uni_pc",
"simple",
1
]
},
{
"id": 48,
"pos": [440, 50],
"mode": 0,
"size": [210, 58],
"type": "ModelSamplingSD3",
"flags": {},
"order": 7,
"inputs": [{ "link": 94, "name": "model", "type": "MODEL" }],
"outputs": [
{ "name": "MODEL", "type": "MODEL", "links": [95], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ModelSamplingSD3" },
"widgets_values": [8]
},
{
"id": 37,
"pos": [20, 40],
"mode": 0,
"size": [346.7470703125, 82],
"type": "UNETLoader",
"flags": {},
"order": 1,
"inputs": [],
"outputs": [
{ "name": "MODEL", "type": "MODEL", "links": [94], "slot_index": 0 }
],
"properties": { "Node name for S&R": "UNETLoader" },
"widgets_values": ["wan2.1_t2v_1.3B_fp16.safetensors", "default"]
},
{
"id": 6,
"pos": [415, 186],
"mode": 0,
"size": [422.84503173828125, 164.31304931640625],
"type": "CLIPTextEncode",
"color": "#232",
"flags": {},
"order": 8,
"title": "CLIP Text Encode (Positive Prompt)",
"inputs": [
{ "link": 74, "name": "clip", "type": "CLIP" },
{
"pos": [10, 36],
"link": 96,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"bgcolor": "#353",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [46],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [
"a fox moving quickly in a beautiful winter scenery nature trees mountains daytime tracking camera"
]
},
{
"id": 7,
"pos": [413, 389],
"mode": 0,
"size": [425.27801513671875, 180.6060791015625],
"type": "CLIPTextEncode",
"color": "#322",
"flags": {},
"order": 9,
"title": "CLIP Text Encode (Negative Prompt)",
"inputs": [
{ "link": 75, "name": "clip", "type": "CLIP" },
{
"pos": [10, 36],
"link": 97,
"name": "text",
"type": "STRING",
"widget": { "name": "text" }
}
],
"bgcolor": "#533",
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [52],
"slot_index": 0
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [
"色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走"
]
},
{
"id": 38,
"pos": [-10.047812461853027, 187.37384033203125],
"mode": 0,
"size": [390, 98],
"type": "CLIPLoader",
"flags": {},
"order": 2,
"inputs": [],
"outputs": [
{ "name": "CLIP", "type": "CLIP", "links": [74, 75], "slot_index": 0 }
],
"properties": { "Node name for S&R": "CLIPLoader" },
"widgets_values": [
"umt5_xxl_fp8_e4m3fn_scaled.safetensors",
"wan",
"default"
]
},
{
"id": 49,
"pos": [-535.2967529296875, 342.3277587890625],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 3,
"inputs": [],
"outputs": [{ "name": "text", "type": "STRING", "links": [96] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": [
"positive_prompt",
"a fox moving quickly in a beautiful winter scenery nature trees mountains daytime tracking camera",
"Prompt",
"The text prompt to guide video generation. "
]
},
{
"id": 50,
"pos": [-526.2716064453125, 703.8343505859375],
"mode": 0,
"size": [400, 200],
"type": "ComfyUIDeployExternalText",
"flags": {},
"order": 4,
"inputs": [],
"outputs": [{ "name": "text", "type": "STRING", "links": [97] }],
"properties": { "Node name for S&R": "ComfyUIDeployExternalText" },
"widgets_values": [
"negative_prompt",
"色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走",
"Negative Prompt",
"The negative prompt to use. Use it to address details that you don't want in the image. This could be colors, objects, scenery and even the small details (e.g. moustache, blurry, low resolution). "
]
},
{
"id": 40,
"pos": [516.926513671875, 619.59716796875],
"mode": 0,
"size": [315, 150],
"type": "EmptyHunyuanLatentVideo",
"flags": {},
"order": 10,
"inputs": [
{
"pos": [10, 36],
"link": 100,
"name": "width",
"type": "INT",
"widget": { "name": "width" }
},
{
"pos": [10, 60],
"link": 99,
"name": "height",
"type": "INT",
"widget": { "name": "height" }
}
],
"outputs": [
{ "name": "LATENT", "type": "LATENT", "links": [91], "slot_index": 0 }
],
"properties": { "Node name for S&R": "EmptyHunyuanLatentVideo" },
"widgets_values": [832, 480, 33, 1]
},
{
"id": 28,
"pos": [1460, 190],
"mode": 0,
"size": [870.8511352539062, 643.7430419921875],
"type": "SaveAnimatedWEBP",
"flags": {},
"order": 13,
"inputs": [{ "link": 56, "name": "images", "type": "IMAGE" }],
"outputs": [],
"properties": {},
"widgets_values": ["ComfyUI", 16, false, 90, "default"]
},
{
"id": 51,
"pos": [-522.7415161132812, 959.3386840820312],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 5,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [100], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["width", 832, "Width", "The Width of the Video. "]
},
{
"id": 52,
"pos": [-518.9917602539062, 1207.9444580078125],
"mode": 0,
"size": [453.5999755859375, 200],
"type": "ComfyUIDeployExternalNumberInt",
"flags": {},
"order": 6,
"inputs": [],
"outputs": [
{ "name": "value", "type": "INT", "links": [99], "slot_index": 0 }
],
"properties": { "Node name for S&R": "ComfyUIDeployExternalNumberInt" },
"widgets_values": ["height", 480, "Height", "The Height of the Video. "]
}
],
"config": {},
"groups": [
{
"id": 1,
"color": "#3f789e",
"flags": {},
"title": "Inputs",
"bounding": [
-560.9110717773438, 255.1485595703125, 500.94989013671875,
333.4786682128906
],
"font_size": 24
},
{
"id": 2,
"color": "#b06634",
"flags": {},
"title": "Additional",
"bounding": [
-556.5305786132812, 619.87548828125, 761.2673950195312,
811.6837768554688
],
"font_size": 24
}
],
"version": 0.4,
"last_link_id": 100,
"last_node_id": 52
}
+17 -37
View File
@@ -6,12 +6,10 @@ from PIL import Image, ImageOps
from io import BytesIO
from pydantic import BaseModel as PydanticBaseModel
class BaseModel(PydanticBaseModel):
class Config:
arbitrary_types_allowed = True
class Status(Enum):
NOT_STARTED = "not-started"
RUNNING = "running"
@@ -19,7 +17,6 @@ class Status(Enum):
FAILED = "failed"
UPLOADING = "uploading"
class StreamingPrompt(BaseModel):
workflow_api: Any
auth_token: str
@@ -27,52 +24,42 @@ class StreamingPrompt(BaseModel):
running_prompt_ids: set[str] = set()
status_endpoint: Optional[str]
file_upload_endpoint: Optional[str]
workflow: Any
gpu_event_id: Optional[str] = None
class SimplePrompt(BaseModel):
status_endpoint: Optional[str]
file_upload_endpoint: Optional[str]
token: Optional[str]
workflow_api: dict
status: Status = Status.NOT_STARTED
progress: set = set()
last_updated_node: Optional[str] = None
last_updated_node: Optional[str] = None,
uploading_nodes: set = set()
done: bool = False
is_realtime: bool = False
start_time: Optional[float] = None
gpu_event_id: Optional[str] = None
is_realtime: bool = False,
start_time: Optional[float] = None,
sockets = dict()
prompt_metadata: dict[str, SimplePrompt] = {}
streaming_prompt_metadata: dict[str, StreamingPrompt] = {}
class BinaryEventTypes:
PREVIEW_IMAGE = 1
UNENCODED_PREVIEW_IMAGE = 2
max_output_id_length = 24
async def send_image(image_data, sid=None, output_id: str = None):
async def send_image(image_data, sid=None, output_id:str = None):
max_length = max_output_id_length
output_id = output_id[:max_length]
padded_output_id = output_id.ljust(max_length, "\x00")
encoded_output_id = padded_output_id.encode("ascii", "replace")
padded_output_id = output_id.ljust(max_length, '\x00')
encoded_output_id = padded_output_id.encode('ascii', 'replace')
image_type = image_data[0]
image = image_data[1]
max_size = image_data[2]
quality = image_data[3]
if max_size is not None:
if hasattr(Image, "Resampling"):
if hasattr(Image, 'Resampling'):
resampling = Image.Resampling.BILINEAR
else:
resampling = Image.ANTIALIAS
@@ -96,23 +83,17 @@ async def send_image(image_data, sid=None, output_id: str = None):
position_after = bytesIO.tell()
bytes_written = position_after - position_before
print(f"Bytes written: {bytes_written}")
image.save(bytesIO, format=image_type, quality=quality, compress_level=1)
preview_bytes = bytesIO.getvalue()
await send_bytes(BinaryEventTypes.PREVIEW_IMAGE, preview_bytes, sid=sid)
async def send_socket_catch_exception(function, message):
try:
await function(message)
except (
aiohttp.ClientError,
aiohttp.ClientPayloadError,
ConnectionResetError,
) as err:
except (aiohttp.ClientError, aiohttp.ClientPayloadError, ConnectionResetError) as err:
print("send error:", err)
def encode_bytes(event, data):
if not isinstance(event, int):
raise RuntimeError(f"Binary event types must be integers, got {event}")
@@ -122,10 +103,9 @@ def encode_bytes(event, data):
message.extend(data)
return message
async def send_bytes(event, data, sid=None):
message = encode_bytes(event, data)
print("sending image to ", event, sid)
if sid is None:
@@ -133,4 +113,4 @@ async def send_bytes(event, data, sid=None):
for ws in _sockets:
await send_socket_catch_exception(ws.send_bytes, message)
elif sid in sockets:
await send_socket_catch_exception(sockets[sid].send_bytes, message)
await send_socket_catch_exception(sockets[sid].send_bytes, message)
+3 -3
View File
@@ -1,9 +1,9 @@
[project]
name = "comfyui-deploy"
description = "Open source comfyui deployment platform, a vercel for generative workflow infra."
version = "2.2.1"
license = { file = "LICENSE" }
dependencies = ["aiofiles", "pydantic", "opencv-python", "imageio-ffmpeg", "tabulate", "brotli"]
version = "1.0.0"
license = "LICENSE"
dependencies = ["aiofiles", "pydantic", "opencv-python", "imageio-ffmpeg"]
[project.urls]
Repository = "https://github.com/BennyKok/comfyui-deploy"
-1
View File
@@ -3,5 +3,4 @@ pydantic
opencv-python
imageio-ffmpeg
brotli
tabulate
# logfire
+4
View File
@@ -0,0 +1,4 @@
/** @typedef {import('../../../web/scripts/api.js').api} API*/
import { api as _api } from '../../scripts/api.js';
/** @type {API} */
export const api = _api;
+4
View File
@@ -0,0 +1,4 @@
/** @typedef {import('../../../web/scripts/app.js').ComfyApp} ComfyApp*/
import { app as _app } from '../../scripts/app.js';
/** @type {ComfyApp} */
export const app = _app;
+295 -1307
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
// /** @typedef {import('../../../web/scripts/api.js').api} API*/
// import { api as _api } from "../../scripts/api.js";
// /** @type {API} */
// export const api = _api;
/** @typedef {typeof import('../../../web/scripts/widgets.js').ComfyWidgets} Widgets*/
import { ComfyWidgets as _ComfyWidgets } from "../../scripts/widgets.js";
/**
* @type {Widgets}
*/
export const ComfyWidgets = _ComfyWidgets;
// import { LGraphNode as _LGraphNode } from "../../types/litegraph.js";
/** @typedef {typeof import('../../../web/types/litegraph.js').LGraphNode} LGraphNode*/
/** @type {LGraphNode}*/
export const LGraphNode = LiteGraph.LGraphNode;
-387
View File
@@ -1,387 +0,0 @@
// Workflow list management
let workflowsState = {
workflows: [],
offset: 0,
limit: 20,
loading: false,
hasMore: true,
initialized: false,
currentSearch: "",
};
// Make workflowsState accessible globally
window.workflowsState = workflowsState;
async function fetchWorkflows(getData, offset = 0, limit = 20, search = "") {
try {
const data = getData();
if (!data.apiKey) {
throw new Error("API key not configured");
}
const params = new URLSearchParams({
offset: offset.toString(),
limit: limit.toString(),
api_url: data.apiUrl || "https://api.comfydeploy.com",
...(search && { search }),
});
const response = await fetch(`/comfyui-deploy/workflows?${params}`, {
method: "GET",
headers: {
Authorization: `Bearer ${data.apiKey}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error(`Failed to fetch workflows: ${response.status}`);
}
const result = await response.json();
console.log("result", result);
return Array.isArray(result) ? result : [];
} catch (error) {
console.error("Error fetching workflows:", error);
return [];
}
}
function createWorkflowItem(workflow, getTimeAgo, getData) {
const li = document.createElement("li");
li.style.cssText = `
border-bottom: 1px solid #444;
background: transparent;
transition: all 0.2s ease;
cursor: pointer;
`;
li.addEventListener("mouseenter", () => {
li.style.background = "#333";
});
li.addEventListener("mouseleave", () => {
li.style.background = "transparent";
});
// Add click handler to fetch and load workflow data
li.addEventListener("click", async () => {
try {
const data = getData();
if (!data.apiKey) {
console.error("No API key configured");
return;
}
// Show loading toast
const loadingToast = window.app.extensionManager.toast.add({
severity: "info",
summary: "Loading workflow...",
detail: `Loading "${workflow.name}"`,
life: 3000,
});
const params = new URLSearchParams({
workflow_id: workflow.id,
api_url: data.apiUrl || "https://api.comfydeploy.com",
});
const response = await fetch(`/comfyui-deploy/workflow?${params}`, {
method: "GET",
headers: {
Authorization: `Bearer ${data.apiKey}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error(`Failed to fetch workflow: ${response.status}`);
}
const workflowData = await response.json();
console.log("Workflow data:", workflowData);
// Load the workflow into the graph
if (workflowData.versions && workflowData.versions.length > 0) {
const latestVersion = workflowData.versions[0];
if (latestVersion.workflow && window.app) {
// Load the workflow
window.app.loadGraphData(latestVersion.workflow);
// Show success toast
window.app.extensionManager.toast.add({
severity: "success",
summary: "Workflow loaded successfully",
detail: `Loaded "${workflow.name}" v${latestVersion.version}`,
life: 3000,
});
}
}
} catch (error) {
console.error("Error loading workflow:", error);
// Show error toast
window.app.extensionManager.toast.add({
severity: "error",
summary: "Failed to load workflow",
detail: error.message,
life: 5000,
});
} finally {
loadingToast.close();
}
});
const updatedDate = new Date(workflow.updated_at);
const timeAgo = getTimeAgo(updatedDate);
li.innerHTML = `
<div style="padding: 12px 16px;">
<div style="display: flex; align-items: flex-start; gap: 12px;">
${
workflow.cover_image
? `<img src="${workflow.cover_image}"
style="width: 40px; height: 40px; border-radius: 4px; object-fit: cover; flex-shrink: 0;"
onerror="this.style.display='none'">`
: `<div style="width: 40px; height: 40px; border-radius: 4px; background: #444; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 14px; color: #888;">
${workflow.name.charAt(0).toUpperCase()}
</div>`
}
<div style="flex: 1; min-width: 0;">
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 4px;">
<h4 style="margin: 0; font-size: 14px; font-weight: 400; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
${workflow.name}
</h4>
${
workflow.pinned
? `<span style="color: #ffd700; font-size: 12px;">📌</span>`
: ""
}
</div>
${
workflow.description
? `<p style="margin: 0 0 8px 0; font-size: 12px; color: #bbb; line-height: 1.3; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;">
${workflow.description}
</p>`
: ""
}
<div style="display: flex; align-items: center; gap: 8px; margin-top: 8px;">
<img src="${workflow.user_icon}"
style="width: 16px; height: 16px; border-radius: 50%;"
onerror="this.style.display='none'">
<span style="font-size: 11px; color: #888;">
${workflow.user_name} • Updated ${timeAgo}
</span>
</div>
</div>
</div>
</div>
`;
return li;
}
async function loadMoreWorkflows(element, getData, getTimeAgo) {
if (workflowsState.loading || !workflowsState.hasMore) return;
workflowsState.loading = true;
const workflowsList = element.querySelector("#workflows-list");
const workflowsLoading = element.querySelector("#workflows-loading");
// Show loading indicator
workflowsLoading.style.display = "flex";
try {
const newWorkflows = await fetchWorkflows(
getData,
workflowsState.offset,
workflowsState.limit,
workflowsState.currentSearch
);
if (newWorkflows.length === 0) {
workflowsState.hasMore = false;
} else {
workflowsState.workflows.push(...newWorkflows);
workflowsState.offset += newWorkflows.length;
// Render new workflow items
newWorkflows.forEach((workflow) => {
const workflowItem = createWorkflowItem(workflow, getTimeAgo, getData);
workflowsList.appendChild(workflowItem);
});
}
} catch (error) {
console.error("Error loading more workflows:", error);
} finally {
workflowsState.loading = false;
workflowsLoading.style.display = "none";
}
}
function setupInfiniteScroll(container, element, getData, getTimeAgo) {
let isScrolling = false;
container.addEventListener("scroll", () => {
if (isScrolling) return;
const { scrollTop, scrollHeight, clientHeight } = container;
// Load more when scrolled to bottom (with 100px threshold)
if (scrollTop + clientHeight >= scrollHeight - 100) {
isScrolling = true;
loadMoreWorkflows(element, getData, getTimeAgo).finally(() => {
isScrolling = false;
});
}
});
}
async function initializeWorkflowsList(element, getData, getTimeAgo) {
const workflowsContainer = element.querySelector("#workflows-container");
const workflowsList = element.querySelector("#workflows-list");
const workflowsLoading = element.querySelector("#workflows-loading");
// Check if already initialized AND the DOM elements still exist
if (
workflowsState.initialized &&
workflowsList &&
workflowsList.children.length > 0
)
return;
try {
// Reset state (always reset when reinitializing)
workflowsState = {
workflows: [],
offset: 0,
limit: 20,
loading: false,
hasMore: true,
initialized: true,
currentSearch: "",
};
// Clear existing content in case of reinitialization
if (workflowsList) {
workflowsList.innerHTML = "";
}
// Show container and loading
workflowsContainer.style.display = "block";
workflowsLoading.style.display = "flex";
// Style the workflows list for full height scrolling
workflowsList.style.cssText = `
list-style-type: none;
padding: 0;
margin: 0;
height: calc(100vh - 350px);
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: #666 transparent;
border-top: 1px solid #444;
`;
// Add webkit scrollbar styles
const style = document.createElement("style");
style.textContent = `
#workflows-list::-webkit-scrollbar {
width: 6px;
}
#workflows-list::-webkit-scrollbar-track {
background: transparent;
}
#workflows-list::-webkit-scrollbar-thumb {
background: #666;
border-radius: 3px;
}
#workflows-list::-webkit-scrollbar-thumb:hover {
background: #777;
}
`;
document.head.appendChild(style);
// Setup infinite scroll
setupInfiniteScroll(workflowsList, element, getData, getTimeAgo);
// Load initial workflows
await loadMoreWorkflows(element, getData, getTimeAgo);
// Show the list
workflowsList.style.display = "block";
} catch (error) {
console.error("Error initializing workflows list:", error);
workflowsLoading.innerHTML = `
<div style="text-align: center; color: #e74c3c; font-size: 12px; padding: 20px;">
<div>Failed to load workflows</div>
<button onclick="initializeWorkflowsList(this.closest('.comfy-menu'), getData, getTimeAgo)"
style="margin-top: 8px; padding: 4px 8px; font-size: 11px; background: #f0f0f0; border: 1px solid #ccc; border-radius: 4px; cursor: pointer;">
Retry
</button>
</div>
`;
}
}
// Search functionality
function addWorkflowSearch(element, getData, getTimeAgo) {
const workflowsContainer = element.querySelector("#workflows-container");
const h4 = workflowsContainer.querySelector("h4");
const searchContainer = document.createElement("div");
searchContainer.style.cssText = "margin-bottom: 12px;";
const searchInput = document.createElement("input");
searchInput.type = "text";
searchInput.placeholder = "Search workflows...";
searchInput.style.cssText = `
width: 100%;
padding: 8px 12px;
border: 1px solid #555;
border-radius: 6px;
font-size: 12px;
box-sizing: border-box;
background: #333;
color: #fff;
`;
let searchTimeout;
searchInput.addEventListener("input", (e) => {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(async () => {
const searchTerm = e.target.value.trim();
// Update the tracked search term
workflowsState.currentSearch = searchTerm;
// Reset state for new search
workflowsState.workflows = [];
workflowsState.offset = 0;
workflowsState.hasMore = true;
// Clear current list
const workflowsList = element.querySelector("#workflows-list");
workflowsList.innerHTML = "";
// Load with search term
workflowsState.loading = false;
await loadMoreWorkflows(element, getData, getTimeAgo);
}, 300);
});
searchContainer.appendChild(searchInput);
h4.after(searchContainer);
}
// Export the functions
export {
initializeWorkflowsList,
addWorkflowSearch,
workflowsState,
fetchWorkflows,
loadMoreWorkflows,
};
-1
View File
@@ -6,5 +6,4 @@ export const customInputNodes: Record<string, string> = {
ComfyUIDeployExternalNumberInt: "integer",
ComfyUIDeployExternalLora: "string - (public lora download url)",
ComfyUIDeployExternalCheckpoint: "string - (public checkpoints download url)",
ComfyUIDeployExternalFaceModel: "string - (public face model download url)",
};