ComfyUI 完全指南
第一章:ComfyUI 基础入门
1.1 什么是 ComfyUI?
| 概念名称 | 说明 | 注意事项 |
|---|
| ComfyUI | 一个基于节点的工作流图形界面工具,用于构建和执行 Stable Diffusion 等生成式 AI 模型的推理流程。 | 不是传统 GUI 图像生成器,而是可视化编程环境。 |
| 节点(Node) | 工作流中的基本功能单元,每个节点封装特定操作(如加载模型、生成图像、调整参数等)。 | 节点之间通过数据端口连接,形成执行图。 |
| 工作流(Workflow) | 由多个节点及其连接关系构成的完整推理流程,可保存为 JSON 文件。 | 工作流具有确定性,相同输入 + 相同节点配置 = 相同输出。 |
| 非破坏性编辑 | 所有操作均可随时修改、重连、替换,不影响原始模型或数据。 | 鼓励实验性搭建,无需担心”覆盖”结果。 |
| 开源与可扩展性 | ComfyUI 完全开源(MIT 许可),支持社区开发的自定义节点插件。 | 插件质量参差不齐,需注意来源安全性。 |
1.2 安装与启动 ComfyUI
| 步骤名称 | 操作细节 | 注意事项 |
|---|
| 克隆官方仓库 | 在终端执行:git clone https://github.com/comfyanonymous/ComfyUI.git | 需预先安装 Git;建议使用稳定分支(main)。 |
| 安装 Python 依赖 | 进入 ComfyUI 目录后执行:pip install -r requirements.txt | 推荐使用 Python 3.10 或 3.11;避免系统全局 pip。 |
| 下载模型文件 | 将 Stable Diffusion 模型(如 .ckpt 或 .safetensors)放入 models/checkpoints/ 目录 | 模型需用户自行提供,不可直接分发。 |
| 启动 ComfyUI 服务 | 在终端执行:python main.py | 默认监听 http://127.0.0.1:8188;首次启动会自动下载部分依赖(如 torch)。 |
| 配置启动参数(可选) | 例如:python main.py --listen 0.0.0.0 --port 8080 | --listen 0.0.0.0 允许局域网访问;注意防火墙设置。 |
| 使用虚拟环境(推荐) | 创建并激活虚拟环境后再安装依赖,例如:python -m venv comfy_env && source comfy_env/bin/activate(Linux/macOS) | Windows 用户使用 comfy_env\Scripts\activate |
1.3 界面概览与基本操作
| 操作名称 | 操作细节 | 注意事项 |
|---|
| 添加节点 | 右键画布空白处 → 选择节点类别(如 Loaders、Samplers)→ 点击具体节点类型 | 也可通过快捷键 Ctrl+Space(Windows/Linux)或 Cmd+Space(macOS)打开搜索菜单。 |
| 移动画布 | 按住空格键 + 鼠标左键拖动 | 类似 Photoshop 导航方式。 |
| 连接节点端口 | 从一个节点的输出端口(右侧圆点)拖拽到另一个节点的输入端口(左侧圆点) | 仅当数据类型兼容时才能连接(如 IMAGE → IMAGE)。 |
| 断开连接 | 点击已连接的连线中间的小圆点,或拖拽连线末端离开端口 | 无法直接删除单根连线,需通过断开操作。 |
| 执行工作流 | 点击顶部工具栏的 “Queue Prompt” 按钮 | 必须存在至少一个 “KSampler” 或等效执行节点,且输入完整。 |
| 查看生成结果 | 结果自动显示在 “Preview Image” 节点或 “Save Image” 节点输出区域 | 若无预览节点,需手动添加。 |
| 删除节点 | 选中节点后按 Delete 键 | 支持多选(框选或 Shift+点击)。 |
| 保存工作流 | 点击顶部 “Save” 按钮(软盘图标),保存为 .json 文件 | 仅保存节点结构与参数,不包含模型或图像数据。 |
| 加载工作流 | 点击顶部 “Load” 按钮(文件夹图标),选择已保存的 .json 文件 | 若缺少对应模型或自定义节点,可能报错或显示缺失节点。 |
| 自动布局(Auto Arrange) | 右键画布 → 选择 “Auto Arrange” | 有助于整理复杂工作流,但可能不完全符合用户逻辑顺序。 |
第二章:工作流(Workflow)构建基础
2.1 节点(Node)类型与功能分类
| 节点类别 | 说明 | 典型节点示例 | 注意事项 |
|---|
| 加载器类(Loaders) | 用于加载模型、VAE、Lora、文本编码器等资源 | Load Checkpoint, Load VAE, Load Lora | 模型路径需正确;部分节点自动缓存以提升性能。 |
| 采样器类(Samplers) | 执行扩散过程的核心推理节点,控制生成质量与步数 | KSampler, KSampler Advanced | 必须连接正/负提示词和潜在空间输入;Advanced 版支持更细粒度控制。 |
| 编码/解码类 | 将图像转为潜在表示(Encode)或将潜在表示还原为图像(Decode) | CLIP Text Encode, VAEEncode, VAEDecode | CLIP 编码器输出 conditioning,非图像数据。 |
| 图像处理类 | 对生成图像进行后处理,如缩放、裁剪、遮罩合成等 | Image Scale, Image Crop, MaskComposite | 输入必须是 IMAGE 类型;部分节点支持批处理。 |
| 条件控制类 | 提供 ControlNet、T2I-Adapter、IP-Adapter 等高级控制信号 | ControlNet Apply, IPAdapter Apply | 需先加载对应 ControlNet 模型;图像尺寸需匹配主图。 |
| 实用工具类 | 包括常量、数学运算、列表操作、调试输出等辅助功能 | Primitive, Math, Preview Image, Show Text | Primitive 节点可作为参数占位符;Preview 不影响流程执行。 |
| 自定义节点 | 由社区或用户开发的扩展节点,功能多样 | Impact Pack, WAS Node Suite 等 | 需手动安装插件;版本兼容性需注意。 |
2.2 连接节点:数据流与执行顺序
| 概念/操作名称 | 说明 | 示例/细节 | 注意事项 |
|---|
| 数据端口(Port) | 节点左侧为输入端口,右侧为输出端口;每个端口有明确数据类型(如 IMAGE、LATENT、CONDITIONING) | CLIP Text Encode 输出 CONDITIONING → KSampler 的 positive 输入 | 类型不匹配时无法连接,系统会提示错误。 |
| 执行依赖关系 | ComfyUI 按数据依赖自动推导执行顺序,无需手动指定流程 | 先执行 Load Checkpoint,再执行 KSampler | 无输入依赖的节点不会被执行。 |
| 多输入合并 | 某些节点支持多个同类型输入(如多个 Lora 叠加) | Load Lora → Model Merge(需通过特定节点实现叠加) | 并非所有节点支持多输入;需使用 ModelMerge 或 Apply Lora 链式调用。 |
| 分支与复用 | 一个输出端口可连接到多个输入端口(广播) | 一个 KSampler 输出 IMAGE 可同时连到 Save Image 和 Image Scale | 数据会被复制,不影响原始值。 |
| 循环与递归限制 | ComfyUI 不支持显式循环结构;工作流为有向无环图(DAG) | 无法将节点输出直接或间接连回自身输入 | 若需迭代效果,需借助外部脚本或多次执行。 |
| 惰性求值机制 | 仅执行生成最终输出所必需的节点路径 | 若删除 Save Image 节点且无其他输出,整个流程可能不执行 | 调试时建议保留 Preview Image 或 Save Image 节点。 |
2.3 保存、加载与分享工作流
| 操作名称 | 操作细节 | 示例/用途 | 注意事项 |
|---|
| 保存为 JSON | 点击顶部工具栏 “Save” 按钮(软盘图标),文件扩展名为 .json | workflow_v1.json | 仅包含节点配置、连接关系和参数,不含模型、图像或自定义节点代码。 |
| 加载 JSON 工作流 | 点击 “Load” 按钮(文件夹图标),选择本地 .json 文件 | 可恢复之前构建的复杂流程 | 若缺少对应模型或插件节点,会显示红色”缺失节点”占位符。 |
| 导出带资源的工作流(非官方) | 使用第三方插件(如 ComfyUI-Manager)打包模型引用信息 | 生成附带 model_info.json 的压缩包 | 官方不支持自动打包模型,需手动管理依赖。 |
| 分享工作流 | 将 .json 文件上传至社区平台(如 OpenArt、Civitai、GitHub Gist) | 供他人复现相同生成效果 | 建议在描述中注明所需模型名称、版本及插件依赖。 |
| 工作流版本兼容性 | ComfyUI 更新可能导致旧工作流节点参数变化或废弃 | 新版中某些节点重命名(如 “KSampler” → 保留但内部逻辑优化) | 建议定期备份工作流;重大更新前测试兼容性。 |
| 清理未连接节点 | 右键画布 → “Clean Unconnected Nodes” | 移除调试残留或废弃节点,使工作流更清晰 | 不影响已连接的有效流程。 |
| 工作流注释与分组 | 使用 “Note” 节点添加文字说明;或使用 “Reroute” 整理连线 | 在复杂流程中标注模块功能(如 “Face Refinement Section”) | Note 节点不影响执行;Reroute 可减少连线交叉。 |
第三章:常用内置节点详解
3.1 加载器节点(Loaders)
| 方法名称 | 语法(输入参数 → 输出) | 用途 | 代码示例(节点配置片段) | 注意事项 |
|---|
| Load Checkpoint | 输入:ckpt_name(str);输出:MODEL, CLIP, VAE | 加载完整 Stable Diffusion 模型 | "class_type": "CheckpointLoaderSimple", "inputs": {"ckpt_name": "realisticVisionV60B1_v60B1VAE.safetensors"} | 模型需位于 models/checkpoints/;首次加载较慢,后续缓存加速。 |
| Load VAE | 输入:vae_name(str);输出:VAE | 单独加载 VAE 解码器 | "class_type": "VAELoader", "inputs": {"vae_name": "vae-ft-mse-840000-ema-pruned.safetensors"} | 可替换 checkpoint 自带的 VAE 以改善细节或修复色偏。 |
| Load Lora | 输入:lora_name(str), strength_model(float), strength_clip(float);输出:MODEL, CLIP | 加载并应用 LoRA 微调权重 | "class_type": "LoraLoader", "inputs": {"lora_name": "add_detail.safetensors", "strength_model": 1.0, "strength_clip": 1.0} | 需先连接基础模型;多个 LoRA 需链式加载。 |
| Load Textual Inversion | 输入:embedding_name(str);输出:CLIP | 加载嵌入向量(如 .pt/.bin)用于提示词扩展 | "class_type": "TextualInversionLoader", "inputs": {"embedding_name": "badhandv4.pt"} | 嵌入文件需放在 models/embeddings/;仅影响 CLIP 编码。 |
| Load ControlNet Model | 输入:control_net_name(str);输出:CONTROL_NET | 加载 ControlNet 权重 | "class_type": "ControlNetLoader", "inputs": {"control_net_name": "control_canny-fp16.safetensors"} | 必须与 Apply ControlNet 节点配合使用。 |
| Load Upscale Model | 输入:model_name(str);输出:UPSCALE_MODEL | 加载 ESRGAN/SwinIR 等超分模型 | "class_type": "UpscaleModelLoader", "inputs": {"model_name": "RealESRGAN_x4plus.pth"} | 用于 Image Upscale (Model) 节点。 |
3.2 模型推理节点(Models & Samplers)
| 方法名称 | 语法(输入参数 → 输出) | 用途 | 代码示例(节点配置片段) | 注意事项 |
|---|
| KSampler | 输入:model, seed, steps, cfg, sampler_name, scheduler, positive, negative, latent_image;输出:LATENT | 标准扩散采样器 | "class_type": "KSampler", "inputs": {"seed": 12345, "steps": 20, "cfg": 7.0, "sampler_name": "dpmpp_2m", "scheduler": "karras", ...} | 最常用采样节点;latent_image 通常来自 Empty Latent Image。 |
| KSampler Advanced | 输入:同上 + add_noise, start_at_step, end_at_step, return_with_leftover_noise;输出:LATENT | 高级采样器,支持分段采样与噪声控制 | "class_type": "KSamplerAdvanced", "inputs": {"add_noise": true, "start_at_step": 0, "end_at_step": 15, "return_with_leftover_noise": false} | 适用于 img2img、inpainting 或多阶段生成。 |
| CLIP Text Encode | 输入:text(str), clip;输出:CONDITIONING | 将文本提示编码为条件向量 | "class_type": "CLIPTextEncode", "inputs": {"text": "a portrait of a cat wearing sunglasses", "clip": ["4", 1]} | 正负提示需分别编码后传入 KSampler。 |
| Empty Latent Image | 输入:width(int), height(int), batch_size(int);输出:LATENT | 创建空白潜在空间张量 | "class_type": "EmptyLatentImage", "inputs": {"width": 512, "height": 768, "batch_size": 1} | 尺寸需匹配模型训练分辨率(通常 512 或 768)。 |
| VAEEncode | 输入:pixels(IMAGE), vae;输出:LATENT | 将图像编码为潜在表示(用于 img2img) | "class_type": "VAEEncode", "inputs": {"pixels": ["5", 0], "vae": ["2", 2]} | 图像需先经 Load Image 加载。 |
| VAEDecode | 输入:samples(LATENT), vae;输出:IMAGE | 将潜在表示解码为 RGB 图像 | "class_type": "VAEDecode", "inputs": {"samples": ["3", 0], "vae": ["2", 2]} | 所有生成流程最终需此节点输出可视图像。 |
3.3 图像处理与后处理节点(Image Processing)
| 方法名称 | 语法(输入参数 → 输出) | 用途 | 代码示例(节点配置片段) | 注意事项 |
|---|
| Load Image | 输入:image(str);输出:IMAGE, MASK | 从本地加载图像及透明通道遮罩 | "class_type": "LoadImage", "inputs": {"image": "input.png"} | 支持 PNG/JPG;MASK 仅当图像含 Alpha 通道时有效。 |
| Save Image | 输入:images(IMAGE), filename_prefix(str);输出:— | 保存图像到 output 目录 | "class_type": "SaveImage", "inputs": {"filename_prefix": "my_output"} | 自动编号命名;路径不可自定义(除非修改源码)。 |
| Preview Image | 输入:images(IMAGE);输出:— | 在 UI 中实时预览结果 | "class_type": "PreviewImage", "inputs": {"images": ["6", 0]} | 仅用于调试,不影响执行逻辑。 |
| Image Scale | 输入:image(IMAGE), upscale_method(str), width(int), height(int), crop(str);输出:IMAGE | 调整图像尺寸 | "class_type": "ImageScale", "inputs": {"upscale_method": "lanczos", "width": 1024, "height": 1024, "crop": "center"} | crop 可选 “disabled”, “center”, “top”, “bottom” 等。 |
| Image Crop | 输入:image(IMAGE), width(int), height(int), x(int), y(int);输出:IMAGE | 裁剪指定区域 | "class_type": "ImageCrop", "inputs": {"width": 256, "height": 256, "x": 100, "y": 100} | 坐标原点在左上角;超出边界会报错。 |
| MaskComposite | 输入:destination(IMAGE), source(IMAGE), mask(MASK), x(int), y(int), operation(str);输出:IMAGE | 将源图按遮罩合成到目标图 | "class_type": "MaskComposite", "inputs": {"operation": "add", "x": 0, "y": 0} | operation 可为 “add”, “subtract”, “multiply” 等。 |
| Image Blend | 输入:image1(IMAGE), image2(IMAGE), blend_factor(float);输出:IMAGE | 线性混合两张图像 | "class_type": "ImageBlend", "inputs": {"blend_factor": 0.5} | 两图尺寸必须一致。 |
3.4 条件与控制节点(Conditioning & Control)
| 方法名称 | 语法(输入参数 → 输出) | 用途 | 代码示例(节点配置片段) | 注意事项 |
|---|
| ControlNet Apply | 输入:conditioning(CONDITIONING), control_net(CONTROL_NET), image(IMAGE), strength(float);输出:CONDITIONING | 应用 ControlNet 控制信号 | "class_type": "ControlNetApply", "inputs": {"strength": 0.8, "image": ["7", 0], "control_net": ["8", 0], "conditioning": ["9", 0]} | image 尺寸应与生成图一致;strength 控制影响力。 |
| IPAdapter Apply | 输入:ipadapter(IPADAPTER), model(MODEL), image(IMAGE), weight(float);输出:MODEL | 应用 IP-Adapter 图像提示 | "class_type": "IPAdapterApply", "inputs": {"weight": 0.6, "image": ["10", 0]} | 需先加载 IPAdapter 模型;支持多图输入(部分实现)。 |
| Conditioning Combine | 输入:conditioning_1(CONDITIONING), conditioning_2(CONDITIONING);输出:CONDITIONING | 合并两个条件向量(如正提示+ControlNet) | "class_type": "ConditioningCombine", "inputs": {"conditioning_1": ["11", 0], "conditioning_2": ["12", 0]} | 顺序可能影响结果;通常 ControlNet 条件后合并。 |
| Conditioning Set Area | 输入:conditioning(CONDITIONING), width(int), height(int), x(int), y(int), strength(float);输出:CONDITIONING | 限制提示词作用区域 | "class_type": "ConditioningSetArea", "inputs": {"width": 256, "height": 256, "x": 100, "y": 100, "strength": 1.0} | 用于局部重绘或焦点控制。 |
| T2I-Adapter Apply | 输入:conditioning, adapter(T2I_ADAPTER), image(IMAGE), weight(float);输出:CONDITIONING | 应用 T2I-Adapter(如深度图、姿态) | "class_type": "T2IAdapterApply", "inputs": {"weight": 0.7, "image": ["13", 0]} | 需预处理输入图为对应特征图(如 Canny 边缘)。 |
| GLIGEN Apply | 输入:conditioning, gligen_model, text(str), boxes(list);输出:CONDITIONING | 在指定框内生成特定对象(GLIGEN) | "class_type": "GLIGENApply", "inputs": {"text": "a red apple", "boxes": [[0.2, 0.3, 0.4, 0.5]]} | boxes 为归一化坐标 [x1, y1, x2, y2]。 |
第四章:自定义节点开发
4.1 自定义节点结构与注册机制
| 方法/概念名称 | 语法/说明 | 用途 | 代码示例 | 注意事项 |
|---|
| 节点类定义 | 继承 comfy.nodes.PreviewImage 或直接定义函数,使用 @classmethod 装饰器 | 创建自定义功能逻辑 | 见下方代码 | 必须定义 INPUT_TYPES, RETURN_TYPES, FUNCTION, CATEGORY 四个类属性。 |
| 节点注册 | 将节点类放入 __init__.py 或通过 NODE_CLASS_MAPPINGS 显式注册 | 使 ComfyUI 能识别并加载节点 | NODE_CLASS_MAPPINGS = {"MyCustomNode": MyCustomNode};NODE_DISPLAY_NAME_MAPPINGS = {"MyCustomNode": "My Custom Node"} | 文件需放在 custom_nodes/your_plugin/ 目录下;重启 ComfyUI 生效。 |
| 插件目录结构 | custom_nodes/<插件名>/__init__.py | 标准化自定义节点组织方式 | custom_nodes/my_custom_node/ 下包含 __init__.py 和 nodes.py | 避免直接修改 ComfyUI 核心代码;便于版本管理和分享。 |
| 动态加载机制 | ComfyUI 启动时自动扫描 custom_nodes/ 下所有子目录并导入 __init__.py | 无需手动配置即可加载社区插件 | — | 插件若含语法错误会导致整个目录加载失败,建议独立测试。 |
| 节点显示名称映射 | 使用 NODE_DISPLAY_NAME_MAPPINGS 定义 UI 中显示的友好名称 | 提升用户界面可读性 | NODE_DISPLAY_NAME_MAPPINGS = {"MyCustomNode": "Uppercase Text Converter"} | 显示名可包含空格和特殊字符,不影响内部调用。 |
节点类定义代码示例:
class MyCustomNode:
@classmethod
def INPUT_TYPES(cls):
return {"required": {"text": ("STRING", {"default": "hello"})}}
RETURN_TYPES = ("STRING",)
FUNCTION = "execute"
CATEGORY = "custom/utils"
def execute(self, text):
return (text.upper(),)
4.2 输入输出定义与类型系统
| 方法/概念名称 | 语法/说明 | 用途 | 代码示例 | 注意事项 |
|---|
INPUT_TYPES 结构 | 返回字典,含 "required" 和可选 "optional" 键,值为参数名到类型+配置的映射 | 定义节点输入接口 | 见下方代码 | 支持类型包括:INT, FLOAT, STRING, BOOLEAN, IMAGE, LATENT, MODEL, CLIP, VAE, CONDITIONING, MASK 等。 |
RETURN_TYPES | 类属性,元组形式列出输出数据类型 | 声明节点输出的数据类型 | RETURN_TYPES = ("IMAGE", "MASK") | 输出顺序必须与 execute 函数返回值一致。 |
RETURN_NAMES(可选) | 类属性,为每个输出指定 UI 显示名称 | 提高工作流可读性 | RETURN_NAMES = ("processed_image", "alpha_mask") | 若未定义,默认使用 output_0, output_1… |
| 类型兼容规则 | 只有相同或兼容类型才能连接(如 IMAGE → IMAGE) | 保证数据流类型安全 | — | 自定义类型需通过全局类型系统注册(不推荐初学者使用)。 |
| 默认值与约束 | 在 INPUT_TYPES 中通过字典设置 default/min/max/step 等 | 控制参数范围与初始值 | "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}) | STRING 类型支持多行:{"default": "", "multiline": True}。 |
| 多选/下拉菜单 | 使用元组列表作为类型定义 | 提供预设选项 | "mode": (["resize", "crop", "pad"], {"default": "resize"}) | 用户只能从列表中选择,不可输入其他值。 |
INPUT_TYPES 完整示例:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": ("INT", {"default": 10, "min": 1, "max": 100})
},
"optional": {
"multiplier": ("FLOAT", {"default": 1.0})
}
}
4.3 调试与日志输出方法
| 方法/操作名称 | 语法/说明 | 用途 | 代码示例 | 注意事项 |
|---|
print() 输出 | 在 execute 方法中使用标准 Python print | 临时调试变量值 | def execute(self, text): print(f"[DEBUG] Input text: {text}"); return (text,) | 输出显示在启动 ComfyUI 的终端中;生产环境应移除。 |
logging 模块 | 使用 Python 内置 logging 记录结构化日志 | 更规范的日志管理 | import logging; logger = logging.getLogger(__name__); logger.info("Processing value: %s", x) | 需配置日志级别;默认 INFO 及以上会显示。 |
| 异常抛出 | raise ValueError 或其他异常 | 提示用户输入错误 | if value <= 0: raise ValueError("Value must be positive") | ComfyUI 会捕获异常并在 UI 中显示红色错误提示。 |
| Preview Image 调试 | 在自定义节点中返回 IMAGE 并连接 Preview Image 节点 | 可视化中间结果 | RETURN_TYPES = ("IMAGE",);图像需为 [B, H, W, C] 格式,C=3,值范围 [0,1]。 | 注意数据格式。 |
| 临时保存中间结果 | 使用 tempfile 或固定路径写入文件 | 持久化调试数据 | with open("/tmp/debug_output.txt", "w") as f: f.write(str(data)) | 注意路径跨平台兼容性;避免写入 ComfyUI 核心目录。 |
使用 comfy.utils | 调用 ComfyUI 内部工具函数(如 common_upscale) | 复用已有图像处理逻辑 | from comfy.utils import common_upscale; upscaled = common_upscale(image, 1024, 1024, "lanczos", "center") | 需了解内部 API,可能随版本变动。 |
第五章:高级功能与扩展
5.1 批处理与循环节点
| 方法/概念名称 | 语法/说明 | 用途 | 示例 | 注意事项 |
|---|
| Image Batch | 输入多个 IMAGE,自动合并为 batch 维度 | 将多张图像打包成单个批次输入模型 | 使用节点 “ImageBatch”:连接 image1, image2 → 自动输出 [B=2, H, W, C] 张量 | 所有输入图像尺寸必须一致;否则报错。 |
| Batch to Image List | 将 BATCH 图像拆分为图像列表 | 便于对每张图单独后处理 | 节点 “ImageListToImageBatch” 的逆操作;配合 “For Loop” 类插件使用 | 官方 ComfyUI 无原生循环,需依赖插件(如 WAS Suite 或 Impact Pack)。 |
| Primitive 节点 + 批提示 | 使用 STRING 或 INT 的 Primitive 节点作为提示词/种子占位符 | 实现参数批量替换 | 创建 Primitive (STRING) → 连接到 CLIP Text Encode;保存工作流后,通过脚本修改 JSON 中的值实现批量生成 | 需外部脚本驱动;非 UI 内置批处理。 |
| Seed++ 节点(社区插件) | 自动生成递增种子序列 | 快速生成多组随机结果 | 安装 Impact Pack 后使用 “Seed++” 节点,设置起始 seed 和 count | 依赖第三方插件;非官方内置功能。 |
| For Loop 模拟(WAS Suite) | 利用 “Math” + “Conditioning” + “Reroute” 构建有限迭代逻辑 | 在无真正循环支持下模拟重复操作 | WAS Node Suite 提供 “While Loop” 和 “Index” 节点 | 性能开销大;仅适用于轻量级重复任务。 |
| 批量保存命名 | Save Image 节点自动按序编号(00001_, 00002_…) | 区分同一批次中不同输出 | filename_prefix 设为 "batch_run" → 输出 batch_run_00001_.png, batch_run_00002_.png… | 无法自定义命名规则(除非修改源码或使用插件)。 |
5.2 外部 API 集成与脚本调用
| 方法/操作名称 | 语法/说明 | 用途 | 示例 | 注意事项 |
|---|
| 启用 REST API | 启动 ComfyUI 时添加 --listen 和 --port 参数 | 允许外部程序通过 HTTP 请求触发工作流 | python main.py --listen 0.0.0.0 --port 8188 | 默认仅本地访问;开放网络需注意安全。 |
| API:获取队列状态 | GET /queue | 查询当前任务队列 | curl http://localhost:8188/queue | 返回 pending/running 任务列表。 |
| API:执行工作流 | POST /prompt;Body: {"prompt": {...}, "extra_data": {}, "client_id": "..."} | 以编程方式提交完整工作流 JSON | 使用 Python requests:resp = requests.post("http://localhost:8188/prompt", json={"prompt": workflow_dict}) | workflow_dict 需与 .json 文件结构一致;需处理节点 ID 映射。 |
| 获取输出图像 | 监听 WebSocket 或轮询 /history | 获取生成结果的文件名 | 通过 client_id 关联请求与响应;从 /history/{prompt_id} 获取 output_images 字段 | 推荐使用 WebSocket 实时监听(官方提供示例 client.py)。 |
| 调用外部脚本(Exec Node) | 使用 WAS Suite 的 “Text File Write” 或 “Python Script” 节点 | 在工作流中执行系统命令或 Python 脚本 | ”PythonScriptNode” 输入 code 字符串 | 存在安全风险;默认禁用,需手动启用 exec 权限。 |
| 触发 Webhook | 在工作流末尾添加 HTTP 请求节点(需插件) | 生成完成后通知其他服务 | 安装 ComfyUI-Advanced-ControlNet 或自定义节点,发送 POST 到 Slack/Discord webhook | 需处理网络异常和重试逻辑。 |
| 参数化工作流模板 | 编写脚本动态替换 JSON 中的字段(如 prompt、seed) | 实现大规模自动化生成 | data["3"]["inputs"]["text"] = "a photo of " + subject | 节点 ID(如 “3”)可能随编辑变化,建议使用标签或注释辅助定位。 |
5.3 插件管理与社区资源
| 方法/操作名称 | 语法/说明 | 用途 | 示例 | 注意事项 |
|---|
| ComfyUI-Manager 插件 | 安装后提供 UI 界面管理插件 | 一键安装/更新/卸载社区节点 | cd custom_nodes && git clone https://github.com/ltdrdata/ComfyUI-Manager.git | 需联网;部分插件依赖特定 Python 包。 |
| 插件依赖自动安装 | Manager 支持读取插件的 requirements.txt 并自动 pip install | 简化环境配置 | 插件目录含 requirements.txt | 若系统无权限,需手动运行 pip install -r。 |
| 社区资源平台 | Civitai、OpenArt、GitHub、Comfy-Org 官方仓库 | 获取模型、工作流、节点插件 | Civitai 搜索 “ComfyUI workflow” → 下载 .json | 注意许可证(License)和兼容性(SD1.5 vs SDXL)。 |
| 插件冲突排查 | 临时移除 custom_nodes/ 下插件目录测试 | 定位导致崩溃或错误的插件 | mv ComfyUI-Impact-Pack /tmp/ | 建议一次只启用一个新插件进行测试。 |
| 节点文档与示例 | 大多数插件在 GitHub README 中提供节点图和参数说明 | 快速上手复杂插件 | Impact Pack README 包含人脸检测、细节增强等完整工作流截图 | 优先阅读官方文档,避免误用。 |
| 贡献与反馈 | 在插件仓库提 Issue 或 PR | 报告 Bug 或贡献代码 | GitHub → Issues → 描述问题 + 附工作流 JSON + 错误日志 | 提供可复现步骤将极大提升修复效率。 |
第六章:性能优化与部署
6.1 显存管理与模型卸载策略
| 方法/操作名称 | 语法/说明 | 用途 | 示例 | 注意事项 |
|---|
| 启用模型自动卸载 | 在 extra_model_paths.yaml 或启动参数中配置 | 减少显存占用,避免 OOM | 启动命令:python main.py --disable-smart-memory(注:默认已启用智能内存管理) | ComfyUI 默认启用”按需加载+空闲卸载”;禁用后可能提升速度但增加显存压力。 |
| 手动触发模型清理 | 使用内置节点 “FreeU” 或 “Model Sampling” 中的 unload 选项(部分插件支持) | 主动释放不再使用的模型 | Impact Pack 提供 “Unload Model” 节点,连接至工作流末尾 | 官方节点无直接 unload 接口;依赖社区插件实现。 |
| 模型共享机制 | 多个工作流共用同一 CLIP/VAE/MODEL 实例 | 避免重复加载相同模型 | 将 KSampler 和 CLIP Text Encode 连接到同一个 CheckpointLoader 节点输出 | 若修改模型路径,所有引用将同步更新。 |
| 使用低精度推理(FP16) | 加载模型时自动使用半精度(若硬件支持) | 降低显存消耗,提升推理速度 | 大多数 Checkpoint 模型在 RTX 显卡上默认以 FP16 加载;无需额外设置 | 部分老模型或自定义 LoRA 可能出现数值不稳定。 |
| 显存监控工具 | 通过 nvidia-smi 或集成日志观察显存变化 | 诊断瓶颈 | 终端运行:watch -n 1 nvidia-smi | ComfyUI 本身不提供显存面板;可结合第三方监控插件(如 ComfyUI-Manager 的状态栏)。 |
| 分块处理大图(Tiled VAE) | 启用 Tiled VAE 解码/编码 | 支持超分辨率图像生成而不爆显存 | 安装插件 ComfyUI-TiledDiffusion,使用 “Tiled VAE Decode” 节点替代标准 VAE Decode | 会略微降低图像连贯性;适用于 >2K 分辨率任务。 |
6.2 工作流加速技巧
| 方法/操作名称 | 语法/说明 | 用途 | 示例 | 注意事项 |
|---|
| 缓存中间结果(Cache Node) | 使用 “Cache” 节点(如 WAS Suite 提供)保存昂贵计算结果 | 避免重复执行相同子流程 | 将 ControlNet 预处理结果接入 Cache 节点 → 后续迭代直接读取缓存 | 缓存基于输入哈希;输入不变则跳过计算。 |
| 禁用预览图生成 | 在 Save Image 节点取消勾选 “Preview” 或移除 Preview Image 节点 | 减少 CPU 图像解码开销 | 删除工作流中所有 Preview Image 节点;或设置环境变量:COMFYUI_PREVIEW=0(部分版本支持) | 对批量生成场景提速明显。 |
| 使用更高效的采样器 | 选择 DPM++ 2M Karras、UniPC 等快速收敛采样器 | 在较少步数下获得高质量结果 | KSampler 节点:sampler_name = "dpmpp_2m_karras", steps = 20 | 不同采样器对步数敏感度不同;建议测试对比。 |
| 并行工作流执行 | 通过 API 同时提交多个独立 prompt | 利用 GPU 空闲周期提升吞吐 | 多线程脚本并发调用 /prompt 接口(需确保 batch size 合理) | GPU 利用率高时可能互相阻塞;建议监控队列长度。 |
| 优化图像尺寸 | 输入图像尽量为 64 的倍数(如 512x768) | 避免内部 padding 带来的计算浪费 | 使用 “Image Scale” 节点将输入统一缩放到 512x768 或 1024x1024 | SD1.5 最佳尺寸为 512;SDXL 为 1024。 |
| 预加载常用模型 | 启动时自动加载高频模型(通过脚本或 Manager 插件) | 减少首次生成延迟 | 使用 ComfyUI-Manager 的 “Model Auto Load” 功能,配置常驻模型列表 | 会增加启动时间和初始显存占用。 |
6.3 Docker 部署与远程访问
| 方法/操作名称 | 语法/说明 | 用途 | 示例 | 注意事项 |
|---|
| 官方 Docker 镜像构建 | 基于 GitHub 提供的 Dockerfile 构建 | 快速容器化部署 | git clone https://github.com/comfyanonymous/ComfyUI.git; cd ComfyUI; docker build -t comfyui . | 需提前安装 NVIDIA Container Toolkit。 |
| 启用 GPU 支持 | 运行容器时添加 --gpus all 参数 | 使容器内程序可调用宿主机 GPU | docker run --gpus all -p 8188:8188 -v ./models:/ComfyUI/models comfyui | 确保宿主机已安装 nvidia-docker2。 |
| 持久化模型与工作流 | 通过 -v 挂载宿主机目录到容器内 | 保留模型、自定义节点和工作流 | -v /host/models:/ComfyUI/models -v /host/custom_nodes:/ComfyUI/custom_nodes -v /host/input:/ComfyUI/input | 路径需与容器内一致;注意文件权限。 |
| 远程 Web 访问 | 绑定 0.0.0.0 并开放端口 | 允许局域网或其他设备访问 | docker run -p 8188:8188 ... 并在启动命令中加 --listen 0.0.0.0 | 生产环境建议加反向代理(Nginx)和身份验证。 |
| 环境变量配置 | 通过 -e 设置 COMFYUI_ARGS 等变量 | 动态调整启动参数 | docker run -e COMFYUI_ARGS="--listen 0.0.0.0 --port 8188 --disable-smart-memory" ... | 部分镜像需自定义 entrypoint 支持。 |
| HTTPS 与认证(高级) | 结合 Nginx + Let’s Encrypt 或 Basic Auth | 安全远程访问 | 在宿主机部署 Nginx:location / { auth_basic "Restricted"; proxy_pass http://localhost:8188; } | ComfyUI 本身无用户系统;安全依赖外部层。 |
ComfyUI 自定义插件开发教程
第一章:ComfyUI 基础与插件机制概览
1.1 ComfyUI 核心架构简介
| 概念名称 | 说明 | 注意事项 |
|---|
| 节点(Node) | ComfyUI 的基本功能单元,每个节点封装特定操作(如加载模型、生成图像等),通过输入/输出端口连接形成工作流。 | 节点必须继承自特定基类并注册到节点系统中才能被 UI 识别。 |
| 工作流(Workflow) | 由多个节点及其连接关系构成的有向无环图(DAG),描述图像生成的完整流程。 | 工作流以 JSON 格式保存,可通过前端导出/导入。 |
| 执行器(Executor) | 负责解析工作流图并按依赖顺序调度节点执行的后端组件。 | 执行顺序由拓扑排序决定,不支持循环依赖。 |
| 服务端(Server) | 基于 Python 的 HTTP/WebSocket 服务,提供 API 接口、静态资源和 WebSocket 实时通信。 | 默认使用 aiohttp 框架,监听 8188 端口。 |
| 前端(Frontend) | 基于 HTML/JavaScript 的图形化界面,用于构建和运行工作流。 | 前端与后端通过 WebSocket 同步节点状态和执行结果。 |
1.2 插件系统工作原理
| 概念名称 | 说明 | 注意事项 |
|---|
| 插件自动发现机制 | ComfyUI 启动时会扫描 custom_nodes 目录下所有子目录,若包含 __init__.py 或符合特定命名规则,则尝试加载为插件。 | 插件目录名不能以 _ 开头,否则会被跳过。 |
| 节点注册机制 | 插件通过定义函数并使用 @classmethod 或直接在模块顶层调用注册方法(如 NODE_CLASS_MAPPINGS)向系统注册节点类。 | 必须同时提供 NODE_CLASS_MAPPINGS 和 NODE_DISPLAY_NAME_MAPPINGS(可选但推荐)。 |
| 模块隔离 | 每个插件作为独立 Python 模块加载,避免全局命名冲突。 | 插件内部应避免修改全局状态或 monkey-patch 核心模块。 |
| 动态重载支持 | 在开发模式下,可通过重启服务或使用热重载工具(如 watchdog)实现插件代码更新后自动生效。 | Colab 环境通常需手动重启内核以加载新插件。 |
| 依赖管理 | 插件可自带 requirements.txt,用户需手动安装依赖;部分启动脚本(如 main.py --install-deps)可自动处理。 | 不建议在插件中硬编码 pip 安装命令,应引导用户显式安装依赖。 |
1.3 插件目录结构规范
| 组成部分 | 说明 | 注意事项 |
|---|
custom_nodes/your_plugin_name/ | 插件根目录,名称应具有唯一性和描述性(如 ComfyUI-ExamplePlugin)。 | 目录名将影响模块导入路径,避免使用空格或特殊字符。 |
__init__.py | 插件入口文件,必须包含 NODE_CLASS_MAPPINGS 字典,用于注册节点类。 | 若缺失此文件,ComfyUI 将忽略该目录。 |
nodes.py(或其他模块文件) | 实际定义节点类的 Python 文件,可按功能拆分为多个模块。 | 节点类需继承 object,无需特定父类,但需实现标准接口(如 INPUT_TYPES, RETURN_TYPES 等)。 |
requirements.txt | 列出插件依赖的第三方 Python 包(如 torchvision, opencv-python)。 | 用户需自行运行 pip install -r requirements.txt,ComfyUI 不自动安装。 |
__pycache__/ 或 .gitignore | 缓存目录或版本控制忽略文件,不影响功能。 | 建议在 .gitignore 中排除 __pycache__、.ipynb_checkpoints 等临时文件。 |
web/(可选) | 存放自定义前端资源(如 JS、CSS),用于扩展 UI 控件。 | 需配合后端路由注册,普通插件通常不需要。 |
LICENSE / README.md | 开源许可证和使用说明,提升插件可用性与合规性。 | 社区分发时强烈建议包含。 |
第二章:本地与 Colab 环境搭建
2.1 本地 ComfyUI 安装与运行
| 步骤名称 | 操作细节 | 注意事项 |
|---|
| 克隆官方仓库 | 在终端执行:git clone https://github.com/comfyanonymous/ComfyUI.git | 建议使用稳定分支(如 master),避免直接使用开发中 commit。 |
| 安装 Python 依赖 | 进入目录后运行:pip install -r requirements.txt | 需 Python ≥ 3.9;建议在虚拟环境(venv 或 conda)中操作。 |
| 安装 PyTorch | 根据 CUDA 版本从 PyTorch 官网安装对应版本,例如:pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 | 不要使用 requirements.txt 中的 CPU 版本(若需 GPU 支持)。 |
| 启动服务 | 执行:python main.py | 默认监听 127.0.0.1:8188,如需局域网访问加参数 --listen 0.0.0.0。 |
| 访问 WebUI | 在浏览器打开:http://127.0.0.1:8188 | 若启用 --listen,可从其他设备访问本机 IP。 |
| 安装自定义插件 | 将插件目录放入 ComfyUI/custom_nodes/ 下,重启服务生效 | 插件目录需含 __init__.py,否则不会被加载。 |
2.2 在 Google Colab 中部署 ComfyUI
| 步骤名称 | 操作细节 | 注意事项 |
|---|
| 创建新 Colab 笔记本 | 在 Google Drive 中新建 .ipynb 文件,选择 GPU 运行时(Runtime → Change runtime type → GPU) | 免费版 Colab 有运行时长限制(通常 ≤ 12 小时)。 |
| 克隆 ComfyUI 仓库 | 执行:!git clone https://github.com/comfyanonymous/ComfyUI.git | 使用 ! 表示 shell 命令,在 Colab cell 中运行。 |
| 安装依赖 | 执行:%cd ComfyUI 后 !pip install -r requirements.txt | Colab 已预装 PyTorch,通常无需重新安装,但需确认版本兼容性。 |
| 启动 ComfyUI 服务 | 执行:!python main.py --listen 0.0.0.0 --port 8188 | 必须加 --listen 0.0.0.0 才能通过隧道访问。 |
| 建立公网隧道 | 使用 ngrok:先 !pip install pyngrok,再 from pyngrok import ngrok; ngrok.set_auth_token("YOUR_TOKEN"); public_url = ngrok.connect(8188) | ngrok 需注册账号获取免费 token;也可用 Cloudflare Tunnel 替代。 |
| 获取访问链接 | 打印 public_url 并在新标签页打开 | 首次加载可能较慢,因需下载模型或初始化资源。 |
2.3 持久化插件开发环境配置(Colab)
| 步骤名称 | 操作细节 | 注意事项 |
|---|
| 挂载 Google Drive | 执行:from google.colab import drive; drive.mount('/content/drive') | 插件代码建议存于 Drive 以避免会话丢失。 |
| 软链接插件目录 | 将 Drive 中的插件目录链接到 ComfyUI:!ln -s /content/drive/MyDrive/comfy_plugins /content/ComfyUI/custom_nodes/my_plugin | 使用符号链接(symlink)便于实时同步代码修改。 |
| 自动安装插件依赖 | 在启动前运行:!pip install -r /content/drive/MyDrive/comfy_plugins/requirements.txt | 避免每次重启都手动安装依赖。 |
| 保存启动脚本 | 将完整启动流程写入 .py 或 .sh 文件并存于 Drive,例如 start_comfy.py | 可封装 ngrok 启动、路径设置等逻辑,提高复用性。 |
| 使用 Colab Notebook 单元格组织流程 | 分别创建”挂载”、“克隆”、“链接插件”、“启动服务”等单元格 | 便于调试和按需重跑部分步骤。 |
| 备份工作流 JSON | 将常用工作流导出为 .json 并保存至 Drive | 防止 Colab 会话结束后丢失工作流配置。 |
第三章:自定义节点开发基础
3.1 节点类的基本结构
| 方法/属性名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 类定义 | class MyNode: | 定义一个自定义节点类,无需继承特定父类 | class ImageProcessor: | 类名应具有描述性,避免与内置节点冲突 |
@classmethod 或模块级字典 | NODE_CLASS_MAPPINGS = {"MyNode": MyNode} | 将节点类注册到 ComfyUI 系统中 | NODE_CLASS_MAPPINGS = {"ImageProcessor": ImageProcessor} | 必须在插件的 __init__.py 或顶层模块中定义 |
NODE_DISPLAY_NAME_MAPPINGS | NODE_DISPLAY_NAME_MAPPINGS = {"MyNode": "My Custom Node"} | 为节点指定在 UI 中显示的友好名称 | NODE_DISPLAY_NAME_MAPPINGS = {"ImageProcessor": "Image Enhancer"} | 可选,但推荐提供以提升用户体验 |
FUNCTION 类属性 | FUNCTION = "process" | 指定节点执行时调用的实例方法名 | FUNCTION = "enhance_image" | 默认为 "execute",若使用其他名称需显式声明 |
CATEGORY 类属性 | CATEGORY = "image/postprocessing" | 定义节点在 UI 菜单中的分类路径 | CATEGORY = "my_plugins/image" | 使用斜杠分隔层级,便于组织 |
RETURN_TYPES | RETURN_TYPES = ("IMAGE",) | 声明节点输出的数据类型(用于类型检查和连接验证) | RETURN_TYPES = ("IMAGE", "MASK") | 必须为元组,即使只有一个输出 |
RETURN_NAMES(可选) | RETURN_NAMES = ("enhanced_image", "alpha_mask") | 为输出端口指定 UI 显示名称 | RETURN_NAMES = ("output_img",) | 若未提供,则使用默认名称如 "output 0" |
3.2 输入输出定义方法
| 方法/属性名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
INPUT_TYPES 类方法 | @classmethod def INPUT_TYPES(cls): return {...} | 定义节点的所有输入参数及其类型、默认值和 UI 控件 | 见下方示例 | 必须为类方法,返回嵌套字典 |
输入类型:"STRING" | "prompt": ("STRING", {"default": "hello"}) | 接收文本字符串输入 | "text": ("STRING", {"multiline": True}) | 支持 multiline, dynamicPrompts 等选项 |
输入类型:"INT" / "FLOAT" | "steps": ("INT", {"default": 20, "min": 1, "max": 100}) | 接收整数或浮点数,可设范围 | "scale": ("FLOAT", {"default": 7.5, "min": 0.0, "max": 20.0}) | step 参数可控制滑块步长 |
输入类型:"BOOLEAN" | "use_gpu": ("BOOLEAN", {"default": True}) | 布尔开关 | "flip": ("BOOLEAN", {"default": False}) | UI 显示为复选框 |
输入类型:数据类(如 "IMAGE") | "image": ("IMAGE",) | 接收来自其他节点的数据流(如图像张量) | "latent": ("LATENT",) | 类型名必须大写,且与输出类型匹配 |
动态输入("required" vs "optional") | 在 INPUT_TYPES 中分组定义 | 区分必填与可选输入 | {"required": {...}, "optional": {"mask": ("MASK",)}} | optional 字段在 UI 中可折叠,缺失时传入 None |
| 自定义下拉菜单 | "mode": (["fast", "quality"], {"default": "fast"}) | 提供枚举选项 | "scheduler": (["euler", "ddim"],) | 第一个元素是选项列表,必须为 list 或 tuple |
INPUT_TYPES 完整代码示例:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text": ("STRING", {"multiline": True}),
"strength": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0})
},
"optional": {
"image": ("IMAGE",)
}
}
3.3 执行逻辑与数据流控制
| 方法/属性名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
执行方法(由 FUNCTION 指定) | def process(self, text, strength, image=None): ... | 实现节点核心逻辑,接收输入并返回输出 | def enhance(self, image, factor=1.0): return (enhanced_img,) | 参数名必须与 INPUT_TYPES 中键名一致 |
| 返回值格式 | return (output1, output2, ...) | 返回元组,顺序对应 RETURN_TYPES | return (processed_image, mask_tensor) | 必须为元组,即使只有一个输出也要加逗号 |
| 张量数据格式(IMAGE) | torch.Tensor,shape: (B, H, W, C) | ComfyUI 图像标准格式(B=批量, C=通道=3 或 4) | img = torch.clamp(img, 0, 1) | 像素值通常为 [0, 1] 浮点数,非 [0,255] |
| 错误处理 | 使用 raise ValueError("message") | 抛出异常将中断工作流并在 UI 显示错误 | if image is None: raise ValueError("Image input required") | 避免静默失败,应提供明确错误信息 |
| 日志输出 | print() 或 logging | 调试时输出信息到控制台 | print(f"Processing image of shape {image.shape}") | Colab 中可在运行单元格下方查看输出 |
| 无副作用原则 | 不修改输入张量,返回新对象 | 保证工作流可重入与并行安全 | output = input_tensor.clone() | 直接修改输入可能导致上游节点状态污染 |
第四章:高级节点功能实现
4.1 动态输入/输出端口
| 方法/属性名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
RETURN_TYPES 动态设置 | 在执行方法内动态返回类型 | 允许根据条件改变输出类型或数量 | return ("STRING", "IMAGE") if condition else ("STRING",) | 必须确保逻辑清晰且可预测,避免混乱的连接 |
RETURN_NAMES 动态设置(可选) | 同样可以在执行方法内动态返回名称 | 根据实际输出情况调整显示名称 | return ("processed_text", "modified_image") if condition else ("original_text",) | 提高用户理解度,但需与 RETURN_TYPES 对应 |
INPUT_TYPES 动态配置 | 通过类变量或执行时逻辑修改 | 支持基于上下文变化的输入端口 | 使用类变量控制 INPUT_TYPES 或在运行时修改 | 可能影响节点复用性,谨慎使用 |
| 条件输入 | 定义可选或条件性输入 | 提供更灵活的节点接口设计 | "optional_input": ("FLOAT", {"default": 0.5, "optional": True}) | 确保 UI 能够正确处理并展示这些输入 |
示例代码:
def process(self, text, optional_input=None):
# 根据某些条件决定是否需要使用 optional_input
if optional_input is not None:
processed = f"{text} with {optional_input}"
return (processed,)
else:
return (text,)
4.2 自定义 UI 控件集成
| 方法/属性名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
INPUT_TYPES 中添加自定义控件 | "custom_widget": ("CUSTOM_WIDGET", {...}) | 在节点 UI 中集成特殊控件如滑块、下拉菜单等 | "quality": ("INT", {"widget": "slider", "min": 1, "max": 10}) | 需要框架支持特定控件,否则可能无效 |
| 注册自定义控件 | 在插件初始化阶段注册自定义控件类型 | 扩展 ComfyUI 以支持更多类型的 UI 组件 | NODE_CUSTOM_WIDGETS = {"MyNode": {"custom_slider": {"type": "slider", "min": 0, "max": 1}}} | 必须确保控件逻辑正确实现,并遵循框架规范 |
| 获取自定义控件值 | 在执行方法中正常接收参数 | 使用自定义控件获取用户输入 | def execute(self, custom_slider_value): ... | 自定义控件值如同普通参数一样传递和使用 |
示例代码:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image_quality": ("INT", {"widget": "slider", "min": 1, "max": 10})
}
}
def execute(self, image_quality):
print(f"Processing image at quality level: {image_quality}")
...
4.3 异步与多线程处理
| 方法/属性名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 异步函数定义 | 使用 async def 定义异步执行方法 | 实现非阻塞操作,提高效率 | async def async_process(self, input_data): await asyncio.sleep(1); return result | 需要框架支持异步调用,且注意异常处理 |
| 多线程执行 | 使用 Python threading 模块或第三方库 | 并行处理数据,加速计算密集型任务 | from threading import Thread; thread = Thread(target=compute_heavy_task); thread.start() | 小心管理共享资源,避免死锁和竞争条件 |
| 回调机制 | 设计回调函数或使用事件监听器 | 在任务完成后通知其他组件或更新 UI | on_complete=lambda result: print("Task done!") | 保证回调逻辑简洁可靠,防止内存泄漏 |
示例代码(简化版异步):
import asyncio
class AsyncProcessor:
async def async_execute(self, data):
await asyncio.sleep(2) # 模拟耗时操作
return f"Processed {data}"
# 在主程序或框架适配层中调用
async def main():
processor = AsyncProcessor()
result = await processor.async_execute("example")
print(result)
第五章:模型与资源加载机制
5.1 加载自定义模型(LoRA、Checkpoint 等)
| 方法/属性名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
folder_paths.get_folder_paths("checkpoints") | folder_paths.get_folder_paths("checkpoints") | 获取 ComfyUI 配置的 checkpoint 模型目录列表 | ckpt_dirs = folder_paths.get_folder_paths("checkpoints") | 返回的是列表,可能包含多个路径(如主目录 + extra_model_paths) |
folder_paths.get_filename_list("loras") | folder_paths.get_filename_list("loras") | 获取指定类型模型的可用文件名列表(不含路径) | lora_names = folder_paths.get_filename_list("loras") | 支持类型包括 "checkpoints", "loras", "vae", "clip", "unet" 等 |
load_checkpoint_guess_config() | load_checkpoint_guess_config(ckpt_path) | 自动推断并加载 Stable Diffusion checkpoint 模型 | model, clip, vae = load_checkpoint_guess_config(ckpt_path) | 来自 comfy.sd 模块,适用于 .safetensors 或 .ckpt |
LoraLoader.load_lora() | LoraLoader().load_lora(model, clip, lora_path, strength_model, strength_clip) | 应用 LoRA 权重到模型和 CLIP | model_lora, clip_lora = LoraLoader().load_lora(model, clip, lora_path, 1.0, 1.0) | 需先加载基础模型,再叠加 LoRA |
| 自定义模型加载节点 | 继承标准节点模式,调用上述 API | 在插件中封装模型加载逻辑供用户使用 | 见下方完整示例 | 必须处理路径合法性、文件存在性检查 |
完整节点示例(简化):
import folder_paths
from comfy.sd import load_checkpoint_guess_config
class CustomCheckpointLoader:
@classmethod
def INPUT_TYPES(cls):
return {"required": {"ckpt_name": (folder_paths.get_filename_list("checkpoints"),)}}
RETURN_TYPES = ("MODEL", "CLIP", "VAE")
FUNCTION = "load"
CATEGORY = "custom/loaders"
def load(self, ckpt_name):
ckpt_path = folder_paths.get_full_path("checkpoints", ckpt_name)
model, clip, vae = load_checkpoint_guess_config(ckpt_path)
return (model, clip, vae)
5.2 资源路径管理与缓存策略
| 概念/方法名称 | 说明 | 用途 | 代码示例 | 注意事项 |
|---|
folder_paths.add_model_folder_path(type_name, path) | 向指定模型类型注册额外搜索路径 | 扩展模型加载范围(如挂载 Google Drive 目录) | folder_paths.add_model_folder_path("loras", "/content/drive/MyDrive/lora") | 需在 ComfyUI 启动早期调用(如插件 __init__.py 中) |
folder_paths.get_full_path(type_name, filename) | 根据类型和文件名拼接完整绝对路径 | 安全获取模型文件路径,避免硬编码 | full_path = folder_paths.get_full_path("vae", "vae-ft-mse-840000-ema-pruned.safetensors") | 若文件不存在于任何注册路径,返回 None |
| 模型缓存机制(ComfyUI 内部) | 自动缓存已加载的模型(基于路径哈希) | 避免重复加载相同模型,节省显存和时间 | 无需用户干预,由 ModelPatcher 等内部类管理 | 缓存键为文件路径,重命名文件会视为新模型 |
| 手动清除缓存 | 使用 del 或 gc.collect() 释放模型对象 | 在 Colab 等内存受限环境中主动回收资源 | del model; torch.cuda.empty_cache() | 显式删除变量后调用 PyTorch 清理 GPU 缓存 |
extra_model_paths.yaml | 配置文件,用于全局添加模型搜索路径 | 无需修改代码即可扩展模型目录 | 见下方示例 | 重启服务后生效,适用于多插件共享路径 |
extra_model_paths.yaml 示例片段:
my_models:
base_path: /content/drive/MyDrive/AI_Models
checkpoints: models/Stable-diffusion
loras: models/Lora
5.3 兼容 WebUI 模型格式
| 概念/方法名称 | 说明 | 用途 | 代码示例 | 注意事项 |
|---|
| WebUI Checkpoint 格式 | .ckpt 或 .safetensors 文件,包含 UNet、VAE、CLIP 权重 | ComfyUI 原生支持此类格式,可直接加载 | 与 5.1 中 load_checkpoint_guess_config 兼容 | 不需要转换,但需注意部分 WebUI 特有变体(如 Inpainting 模型)可能缺少 VAE |
| WebUI LoRA 格式 | 单一 .safetensors 文件,含 lora_unet_* 和 lora_te_* 键 | ComfyUI 的 LoraLoader 完全兼容 | 可直接通过 LoraLoader 节点加载 | 确保 LoRA 名称不包含非法字符(如空格、中文) |
| 嵌入(Embeddings / Textual Inversion) | 存放于 embeddings/ 目录的 .pt 或 .bin 文件 | ComfyUI 通过 CLIPLoader 自动识别并加载 | 用户在文本提示中使用 <embedding_name> 即可 | 文件名即为关键词,不支持子目录(除非手动注册路径) |
| VAE 模型兼容性 | WebUI 的 vae-ft-mse-* 等 .safetensors 可直接用于 ComfyUI | 替换默认 VAE 以改善图像质量 | 通过 VAELoader 节点加载 | 若 checkpoint 已内嵌 VAE,需显式替换才生效 |
| 模型元数据缺失处理 | WebUI 模型通常无配置文件(如 config.json) | ComfyUI 通过权重结构自动推断模型类型 | load_checkpoint_guess_config 内部实现猜测逻辑 | 极少数非标模型可能加载失败,需手动指定配置 |
第六章:插件打包与分发
6.1 插件元数据配置(__init__.py、pyproject.toml)
| 配置项/文件 | 语法/结构 | 用途 | 示例 | 注意事项 |
|---|
__init__.py 中的 NODE_CLASS_MAPPINGS | 字典,键为节点标识符,值为类对象 | 向 ComfyUI 注册所有自定义节点 | NODE_CLASS_MAPPINGS = {"MyNode": MyNodeClass} | 必须存在,否则插件不会被识别 |
NODE_DISPLAY_NAME_MAPPINGS | 字典,键同上,值为 UI 显示名 | 提供用户友好的节点名称 | NODE_DISPLAY_NAME_MAPPINGS = {"MyNode": "My Custom Processor"} | 可选,但强烈推荐 |
__init__.py 中的 __all__(可选) | 列表,指定公开接口 | 控制 from plugin import * 的行为 | __all__ = ["MyNodeClass"] | 非必需,主要用于代码规范 |
pyproject.toml(标准格式) | 使用 TOML 语法描述项目元数据 | 支持现代 Python 构建工具(如 pip install -e .) | 见下方完整示例 | 若仅用于 ComfyUI,非强制,但利于分发 |
pyproject.toml 的 [project] 区块 | 定义名称、版本、依赖等 | 声明插件基本信息和运行依赖 | name = "comfyui-myplugin";dependencies = ["opencv-python"] | 名称建议以 comfyui- 开头,便于识别 |
pyproject.toml 的 [tool.comfy](社区约定) | 自定义扩展字段(非官方但常用) | 标注插件类别、作者、兼容性等 | [tool.comfy];display_name = "My Plugin";author = "Alice" | 目前无官方 schema,但部分管理器(如 ComfyUI-Manager)会读取 |
pyproject.toml 完整示例:
[build-system]
requires = ["setuptools >= 61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "comfyui-image-enhancer"
version = "1.0.0"
description = "A ComfyUI plugin for image post-processing"
dependencies = [
"opencv-python>=4.5.0",
"numpy"
]
[tool.comfy]
display_name = "Image Enhancer"
author = "Your Name"
category = "postprocessing"
6.2 GitHub 发布与自动更新机制
| 操作/机制名称 | 操作细节 | 用途 | 示例 | 注意事项 |
|---|
| 创建 GitHub 仓库 | 在 GitHub 上新建仓库,命名如 ComfyUI-MyPlugin | 托管插件源码,便于协作与分发 | 仓库 URL: https://github.com/yourname/ComfyUI-MyPlugin | 建议遵循 ComfyUI-<PluginName> 命名惯例 |
| 添加 Release 版本 | 使用 GitHub Releases 发布带版本号的 ZIP 包 | 用户可通过版本号稳定安装 | Tag: v1.0.0,附带源码 ZIP | 确保包含 __init__.py 和必要资源 |
支持 git clone 安装 | 用户执行 git clone <url> custom_nodes/xxx | 最常用安装方式,支持热更新 | git clone https://github.com/.../ComfyUI-MyPlugin | 插件目录名不影响功能,但影响导入路径 |
| 实现自动更新检测(通过 ComfyUI-Manager) | 在插件根目录添加 .git 或 install.json | 兼容第三方插件管理器的更新检查 | 无需额外代码,只要是从 Git 安装即可 | 用户需安装 ComfyUI-Manager |
install.json(可选) | JSON 文件,声明依赖和启动脚本 | 供 ComfyUI-Manager 自动安装依赖 | {"pip": ["opencv-python"], "git": []} | 放在插件根目录,非官方但广泛支持 |
| 使用 GitHub Actions(可选) | 编写 CI 脚本进行基本测试 | 确保主分支代码可运行 | 触发 pytest 或语法检查 | 对简单插件非必需,但提升专业性 |
install.json 示例:
{
"pip": ["opencv-python", "scikit-image"],
"git": []
}
6.3 社区插件注册与兼容性测试
| 机制/操作名称 | 说明 | 用途 | 示例/操作 | 注意事项 |
|---|
| 提交至 ComfyUI-Manager 插件列表 | 在其 GitHub 仓库提交 PR 更新 custom-node-list.json | 让用户能在 UI 中一键安装你的插件 | Fork ComfyUI-Manager,修改列表文件 | 需提供有效仓库 URL 和分类 |
兼容性标签(如 comfyui_version) | 在文档或 pyproject.toml 中声明支持的 ComfyUI 版本范围 | 避免用户在不兼容版本中使用 | "compatible_comfyui": ">=0.3.0" | 目前无强制校验,靠社区自律 |
| 基础兼容性测试 | 在本地或 Colab 中验证:1) 能加载;2) 节点可连接;3) 能出图 | 确保插件在主流环境中正常工作 | 使用默认 SD1.5 checkpoint 测试全流程 | 至少测试 CPU + GPU(如有)两种模式 |
| 避免全局副作用 | 不修改 sys.path、不 monkey-patch 核心模块 | 防止与其他插件冲突 | 使用局部导入,不执行顶层副作用代码 | 插件应”即插即用”,卸载后无残留影响 |
提供 example_workflow.json | 附带一个可运行的工作流示例 | 降低用户上手门槛 | 存放于插件根目录或 examples/ 子目录 | 工作流应仅依赖公开模型或提供下载链接 |
| 遵循开源许可证 | 在仓库中包含 LICENSE 文件 | 明确使用和分发条款 | MIT、Apache-2.0 等宽松许可证更受欢迎 | 无 LICENSE 默认保留所有权利,不利于传播 |
第七章:Colab 环境下的插件调试技巧
7.1 实时日志查看与错误追踪
| 方法/操作名称 | 操作细节 | 用途 | 示例 | 注意事项 |
|---|
使用 print() 输出调试信息 | 在节点执行方法中插入 print() 语句 | 查看变量值、执行路径、中间结果 | print(f"Input shape: {image.shape}") | Colab 单元格输出区域会实时显示,但需确保服务在前台运行 |
| 捕获异常并打印完整 traceback | 使用 try...except + traceback.format_exc() | 获取详细的错误堆栈,便于定位问题 | import traceback; try: result = risky_operation() except Exception as e: print("Error:", traceback.format_exc()) | 避免仅打印 str(e),会丢失上下文 |
| 将日志重定向到文件 | 启动 ComfyUI 前设置日志文件 | 持久化记录,便于回溯分析 | `python main.py —listen 0.0.0.0 2>&1 | tee comfy.log` |
| 监控 GPU 显存使用 | 在单元格中定期运行 !nvidia-smi | 检查是否因显存泄漏导致崩溃 | 在独立单元格中执行 !nvidia-smi | Colab 免费版 GPU 显存有限(通常 ≤ 15GB),需谨慎管理 |
使用 logging 模块(可选) | 配置 Python logging 输出到控制台 | 结构化日志,支持多级别(DEBUG/INFO/ERROR) | import logging; logging.basicConfig(level=logging.DEBUG); logging.debug("Node started") | 在 Colab 中效果与 print() 类似,但更规范 |
7.2 使用 ngrok / Cloudflare Tunnel 暴露 WebUI
| 工具/操作名称 | 操作细节 | 用途 | 示例 | 注意事项 |
|---|
| 使用 ngrok(推荐) | 1. 安装 pyngrok;2. 设置 auth token;3. 调用 ngrok.connect(8188) | 将本地端口映射为公网 HTTPS 链接 | !pip install pyngrok; from pyngrok import ngrok; ngrok.set_auth_token("YOUR_TOKEN"); public_url = ngrok.connect(8188); print(public_url) | 必须注册 ngrok 账号获取免费 token;链接每次会话不同 |
| 使用 Cloudflare Tunnel(替代方案) | 1. 安装 cloudflared;2. 运行 cloudflared tunnel --url http://localhost:8188 | 无需账号的隧道方案,更稳定 | !wget ... cloudflared-linux-amd64 -O cloudflared; !chmod +x cloudflared; !./cloudflared tunnel --url http://localhost:8188 | 输出中查找 https://*.trycloudflare.com 链接;首次运行需确认 |
| 后台运行 ComfyUI + 隧道 | 使用 & 或 nohup 同时启动服务和隧道 | 避免阻塞 Colab 单元格 | !python main.py --listen 0.0.0.0 &; !./cloudflared tunnel ... & | 推荐先启动 ComfyUI,再启动隧道,避免端口未就绪 |
| 自动提取并打印隧道 URL | 解析 cloudflared 输出中的 URL 行 | 方便用户直接点击访问 | 使用 subprocess 和正则匹配 trycloudflare.com URL | 需处理子进程流,避免死锁;ngrok 可直接通过 API 获取 |
| 隧道稳定性提示 | 避免长时间空闲,定期交互 | 防止 Colab 自动断开或隧道超时 | 每 5 分钟在 UI 中点击一次或发送 WebSocket 心跳 | 免费隧道通常有连接数或带宽限制 |
7.3 断点调试与变量监控(结合 VS Code + Colab)
| 方法/工具名称 | 操作细节 | 用途 | 示例 | 注意事项 |
|---|
| 使用 debugpy 远程调试 | 1. 在 Colab 安装 debugpy;2. 启动调试服务器;3. VS Code 连接 | 在 VS Code 中设置断点、单步执行、查看变量 | !pip install debugpy; import debugpy; debugpy.listen(("0.0.0.0", 5678)); print("Waiting for debugger attach..."); debugpy.wait_for_client() | 必须配合 ngrok/Cloudflare 将 5678 端口暴露出去 |
配置 VS Code launch.json | 添加远程 attach 配置 | 连接到 Colab 中的 Python 进程 | {"name": "Attach to Colab", "type": "python", "request": "attach", "connect": {"host": "YOUR_NGROK_URL", "port": 5678}, "pathMappings": [{"localRoot": "${workspaceFolder}", "remoteRoot": "/content"}]} | remoteRoot 通常为 /content;host 填 ngrok 的 TCP 隧道地址(如 0.tcp.ngrok.io) |
| 创建 ngrok TCP 隧道(用于 debugpy) | ngrok tcp 5678 | 暴露调试端口(非 HTTP) | 在新单元格运行:!ngrok tcp 5678;从输出中获取 0.tcp.ngrok.io:XXXXX | HTTP 隧道无法用于 debugpy,必须用 tcp 类型 |
在节点代码中插入 debugpy.breakpoint() | 触发断点暂停 | 精确控制调试入口点 | def execute(self, image): debugpy.breakpoint(); return (image * 0.5,) | 仅在已连接调试器时生效,否则继续执行 |
| 替代方案:使用 pdb + 日志 | 在无 IDE 时快速检查状态 | 简易命令行调试 | import pdb; pdb.set_trace() | 在 Colab 中会阻塞输出,需在单元格下方交互输入命令(如 n, p var),体验较差 |
💡 提示:由于 Colab 会话不可持久,建议将调试代码封装在函数中,并通过条件开关(如 if DEBUG:)控制是否启用 debugpy,避免影响正常运行。
第八章:常见问题与性能优化
8.1 内存泄漏检测与规避
| 方法/操作名称 | 语法/说明 | 用途 | 代码示例 | 注意事项 |
|---|
| 显式删除张量变量 | 使用 del 释放不再需要的 PyTorch 张量 | 防止 Python 引用计数阻止内存回收 | del output_tensor; torch.cuda.empty_cache() | 仅删除变量名,不立即释放 GPU 内存,需配合 empty_cache() |
调用 torch.cuda.empty_cache() | 清理 PyTorch 缓存的未使用显存块 | 回收碎片化显存,缓解 OOM | torch.cuda.empty_cache() | 不会释放正在使用的张量,仅清理缓存池 |
| 使用上下文管理器隔离计算 | 在函数内局部作用域执行 heavy 操作 | 确保中间变量在函数退出时自动销毁 | def process(): temp = torch.randn(1000, 1000).cuda(); return temp.mean() | 避免在类实例中长期持有大张量引用 |
监控对象引用(gc 模块) | 使用 gc.get_referrers(obj) 查看谁引用了对象 | 定位意外持有的引用链 | import gc; refs = gc.get_referrers(my_tensor); print(len(refs)) | 仅用于调试,生产环境应避免;输出较难解读 |
| 避免全局缓存字典 | 不在模块顶层存储模型/张量到 dict | 防止插件间或多次运行累积内存 | ❌ 错误:CACHE = {};✅ 正确:使用局部变量或弱引用 | 若必须缓存,考虑 weakref.WeakValueDictionary |
8.2 GPU 显存管理最佳实践
| 方法/操作名称 | 语法/说明 | 用途 | 代码示例 | 注意事项 |
|---|
使用 .to(device) 显式控制设备 | 将张量移至 GPU 或 CPU | 避免隐式复制导致显存浪费 | image = image.to("cuda") if use_gpu else image.to("cpu") | 默认设备可能不是 "cuda",建议显式指定 |
启用 torch.inference_mode() | 上下文管理器,禁用梯度计算和部分历史记录 | 减少显存占用并加速推理 | with torch.inference_mode(): output = model(input) | 替代旧版 torch.no_grad(),更高效 |
| 分批处理(Batching) | 将大任务拆分为小 batch 依次处理 | 控制峰值显存,避免 OOM | for i in range(0, total, batch_size): batch = data[i:i+batch_size]; process(batch) | 需权衡吞吐量与显存,batch_size 过小会降低效率 |
| 使用半精度(FP16) | 调用 .half() 或 autocast | 减少显存占用约 50%,提升速度 | with torch.autocast("cuda"): output = model(input.half()) | 并非所有模型都支持 FP16,可能影响数值稳定性 |
| 及时释放中间结果 | 不保留不必要的中间张量 | 降低显存峰值 | ❌ x1 = f(x); x2 = g(x1); return x2;✅ return g(f(x)) | 复杂逻辑可手动 del x1 后调用 empty_cache() |
8.3 节点执行效率分析工具
| 工具/方法名称 | 语法/说明 | 用途 | 代码示例 | 注意事项 |
|---|
time.time() 简单计时 | 记录执行前后时间戳 | 快速测量节点整体耗时 | import time; start = time.time(); result = heavy_function(); print("Time:", time.time() - start) | 精度较低,适用于粗略评估 |
torch.cuda.Event(GPU 计时) | 使用 CUDA 事件精确测量 GPU 执行时间 | 排除 CPU 调度开销,专注 GPU 性能 | start = torch.cuda.Event(enable_timing=True); end = torch.cuda.Event(enable_timing=True); start.record(); output = model(input); end.record(); torch.cuda.synchronize(); print(start.elapsed_time(end)) | 必须调用 synchronize() 等待 GPU 完成 |
cProfile + pstats | Python 内置性能分析器 | 定位 CPU 瓶颈函数 | import cProfile, pstats; pr = cProfile.Profile(); pr.enable(); node.execute(...); pr.disable(); pstats.Stats(pr).sort_stats('cumulative').print_stats(10) | 对 GPU 操作无效,仅分析 Python 层 |
nvprof / nsight(高级) | NVIDIA 命令行性能分析工具 | 深入分析 CUDA kernel 效率 | !nvprof --print-gpu-trace python test_node.py | Colab 中可能受限;需安装 CUDA 工具包 |
| 日志标记关键阶段 | 在节点中插入阶段日志 | 手动划分耗时区间 | print("[DEBUG] Preprocess done"); print("[DEBUG] Model forward done") | 无需额外依赖,适合快速排查慢环节 |
第九章:情绪可控的 index-TTS2 语音大模型插件开发
9.1 index-TTS2 模型加载与推理接口封装
| 方法/组件名称 | 语法/说明 | 用途 | 代码示例 | 注意事项 |
|---|
模型初始化(TTSModel 类) | 使用官方 TTSModel 封装加载 checkpoint 和 config | 统一管理模型实例,避免重复加载 | from tts_model import TTSModel; tts = TTSModel(model_path="models/index-tts2", device="cuda") | 首次加载较慢;建议在插件全局或单例中缓存实例 |
| 支持的情绪标签(Emotion Tags) | 字符串列表,如 "happy", "sad", "angry", "neutral" | 控制语音情感风格 | emotion = "happy" | 实际支持的情绪需参考模型训练数据,非任意字符串都有效 |
推理接口 tts.synthesize() | synthesize(text, emotion=None, language="en", speed=1.0) | 核心语音合成方法 | audio, sr = tts.synthesize("Hello!", emotion="excited", language="en") | 返回 (numpy.ndarray, int),音频为 float32,范围 [-1, 1] |
| 设备自动检测 | 自动选择 "cuda"(若可用)或 "cpu" | 提升兼容性 | device = "cuda" if torch.cuda.is_available() else "cpu" | Colab 环境通常有 GPU,但需显式启用 |
| 模型路径管理 | 使用 folder_paths.get_full_path("tts_models", filename) | 兼容 ComfyUI 资源路径体系 | model_dir = folder_paths.get_full_path("tts_models", "index-tts2") | 需提前将模型放入 ComfyUI/models/tts_models/ 或通过 extra_model_paths.yaml 注册 |
💡 提示:index-TTS2 通常包含 config.json、model.pth 和 vocoder/ 子目录,需完整放置。
9.2 情绪与语音参数的 UI 配置节点设计
| 输入参数名称 | 类型/控件 | 说明 | 示例值 | 注意事项 |
|---|
text | ("STRING", {"multiline": True}) | 待合成的文本内容 | "I'm so happy to see you!" | 支持多行输入,便于长文本 |
emotion | (["neutral", "happy", "sad", "angry", "excited"],) | 情绪风格选择下拉菜单 | "happy" | 选项应与模型实际支持的情绪对齐 |
language | (["en", "zh", "ja", "ko"],) | 语言选择(若模型支持多语) | "zh" | index-TTS2 支持中英日韩,需确认模型版本 |
speed | ("FLOAT", {"default": 1.0, "min": 0.5, "max": 2.0, "step": 0.1}) | 语速控制(0.5~2.0 倍) | 1.2 | 过快或过慢可能影响自然度 |
seed | ("INT", {"default": -1, "min": -1, "max": 1e9}) | 随机种子(-1 表示随机) | -1 或 42 | 用于复现相同语音效果(若模型支持) |
output_format | (["wav", "mp3"],) | 输出音频格式(可选) | "wav" | 插件内部可调用 scipy 或 pydub 转换 |
节点输出定义:
RETURN_TYPES = ("AUDIO", "INT")
RETURN_NAMES = ("audio_waveform", "sample_rate")
- 音频以
(N,) shape 的 NumPy 数组输出,符合 ComfyUI 音频生态惯例(未来可与其他音频节点串联)
9.3 音频输出与持久化(WAV/MP3 导出)
| 功能/方法名称 | 语法/说明 | 用途 | 代码示例 | 注意事项 |
|---|
| 保存为 WAV 文件 | 使用 scipy.io.wavfile.write() | 无损保存合成语音 | from scipy.io.wavfile import write; write("/content/output.wav", sr, (audio * 32767).astype(np.int16)) | 需将 float32 [-1,1] 转为 int16 [-32768, 32767] |
| 保存为 MP3(可选) | 使用 pydub.AudioSegment.export() | 压缩格式,节省空间 | from pydub import AudioSegment; seg = AudioSegment(audio.tobytes(), frame_rate=sr, sample_width=4, channels=1); seg.export("out.mp3", format="mp3") | 需安装 pydub 和 ffmpeg;Colab 默认有 ffmpeg |
| 在 Colab 中下载文件 | 使用 files.download() | 方便用户获取结果 | from google.colab import files; files.download("output.wav") | 仅限 Colab 环境 |
| 返回音频供后续节点使用 | 直接返回 (audio, sr) 元组 | 支持工作流内音频链式处理(如加混响、变速) | return (audio, sr) | 为未来扩展(如音频编辑插件)预留接口 |
| 错误处理:文本为空 | 检查输入并抛出友好错误 | 防止空文本导致崩溃 | if not text.strip(): raise ValueError("Text input is empty!") | 提升用户体验 |
完整节点骨架示例(简化版):
import torch
import numpy as np
from tts_model import TTSModel # 假设已封装
import folder_paths
class IndexTTS2Node:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text": ("STRING", {"multiline": True}),
"emotion": (["neutral", "happy", "sad", "angry", "excited"],),
"language": (["en", "zh", "ja", "ko"],),
"speed": ("FLOAT", {"default": 1.0, "min": 0.5, "max": 2.0}),
}
}
RETURN_TYPES = ("AUDIO", "INT")
RETURN_NAMES = ("audio", "sample_rate")
FUNCTION = "synthesize"
CATEGORY = "audio/tts"
def synthesize(self, text, emotion, language, speed):
if not text.strip():
raise ValueError("Input text is empty!")
model_path = folder_paths.get_full_path("tts_models", "index-tts2")
tts = TTSModel(model_path, device="cuda" if torch.cuda.is_available() else "cpu")
audio, sr = tts.synthesize(text, emotion=emotion, language=language, speed=speed)
return (audio, sr)