您现在的位置是:网站首页> AI人工智能

Comfy UI 技术收集

摘要

Comfy UI 技术收集


1.jpg



ComfyUI目录说明

ComfyUI工作流站点

基础知识

通过ComfyUI接口生成图片成功代码

Comfy UI 使用教程及实践

AI咒语

喂饭级教程!ComfyUI本地部署超详细指南




ComfyUI目录说明

‌ComfyUI 模型默认都放在安装目录下的 models 文件夹里,不同类型模型需存入对应子文件夹。‌‌‌‌

模型分类存放位置:

‌1.大模型(Checkpoints)‌:放入 models/checkpoints/,这是最常用的主模型目录 。

‌2.LoRA 模型‌:放入 models/loras/,用于微调风格或人物 。

‌3.ControlNet 模型‌:放入 models/controlnet/,用于控制构图和姿势 。

‌4.VAE 模型‌:放入 models/vae/,负责图像解码和色彩还原 。

‌5.放大模型‌:放入 models/upscale_models/,用于高清修复 。

‌6.其他模型‌:如 embeddings(嵌入)、clip(文本编码器)、unet、video_models(视频模型)等,均有对应名称的子文件夹


ComfyUI工作流站点

liblibAI绘图

runninghub



基础知识

何为Lora ControlNet 种子 CFG?

何为checkpoints模型?

checkpoints的数据流向?

ComfyUI  API如何使用?

可以编写自己的ComfyUI API 节点吗?

ComfyUI API 节点为何看到custom_nodes 目录里很多子目录,而主目录下.py很少

如何通过websocket调用ComfyUI?

对ComfyUI主要节点作详细的介绍及实际使用?

视频制作常用节点详细讲解及使用?

ComfyUI秋叶整合包API如何设置授权访问?


何为Lora ControlNet 种子 CFG?

1.LoRA 模型

相当于贴纸 / 风格滤镜。底模是基础画风,LoRA 可以额外加指定人物、服饰、画风,比如 “某动漫角色”“汉服”,叠加上去就行,体积很小。

2.ControlNet

相当于打草稿的线稿 / 骨架。正常 AI 自由发挥,ControlNet 强制它按照你给的姿势、轮廓、透视来画,避免人物肢体畸形。

3.种子 (Seed)

生成雪花图的 “随机编号”。同一个种子 + 同样参数,每次生成的初始雪花一模一样,最终画面也基本一致;改种子,雪花就变了,画出来的图也不一样。

4.CFG 数值

可以理解为 AI 听不听提示词的严格程度。数值越高,AI 越死板遵守文字描述;太低就会放飞自我,画得和文字不搭。




何为checkpoints模型?

一句话说清:Checkpoint(简称 CKPT)就是 SD 的 “完整大模型 / 底模”,是训练时存的权重快照,一个文件打包了生成图像必需的三大核心组件。

一、它到底是什么

全称:Checkpoint(检查点模型),俗称底模 / 大模型。

本质:训练过程中定期保存的完整模型权重,相当于游戏的 “存档”。

内容:一个文件里包含三样东西(缺一不可):

MODEL(UNet):负责去噪、构图、细节、光影(紫色端口)。

CLIP:负责把文字转成向量,理解提示词(黄色端口)。

VAE:负责把潜变量解码成清晰图像(粉色端口)。

格式:.ckpt(旧)或 .safetensors(新、更安全、更快)。

大小:2–7GB(SD1.5≈4GB,SDXL≈7GB)。

二、在 ComfyUI 里的位置与作用

存放路径:ComfyUI/models/checkpoints/。

对应节点:Load Checkpoint(CheckpointLoaderSimple)。

输出端口:

MODEL → 给 KSampler(去噪)

CLIP → 给 CLIP Text Encode(提示词)

VAE → 给 VAE Decode(出图)

地位:所有生成的起点;你选哪个 Checkpoint,基本就决定了画面风格上限(写实、动漫、插画、科幻等)。

三、和 LoRA/VAE/ControlNet 的区别(关键)

✅ Checkpoint(底模):完整大模型,决定基础风格 + 画质;必选,一次只加载一个。

✅ LoRA(小模型):微调插件(几十 MB),在底模上叠加特定风格 / 人物 / 服饰;可选,可多个叠加。

✅ VAE:画质增强插件(几百 MB),专门优化色彩、锐度、细节;常随底模打包,也可单独换。

✅ ControlNet:结构控制插件(几百 MB),控姿势、构图、透视;可选。

四、常见 Checkpoint 类型(新手够用)

SD 1.5:最通用、兼容所有 LoRA/ControlNet;写实 / 动漫通吃。

SDXL 1.0:画质更高、细节更好、支持 1024+ 分辨率;需更强显卡。

写实类:Realistic Vision、Deliberate、MeinaMix(真人质感强)。

动漫类:Anything-V3、AbyssOrangeMix、ToonYou(二次元风格)。

五、为什么它叫 Checkpoint

训练大模型要跑几周甚至几个月,中途会每几小时 / 几轮存一次档,防止断电 / 崩了重跑。

这些存档就叫 Checkpoint;最后选效果最好的那个作为正式发布的底模。

六、快速记忆

Checkpoint = 完整底模 = 风格地基。

一个文件 = UNet + CLIP + VAE。

ComfyUI 里 Load Checkpoint 就是加载它,输出紫 / 黄 / 粉三个端口,连到后续节点。


checkpoints的数据流向?

Checkpoint 里打包了两个东西 ——UNet(大模型)+ CLIP(文本编码器);所以要先把 CLIP “取出来”,才能用它去编码你的文字。

你现在的困惑,来自把 “模型权重” 和 “数据流向” 搞混了。我分两层讲:

一、权重层面:Checkpoint = 打包好的一套 “工具”

一个 SD 大模型文件(.safetensors/.ckpt)里,同时存了三个独立子模型的权重:

MODEL(UNet):真正的画图大模型(负责去噪、生成图像)

CLIP:文本编码器(负责把文字→向量)

VAE:解码器(把潜变量→图片)

它们是并列关系,不是谁输入给谁;只是被打包在同一个文件里一起发布。

所以:

Load Checkpoint 的作用:把这三个子模型从文件里拆出来,变成可用的 “工具”

输出三个端口:MODEL、CLIP、VAE(都是 “工具 / 权重”,不是数据)

二、数据流向层面:文字 → CLIP → 向量 → UNet(才是你要的)

正确顺序(数据流动):

1.你输入文本(正向 / 反向提示词)

2.CLIP Text Encode 节点:

输入:CLIP(来自 Checkpoint 的权重) + 你的文字

输出:文本向量(conditioning)

3.KSampler(UNet):

输入:MODEL(UNet 权重) + 文本向量 + 噪声

输出:去噪后的潜变量

4.VAE Decode:

输入:VAE 权重 + 潜变量

输出:最终图片


ComfyUI  API如何使用?

下面我用最直接、可复制就能跑的方式,把 ComfyUI 本地 API 讲透(不绕云服务)。

一、ComfyUI API 本质一句话

ComfyUI 自带 HTTP+WebSocket API,你不需要装任何插件,启动后直接可用:

地址:http://localhost:8188

核心:把 “工作流 JSON” 发进去 → 排队执行 → 轮询 / WS 拿结果

二、先准备:导出 API 格式的工作流

1.在 ComfyUI 里搭好你的图生图 / 文生图流程

2.菜单 → Save (API Format)

1.png


3.得到一个 workflow_api.json(不带界面坐标,纯节点数据

关键点:

普通 Save → 带界面坐标(不能直接给 API 用)

Save (API Format) → 纯执行数据(API 专用)

三、核心接口(必记)

1. 提交任务(最重要)

POST /prompt

作用:下发工作流,返回 prompt_id(任务唯一 ID)

请求体(JSON)

json

{

  "client_id": "my-test-client",

  "prompt": {

    "3": {

      "class_type": "KSampler",

      "inputs": {

        "seed": 12345,

        "steps": 20,

        "cfg": 7,

        "sampler_name": "euler",

        "scheduler": "normal",

        "denoise": 1,

        "model": ["4", 0],

        "positive": ["6", 0],

        "negative": ["7", 0],

        "latent_image": ["5", 0]

      }

    },

    "4": { "class_type": "CheckpointLoaderSimple", "inputs": { "ckpt_name": "v1-5-pruned-emaonly.safetensors" } },

    "5": { "class_type": "EmptyLatentImage", "inputs": { "width": 512, "height": 512, "batch_size": 1 } },

    "6": { "class_type": "CLIPTextEncode", "inputs": { "text": "a beautiful cat", "clip": ["4", 1] } },

    "7": { "class_type": "CLIPTextEncode", "inputs": { "text": "ugly, blurry", "clip": ["4", 1] } },

    "8": { "class_type": "VAEEncode", "inputs": { "vae": ["4", 2], "pixels": ["9", 0] } },

    "9": { "class_type": "LoadImage", "inputs": { "image": "input.jpg" } }

  }

}

返回

json

{

  "prompt_id": "xxxx-xxxx-xxxx",

  "number": 1,

  "node_errors": {}

}

2. 查询任务状态

GET /history/{prompt_id}

作用:看任务是否完成、结果图片地址

3. WebSocket 实时进度(推荐)

地址:ws://localhost:8188/ws?client_id=my-test-client

作用:实时收到:

进度(%)

预览图

完成 / 失败通知

四、Python 调用示例(复制就能跑)

1. 提交任务

python

运行

import requests

import json


API_URL = "http://localhost:8188"

CLIENT_ID = "my-test-client"


# 1. 读取 API 工作流

with open("workflow_api.json", "r", encoding="utf-8") as f:

    workflow = json.load(f)


# 2. 修改参数(例如改提示词、种子)

workflow["6"]["inputs"]["text"] = "a beautiful dog"  # CLIPTextEncode

workflow["3"]["inputs"]["seed"] = 98765


# 3. 提交

resp = requests.post(

    f"{API_URL}/prompt",

    json={"client_id": CLIENT_ID, "prompt": workflow}

)

prompt_id = resp.json()["prompt_id"]

print("任务ID:", prompt_id)

2. 轮询结果

python

运行

import time


def get_result(prompt_id):

    while True:

        resp = requests.get(f"{API_URL}/history/{prompt_id}")

        data = resp.json()

        if prompt_id in data:

            return data[prompt_id]["outputs"]

        time.sleep(1)


outputs = get_result(prompt_id)

print("输出:", outputs)

# 图片地址示例:http://localhost:8188/view?filename=xxx.png

五、常见坑(你一定会遇到)

1.普通 Save 的 JSON 不能用 → 必须 Save (API Format)

2.节点 ID 不能乱改 → JSON 里的 "3"/"4"/"5" 是节点 ID,连线靠它

3.模型路径要对 → CheckpointLoaderSimple 的 ckpt_name 必须是 models/checkpoints/ 里的文件名

4.跨域 → 前端调用要加:

plaintext

--enable-cors-header

启动命令:python main.py --enable-cors-header

六、你之前的疑问(结合 API)

你问:为什么是大模型输出给 CLIP?

在 API JSON 里看:

json

"4": { "class_type": "CheckpointLoaderSimple", ... }  # 输出 MODEL/CLIP/VAE

"6": { "class_type": "CLIPTextEncode", "inputs": { "clip": ["4", 1] } }

["4",1] → 节点 4(Checkpoint)的第 1 个输出(CLIP)

传的是CLIP 权重,不是数据

数据流向:text → CLIP (权重) → vector → MODEL (权重) → image


可以编写自己的ComfyUI API 节点吗?

可以,而且很简单:ComfyUI 的 “节点” 本身就是为 API 设计的,你写的自定义节点天然支持 API 调用,不需要额外改造。下面从原理→最小示例→API 调用→常见坑,一步到位讲清楚。

一、核心结论

ComfyUI 节点 = Python 类 + 固定接口规范

放在 custom_nodes/ 下,重启自动注册,UI/API 都能用

你写的节点:

在界面:出现在右键菜单、可连线

在 API:出现在 prompt JSON 里,直接调用

二、写一个 “自定义 API 节点”(最小可运行)

1. 新建文件

路径:ComfyUI/custom_nodes/my_api_nodes.py

2. 完整代码(复制即用)

python

运行

# my_api_nodes.py

class StringToUpper:

    """自定义节点:把字符串转大写(UI/API 通用)"""


    # 1. 定义输入(API 会校验这个结构)

    @classmethod

    def INPUT_TYPES(cls):

        return {

            "required": {

                "text": ("STRING", {"default": "hello comfyui api"}),

            }

        }


    # 2. 定义输出类型

    RETURN_TYPES = ("STRING",)

    RETURN_NAMES = ("upper_text",)


    # 3. 执行函数(API 最终调用的逻辑)

    FUNCTION = "run"


    # 4. 菜单分类

    CATEGORY = "my_api_tools"


    def run(self, text):

        return (text.upper(),)



# 注册节点(必须,否则 UI/API 看不到)

NODE_CLASS_MAPPINGS = {

    "StringToUpper": StringToUpper

}


# 显示名称(可选)

NODE_DISPLAY_NAME_MAPPINGS = {

    "StringToUpper": "字符串转大写(API可用)"

}

3. 重启 ComfyUI

启动时会加载 custom_nodes/ 下所有 Python 文件

左侧菜单出现:my_api_tools → 字符串转大写(API可用)

三、用 API 调用你的自定义节点

1. 导出 API 格式工作流

界面拖入:StringToUpper + 你需要的其他节点

菜单 → Save (API Format) → 得到 workflow_api.json

2. API JSON 示例(核心部分)

json

{

  "client_id": "my-test",

  "prompt": {

    "1": {

      "class_type": "StringToUpper",

      "inputs": {

        "text": "hello from api"

      }

    }

  }

}

class_type = 你注册的类名 StringToUpper

inputs 和你 INPUT_TYPES 完全一致

3. Python 调用(和官方节点无区别)

python

运行

import requests

import json


API_URL = "http://localhost:8188"

workflow = {

    "client_id": "my-test",

    "prompt": {

        "1": {

            "class_type": "StringToUpper",

            "inputs": {"text": "hello comfyui api"}

        }

    }

}


resp = requests.post(f"{API_URL}/prompt", json=workflow)

print(resp.json())

返回结果会包含 upper_text: "HELLO COMFYUI API"

四、支持复杂类型(如 CLIP、MODEL、IMAGE)

你之前关心的 CLIP / 文本编码,自定义节点也能对接:

python

运行

class MyCLIPTextEncode:

    @classmethod

    def INPUT_TYPES(cls):

        return {

            "required": {

                "text": ("STRING", {"multiline": True}),

                "clip": ("CLIP",)  # 直接接收 Checkpoint 输出的 CLIP

            }

        }

    RETURN_TYPES = ("CONDITIONING",)

    FUNCTION = "encode"

    CATEGORY = "my_api_tools"


    def encode(self, text, clip):

        # 调用 ComfyUI 原生 CLIP 编码逻辑

        tokens = clip.tokenize(text)

        cond = clip.encode_from_tokens(tokens, return_pooled=True)

        return (cond,)

API 里连线:CheckpointLoader → MyCLIPTextEncode (clip输入)

完全遵循原生数据流向:text → CLIP → CONDITIONING → KSampler

五、常见坑(避坑)

必须注册:NODE_CLASS_MAPPINGS 不能少,否则 API 找不到节点

类型严格:INPUT_TYPES/RETURN_TYPES 必须和实际数据匹配(如 CLIP/MODEL/IMAGE)

API 专用导出:必须用 Save (API Format),普通 Save 带 UI 坐标,API 不认

重启生效:修改自定义节点代码后,必须重启 ComfyUI

六、一句话总结

写自定义节点 = 写带固定接口的 Python 类,放在 custom_nodes 目录,天然支持 UI 和 API,没有额外步骤。你可以封装任何逻辑:文本处理、模型加载、API 接口调用、CLIP 编码定制等。


ComfyUI API 节点为何看到custom_nodes 目录里很多子目录,而主目录下.py很少

一句话:因为 ComfyUI 把 “每个自定义节点包” 都当成一个独立 Python 模块(文件夹)来加载,所以都是子目录,主目录很少直接放 .py。下面把原理、规范、现状都说清楚。

一、加载机制:它只扫 “目录包”,不扫散文件

ComfyUI 启动时对 custom_nodes/ 的逻辑是:

遍历 custom_nodes/ 下的每一个子文件夹

对每个子文件夹,看里面有没有 __init__.py

有 → 当成一个 Python 模块包,执行导入,读取 NODE_CLASS_MAPPINGS,注册节点

主目录里直接放的 .py,默认不会被自动加载(除非你手动改启动代码)

所以:

子目录多 = 装了很多节点插件(每个插件一个文件夹)

主目录 .py 少 = 大家都按规范做成 “目录包”,不扔散文件

二、标准结构:一个插件 = 一个文件夹

正规自定义节点(比如 ControlNet、Impact Pack、FaceDetailer)都长这样:

plaintext

custom_nodes/

├── comfyui_controlnet_aux/      # 插件A:独立子目录

│   ├── __init__.py               # 必须:包入口,导出 NODE_CLASS_MAPPINGS

│   ├── nodes.py                   # 节点代码

│   ├── utils/                     # 工具子模块

│   ├── models/                     # 模型/权重

│   └── js/                        # 前端UI

├── ComfyUI-Impact-Pack/         # 插件B:独立子目录

│   ├── __init__.py

│   ├── nodes/

│   ├── ...

└── my_single_node.py             # 很少见:直接放主目录的散文件(不推荐)

为什么要这样?

依赖隔离:每个插件自己的 utils、models、js 不打架

方便安装 / 卸载:删一个文件夹 = 彻底卸载插件

前后端分离:js 放在子目录,ComfyUI 能自动找到并加载前端组件

版本管理:每个插件独立更新,互不影响

三、为什么你看到 “主目录 .py 很少”

官方推荐规范:所有成熟插件都做成 “目录包”,没人往主目录扔散文件

散文件有坑:

主目录 .py 不会自动加载,要手动改代码

容易命名冲突(两个插件都叫 utils.py)

没法带 js、models、依赖文件

你装的都是成熟插件:ControlNet、Impact Pack、FaceDetailer 等,全是子目录形式

四、你自己写节点:两种玩法

1)简单单文件(临时测试)

直接扔 custom_nodes/my_test.py:

python

运行

# my_test.py

class HelloNode:

    INPUT_TYPES = lambda: {"required": {"text": ("STRING", {"default": "hi"})}}

    RETURN_TYPES = ("STRING",)

    FUNCTION = "run"

    CATEGORY = "test"

    def run(self, text):

        return (text,)


NODE_CLASS_MAPPINGS = {"HelloNode": HelloNode}

⚠️ 缺点:要手动在 __init__.py 里 import,否则不加载;没法带前端 js。

2)标准目录包(推荐,和主流插件一致)

plaintext

custom_nodes/my_plugin/

├── __init__.py

└── nodes.py

__init__.py:

python

运行

from .nodes import *

NODE_CLASS_MAPPINGS = {

    "HelloNode": HelloNode

}

nodes.py 写节点类。

✅ 优点:自动加载、可加 js/utils/models、规范、API/UI 都正常。

五、总结

子目录多:每个子目录 = 一个独立插件包(标准做法)

主目录 .py 少:没人用散文件,都按规范做目录包

核心原因:ComfyUI 按 “Python 模块包(带 init.py 的文件夹)” 加载自定义节点

要不要我帮你把之前写的那个自定义节点,改成标准目录包结构,并附上完整 __init__.py,你直接放进去就能自动加载?


如何通过websocket调用ComfyUI?

下面用通俗语言 + 完整流程 + 可直接跑的 Python 示例,把「用 WebSocket 调用 ComfyUI」讲清楚。

(核心:发任务用 HTTP POST /prompt,看进度和结果用 WebSocket /ws

一、原理一句话讲明白

ComfyUI 的 API 是「HTTP 发任务,WebSocket 收实时进度 + 结果」:

HTTP POST /prompt:把你做好的工作流 JSON 发过去,让它开始画图;

WebSocket /ws?client_id=xxx:连上这个地址,全程监听:

队列状态、正在跑哪个节点、采样进度(%);

实时预览图(二进制);

最终生成图片的地址;

全程WebSocket 只收不发,任务是 HTTP 提交的。

二、关键地址(默认)

服务器地址:http://127.0.0.1:8188

提交任务:POST http://127.0.0.1:8188/prompt

监听进度:ws://127.0.0.1:8188/ws?client_id=随便一个唯一ID(UUID)

三、准备工作(3 步)

1. 开启 ComfyUI 并允许跨域(否则外部连不上)

启动时加参数:

bash

运行

python main.py --enable-cors-header

2. 导出工作流为「API 格式 JSON」

在 ComfyUI 里调好图生图 / 文生图流程;

菜单 → Save (API Format) → 保存成 workflow.json;

这个 JSON 就是你要 POST 出去的内容。

3. 安装依赖

bash

运行

pip install websockets requests

四、完整流程(带代码,直接能用)

1. 生成唯一 client_id(用来绑定 WebSocket 和任务)

python

运行

import uuid

client_id = str(uuid.uuid4())  # 例如:'f47ac10b-58cc-4372-a567-0e02b2c3d479'

2. 加载并修改工作流(动态改提示词 / 尺寸)

python

运行

import json


# 读取你导出的 API 工作流

with open("workflow.json", "r", encoding="utf-8") as f:

    prompt = json.load(f)


# 示例:改正向提示词(节点ID看你自己的,比如"6"是CLIP文本编码器)

prompt["6"]["inputs"]["text"] = "a beautiful girl, blue hair, masterpiece"

# 改反向提示词

prompt["7"]["inputs"]["text"] = "ugly, low quality"

# 改宽高

prompt["5"]["inputs"]["width"] = 768

prompt["5"]["inputs"]["height"] = 1024

3. HTTP POST 提交任务

python

运行

import requests


server = "http://127.0.0.1:8188"


payload = {

    "prompt": prompt,

    "client_id": client_id  # 关键!绑定 WebSocket

}


res = requests.post(f"{server}/prompt", json=payload)

res_data = res.json()

prompt_id = res_data["prompt_id"]  # 任务唯一ID,后面过滤用

print("任务已提交,prompt_id:", prompt_id)

4. WebSocket 监听进度 + 结果(核心)

python

运行

import asyncio

import websockets

import json


async def listen():

    uri = f"ws://127.0.0.1:8188/ws?client_id={client_id}"

    async with websockets.connect(uri) as ws:

        while True:

            msg = await ws.recv()

            # 先判断是文本还是二进制

            if isinstance(msg, bytes):

                # 二进制 = 预览图,可保存/显示

                print("收到预览图(二进制)")

                continue


            data = json.loads(msg)

            msg_type = data["type"]

            msg_data = data["data"]


            # 只处理我们这个 prompt_id 的消息

            if msg_data.get("prompt_id") != prompt_id:

                continue


            # 1. 队列状态更新

            if msg_type == "status":

                queue_len = msg_data["status"]["exec_info"]["queue_remaining"]

                print(f"队列剩余任务:{queue_len}")


            # 2. 开始执行某个节点

            elif msg_type == "executing":

                node = msg_data["node"]

                if node is None:

                    print("✅ 任务执行完成!")

                    break

                print(f"正在执行节点:{node}")


            # 3. 采样进度(最常用)

            elif msg_type == "progress":

                value = msg_data["value"]

                max_val = msg_data["max"]

                print(f"采样进度:{value}/{max_val}")


            # 4. 最终结果(图片/视频地址)

            elif msg_type == "execution_success":

                print("🎉 生成成功!结果:")

                print(json.dumps(msg_data, indent=2))

                break


# 运行监听

asyncio.run(listen())

五、WebSocket 会收到哪些消息(通俗解释)

表格

type 说明 你能拿到什么

status 队列变了 还有多少任务在等

executing 正在跑哪个节点 节点 ID(比如 KSampler)

progress 采样进度 当前步 / 总步数(如 12/20)

execution_success 全部跑完 图片文件名 / 地址

二进制数据 实时预览图 直接存为 jpg/png 就能看

六、常见坑(新手必看)

连不上 WebSocket:

启动 ComfyUI 必须加 --enable-cors-header;

防火墙放行 8188 端口;

client_id 必须和 POST /prompt 时一致。

收不到自己任务的消息:

WebSocket 消息里带 prompt_id,必须过滤,不然会收到别人的任务消息。

工作流改了代码就报错:

节点 ID(如 "6")是固定的,不要在 UI 里乱删加节点,否则 ID 变了代码要重改。

七、一句话总结

HTTP POST /prompt:发工作流,绑定 client_id;

WebSocket /ws?client_id=xxx:监听进度、预览图、最终结果;

上面代码复制就能跑,改改提示词和尺寸就能自动出图。


对ComfyUI主要节点作详细的介绍及实际使用?

通俗语言 + 功能 + 参数 + 实际用法 + 连接示例,把 ComfyUI 最核心、最常用的节点一次性讲全,覆盖:模型加载、文本编码、潜空间、采样、VAE 解码、图像保存、ControlNet、LoRA 等。

一、模型加载类(必用)

1. Load Checkpoint(加载主模型)

作用:加载 SD1.5/SDXL 等大模型(.safetensors/.ckpt),一次性输出 MODEL、CLIP、VAE 三样东西。

1.png


关键参数

ckpt_name:选你的模型文件(如 realisticVisionV51.safetensors)

怎么连

MODEL → KSampler

CLIP → CLIP Text Encode

VAE → VAE Decode

2. Load LoRA(加载 LoRA)

作用:给主模型 “加风格 / 加人物 / 加细节”,相当于小插件。

1.png


ComfyUI Load LoRA节点

关键参数

lora_name:选 LoRA 文件(如 animeStyle.safetensors)

strength_model:LoRA 强度(0.6–0.8 常用)

怎么连

输入:MODEL(从 Checkpoint 来)

输出:MODEL(传给 KSampler)

3. VAE Loader(单独加载 VAE)

作用:主模型 VAE 不好时,单独换一个(如 vae-ft-mse-840000-ema-pruned.safetensors),提升色彩 / 清晰度。

怎么连:输出 VAE → VAE Decode

二、文本编码类(必用)

CLIP Text Encode(Prompt)

作用:把你写的中文 / 英文提示词,变成模型能懂的 “数字向量”(CONDITIONING)。

1.png


关键参数

text:正面提示词(如 masterpiece, 1girl, blue hair)

负面提示词另放一个节点(如 low quality, blurry)

怎么连

输入:CLIP(从 Checkpoint 来)

输出:CONDITIONING → KSampler(positive/negative)

三、潜空间 Latent 类(必用)

Empty Latent Image(空潜图)

作用:创建一张空白 “潜空间图片”(SD 真实像素 ÷8),供 KSampler 去 “画”。

1.png


关键参数

width/height:宽高(必须是 64 倍数,如 512×768、1024×1024)

怎么连:输出 LATENT → KSampler

四、核心采样器(最重要)

KSampler(标准采样器)

作用真正画图的核心!往空潜图里反复去噪、迭代,把文字变成图像。

1.png1.png


关键参数(必懂)

seed:随机种子(固定 = 每次出一样图;随机 = 每次不同)

steps:步数(20–30 常用;越高越慢、细节越好)

cfg:提示词强度(7–10 常用;越高越贴近提示词、但易崩)

sampler_name:采样算法(euler a 艺术感强;dpmpp_2m 真实清晰)

scheduler:调度器(normal 通用;karras 细节更好)

怎么连(标准文生图)

MODEL → 输入

positive → 正面 CONDITIONING

negative → 负面 CONDITIONING

latent_image → Empty Latent Image

输出 LATENT → VAE Decode

KSampler Advanced(高级采样)

作用:可指定起始步 / 结束步,用于局部重绘(inpaint)、图生图强度控制。

1.jpg


ComfyUI KSampler Advanced节点

五、VAE 解码(必用)

VAE Decode

作用:把 KSampler 输出的潜空间图(LATENT),还原成肉眼能看的 RGB 图片(IMAGE)。

1.png


怎么连

输入:LATENT(KSampler 输出)、VAE(Checkpoint 或单独 VAE Loader)

输出:IMAGE → Save Image

六、图像输出(必用)

Save Image

作用:把 IMAGE 保存成 PNG/JPG,或直接在 UI 显示。

1.png


关键参数

filename_prefix:文件名前缀(如 my_art)

七、图生图(img2img)关键节点

Load Image

作用:加载一张参考图 / 原图,用于图生图、ControlNet、IP-Adapter。

1.png


ComfyUI Load Image节点

输出:IMAGE → VAE Encode

VAE Encode

作用:把 Load Image 的 RGB 图,压缩成潜空间图(LATENT),给 KSampler 继续画。

1.jpg


ComfyUI VAE Encode节点

怎么连:IMAGE → VAE Encode → KSampler(latent_image)

八、ControlNet(精准控制)

ControlNet Loader

作用:加载 ControlNet 模型(如 openpose、canny、depth),控制人物姿势、构图、线条

1.jpg


ComfyUI ControlNet Loader节点

ControlNet Apply

作用:把 ControlNet 模型 + 控制图(如姿势图),绑定到生成过程。

1.jpg


怎么连

输入:MODEL、CONTROL_NET、IMAGE(Load Image 来的控制图)、CONDITIONING

输出:MODEL → KSampler

九、最简单「文生图」工作流(直接照抄)

Load Checkpoint → 输出 MODEL、CLIP、VAE

CLIP Text Encode(正面)→ 输入 CLIP,写提示词

CLIP Text Encode(负面)→ 输入 CLIP,写负面词

Empty Latent Image → 设 512×768

KSampler → 连 MODEL、正面 / 负面 CONDITIONING、Empty Latent;steps=28、cfg=8、sampler=dpmpp_2m

VAE Decode → 连 KSampler 的 LATENT、VAE

Save Image → 连 VAE Decode 的 IMAGE

1.jpg


十、新手常见疑问

为什么图很糊? → 换 dpmpp_2m 采样器、步数≥25、用高质量 VAE。

提示词不生效? → CFG 调到 7–10、正面词写详细、负面词加 low quality。

SDXL 为什么要 1024×1024? → SDXL 原生训练分辨率就是 1024,512 会糊。


视频制作常用节点详细讲解及使用?

ComfyUI 里做视频最常用、最实用的节点,按「基础→生成→控制→后处理」顺序,用通俗语言 + 功能 + 参数 + 怎么连 + 实战用法一次性讲全。(含:AnimateDiff、SVD、Wan、帧处理、ControlNet、插帧、保存)

一、视频基础节点(必装、必用)

1. Load Video(加载视频)

作用:把现有视频读进来,拆成一帧帧图片(IMAGE 序列)。

常用参数

video_path:选你的 MP4/WebM

start_frame/end_frame:截取片段

frame_step:跳帧(= 隔几帧取一帧,加快处理)

怎么连

输出:IMAGE(帧序列) → 给 ControlNet / 图生图 / 风格迁移

2. Video2Frames / Load Image Batch(帧序列

作用:把「文件夹里的一堆图片」当成视频帧输入。

用法:出图→存文件夹→用这个节点读进来→做视频。

3. Frames2Video / Video Combine(帧→视频)

作用:把一堆图片(IMAGE 序列)拼成 MP4/GIF/WebP。

关键参数

frame_rate(fps):8–24(常用 12,流畅又不卡)

crf:画质(23 = 高清,28 = 普通)

怎么连

IMAGE 序列 → 输入 → 输出视频文件

4. Save Animated WEBP / PNG(存动图

作用:直接输出动图,适合发朋友圈 / 公众号。

二、AnimateDiff(最主流、显存友好:8G 可跑)

1. Load AnimateDiff Model(加载运动模块)

作用:给 SD 模型加「会动的能力」(运动模块 .safetensors)。

参数:model_name 选运动模型(如 mm_sd_v15_v2)

:MODEL(从 Checkpoint)→ 输入 → 输出:带运动的 MODEL

2. AnimateDiff Settings(运动参数)

作用:设定视频帧数、帧率、运动强度。

关键参数

total_frames:总帧数(16–32,太长会崩)

fps:8–12

motion_scale:运动幅度(0.5 = 小动,1.0 = 正常,1.5 = 大动)

连法:输出 settings → AnimateDiff Sampler

3. AnimateDiff Sampler(文生视频核心

作用:带运动地生成一帧帧潜空间(LATENT 序列)。

参数:和 KSampler 一样(steps=25、cfg=8、sampler=dpmpp_2m)

标准文生视频流程

Load Checkpoint → MODEL、CLIP、VAE

Load AnimateDiff Model → 给 MODEL 加运动

CLIP Text Encode(正 / 负提示词)

Empty Latent Image(512×768)

AnimateDiff Settings(24 帧、12fps、motion_scale=1)

AnimateDiff Sampler → 输出 LATENT 序列

VAE Decode → IMAGE 序列

Video Combine → MP4

4. AnimateDiffSlidingWindow(长视频)

作用:超过 32 帧时,用「滑动窗口」防止显存爆炸、画面崩坏。

用法:AnimateDiff Sampler → 这个节点 → VAE Decode

三、SVD(Stable Video Diffusion:图生视频强)

1. SVDLoader(加载 SVD 模型

作用:加载 SVD 专用视频模型(SVD/SVD-XT)。

输出:svd_model

2. SVD_img2vid_Conditioning(图生视频条件)

作用:把一张参考图变成视频的「初始帧」。

关键参数

motion_bucket_id:运动强度(127 = 中等,越高动越大)

fps:8–12

连法:Load Image(参考图)→ 输入 → 输出:positive、negative、latent

3. VideoLinearCFGGuidance(SVD 专用 CFG)

作用:让提示词在视频全程更稳定,减少闪烁。

4. SVD Sampler(图生视频核心)

流程:参考图 → SVD Conditioning → SVD Sampler → VAE Decode → Video Combine

四、Wan2.7(最新、质量最高:12G+ 显存)

1. Load Checkpoint (Wan)

作用:加载 Wan2.7 官方视频大模型。

2. Empty Latent Video

作用:直接创建「视频潜空间」(含帧数)。

参数:width=1280、height=720、length=24(帧数)

3. Wan Text Encode

作用:编码提示词,支持分段落提示词(比如前 8 帧 A、中间 8 帧 B、最后 8 帧 C)。

4. Wan Chunked I2V Sampler(分块图生视频)

作用:长视频自动分块,支持每段不同提示词,质量极高。

五、视频控制(防闪烁、稳画面、控动作)

1. ControlNet Preprocessor (Video Frame)

作用:对每一帧做 ControlNet 预处理(OpenPose/Canny/Depth)。

用法:VIDEO 帧序列 → 预处理 → ControlNet Apply(每一帧都受控)

2. ControlNet Apply(视频版)

作用:让视频全程姿势 / 线条 / 深度一致,不崩坏。

3. Latent Interpolate(潜空间插值)

作用:两张图之间平滑过渡,转场丝滑。

用法:图 A 潜空间 → 插值 → 图 B 潜空间 → 生成中间帧

4. Prompt Interpolation(提示词渐变)

作用:从提示词 A 慢慢变成提示词 B(比如「白天」→「夜晚」)。

5. Flicker Remover(去闪烁)

作用:AI 视频通病「闪烁」,用这个节点一键修复。

参数:strength=0.3–0.5(太强会变糊)

六、视频后处理(补帧、高清、加音乐)

1. Video Frame Interpolation(插帧,补流畅)

作用:12fps → 24fps,动作更丝滑(常用模型:RIFE/DAIN)。

2. Ultimate SD Upscale(帧超分)

作用:把每一帧放大(如 512→1024),视频变高清。

用法:生成的 IMAGE 序列 → 超分 → 再合成视频

3. FFmpeg 系列(加音乐、裁剪、转场)

AddAudio:给视频加背景音乐。

VideoTransition:两个视频之间加转场(淡入淡出、擦除)。

MultiCuttingVideo:裁剪视频片段。

七、3 套「直接能用」的视频工作流

✅ 新手首选(AnimateDiff 文生视频,8G 显存)

1.Load Checkpoint(SD1.5/RealisticVision)

2.Load AnimateDiff Model(mm_sd_v15_v2)

3.CLIP Text Encode(正:masterpiece, 1girl, blue hair;负:low quality, blurry)

4.Empty Latent Image(512×768)

5.AnimateDiff Settings(24 帧、12fps、motion_scale=1)

6.AnimateDiff Sampler(steps=25、cfg=8、dpmpp_2m)

7.VAE Decode

8.Video Combine(12fps)

✅ 图生视频(SVD,人物 / 风景动起来)

1.Load Image(参考图)

2.SVDLoader(SVD-XT)

3.SVD_img2vid_Conditioning(motion_bucket_id=127、fps=12)

4.SVD Sampler

5.VAE Decode

6.Video Combine

✅ 高质量长视频(Wan2.7,12G+)

1.Load Checkpoint (Wan)

2.Empty Latent Video(1280×720×24 帧)

3.Wan Text Encode(提示词)

4.Wan Chunked I2V Sampler

5.VAE Decode

6.Video Combine

八、常见坑(新手必看)

视频闪烁严重 → 加 Flicker Remover、降低 CFG(7–8)、用 dpmpp_2m 采样器。

画面崩坏 / 人脸畸形 → 加 ControlNet(OpenPose)、motion_scale 降到 0.8、步数≥25。

显存不够(8G) → 用 AnimateDiff、分辨率 512×768、帧数≤24、关闭滑动窗口。

运动太假 / 僵硬 → motion_scale 调到 1.2–1.5、fps=8–10、提示词加「dynamic motion, smooth animation」。







AI咒语

ComfyUI有API支持第三方调用吗

怎么知道节点如何连接?



####【豆包】

Q:ComfyUI有API支持第三方调用吗

A:...

ComfyUI 支持通过 API 进行第三方调用,其核心通过内置的 HTTP 服务器提供接口,允许外部程序(如脚本、其他应用)提交工作流、触发生成任务并获取结果。

核心 API 能力说明

1.基础交互方式

ComfyUI 启动时会默认开启一个本地 HTTP 服务器(默认端口 8188),通过发送 HTTP 请求(主要是 POST)与服务器交互,支持提交工作流定义、获取生成状态、下载输出结果等。

2.关键 API 端点

提交工作流任务:POST /prompt

接收一个包含工作流定义的 JSON 数据(即 ComfyUI 中导出的工作流 JSON),触发图像生成任务,返回一个 prompt_id 用于追踪任务状态。示例请求体(简化):

json

{

  "prompt": {

    "3": {

      "class_type": "KSampler",

      "inputs": {

        "seed": 12345,

        "steps": 20,

        "cfg": 7.0,

        // 其他节点参数...

      }

    },

    // 其他节点定义...

  }

}

查询任务状态:GET /history/<prompt_id>通过 prompt_id 查询任务是否完成,返回结果包含生成的图像数据(Base64 编码或文件路径)。

获取输出图像:GET /view?filename=<filename>&type=output直接获取生成的图像文件(需从历史记录中获取 filename)。


第三方调用示例

以 Python 为例,使用 requests 库调用 API 生成图像的基本流程:

python

运行

import requests

import json


# ComfyUI 服务器地址

COMFYUI_URL = "http://localhost:8188"


# 工作流 JSON(可从 ComfyUI 中导出)

workflow = {

  # 完整的工作流定义...

}


# 提交任务

response = requests.post(f"{COMFYUI_URL}/prompt", json={"prompt": workflow})

prompt_id = response.json()["prompt_id"]


# 轮询任务状态

import time

while True:

  history = requests.get(f"{COMFYUI_URL}/history/{prompt_id}").json()

  if prompt_id in history:

    # 获取生成的图像数据(Base64)

    output_node_id = next(iter(history[prompt_id]["outputs"].keys()))

    image_data = history[prompt_id]["outputs"][output_node_id]["images"][0]["data"]

    break

  time.sleep(1)


# 处理图像数据(如保存为文件)

import base64

from PIL import Image

from io import BytesIO


image = Image.open(BytesIO(base64.b64decode(image_data)))

image.save("output.png")

注意事项

工作流 JSON 格式:API 提交的工作流需严格遵循 ComfyUI 的节点定义格式(可在 ComfyUI 中通过「Save (API Format)」导出)。

版本兼容性:不同版本的 ComfyUI 可能调整 API 细节,建议参考官方文档或 GitHub 仓库 的最新说明。

扩展支持:社区有多个插件(如 ComfyUI-API-Wrapper)可简化 API 调用,提供更友好的接口封装。

通过上述方式,第三方程序可以灵活集成 ComfyUI 的图像生成能力,实现自动化工作流或自定义交互逻辑。



喂饭级教程!ComfyUI本地部署超详细指南

点击查看原文



Q:怎么知道节点如何连接?

A:...


先给你一句最关键的:只看颜色 + 左进右出 + 跟着报错走,就能搞定 90% 连接问题。下面分「一眼看懂」「怎么连」「怎么学」三部分讲清楚。

一、先认:端口颜色 = 数据类型(必须同色才能连)

6391542533623152344396383.jpg


🟣 Model(模型):SD 大模型

🟡 CLIP:文本编码用

🩷 VAE:解码 / 编码图像

🟠 Conditioning:提示词(正负)

🩷 Latent:潜变量(中间图像)

🔵 Image:普通图片

🟢 Mask:蒙版

🟢 Number:数字

一句话:不同颜色坚决连不上,同颜色才能拖线。

二、操作:怎么拖线、怎么断、怎么快速连

1. 基本连接(左进右出)

节点左边是输入(In),右边是输出(Out)

按住右边输出圆点 → 拖到另一个节点左边同色输入圆点 → 松手就连上

1.gif


断开:右键连线 → 选 Disconnect;或从输入点往外拖一下取消

2. 数量规则(很重要)

输出:1 对多:一个输出可连给多个节点(比如同一个模型给正负提示词)

1.png


输入:1 对 1:一个输入只能接一条线,再接会把旧线顶掉

3. 快速找可连接节点(新手神器)

从任意端口往外拖线,能连的节点会亮、不能连的会灰掉

1.jpg


直接选,系统自动帮你插好端口,不用自己猜

三、核心流程:标准文生图是怎么连的(记这个就够)

1 Load Checkpoint(加载模型)

输出:MODEL(紫)、CLIP(黄)、VAE(粉)

2 CLIP Text Encode(Positive)

输入:CLIP(黄)

输出:CONDITIONING(橙)→ 连 KSampler positive

3 CLIP Text Encode(Negative)

输入:CLIP(黄)

输出:CONDITIONING(橙)→ 连 KSampler negative

4 Empty Latent Image(设置尺寸)

输出:LATENT(粉)→ 连 KSampler latent_image

5 KSampler(采样出图)

输入:MODEL、positive、negative、latent_image

输出:LATENT(粉)→ 连 VAE Decode

6 VAE Decode(解码成图)

输入:LATENT、VAE

输出:IMAGE(蓝)→ 连 Preview / Save Image

7 Preview Image / Save Image(看结果 / 保存)

图示意(文字版):

plaintext

Checkpoint ── MODEL → KSampler

            ── CLIP → 正/负 CLIP Text Encode ── CONDITIONING → KSampler

            ── VAE → VAE Decode


Empty Latent ── LATENT → KSampler ── LATENT → VAE Decode ── IMAGE → Preview/Save

四、新手怎么快速学会「谁连谁」

1. 先抄现成工作流(最快)

社区随便下一个文生图 / 图生图工作流(.json)

拖进 ComfyUI,顺着线看颜色和流向,对照上面标准流程理解

改一改参数、换个模型,看会不会报错、结果怎么变

2. 看报错信息(最准)

连错会直接红字提示,比如:

TypeError: Cannot connect ... → 颜色 / 类型不对

Multiple links to input → 一个输入连了多个输出

报错会告诉你哪个节点、哪个端口错了,直接改就行

3. 记住几个高频固定配对

CLIP → CLIP Text Encode → KSampler(positive/negative)

Checkpoint → KSampler(model)

Empty Latent → KSampler(latent_image)

KSampler(latent)→ VAE Decode → Image

五、给你一个极简练习步骤(10 分钟上手)

1 拖入:Load Checkpoint、2×CLIP Text Encode、Empty Latent、KSampler、VAE Decode、Preview Image

2 按颜色 + 左进右出,照着标准流程连一遍

3 点 Queue Prompt,能跑出图就成功

4 故意连错一个(比如橙→紫),看报错,加深印象


通过ComfyUI接口生成图片成功代码

using System;

using System.IO;

using System.Net.Http;

using System.Net.WebSockets;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

using Newtonsoft.Json;

using Newtonsoft.Json.Linq;

using System.Windows.Forms;

namespace CallComfyUI

{

    public class ComfyUIClient

    {

        public string serverUrl = "http://127.0.0.1:8188";

        private string clientId = Guid.NewGuid().ToString();

        private HttpClient httpClient;


        public ComfyUIClient()

        {

            httpClient = new HttpClient();

        }


        public async Task<string> QueuePrompt(object workflow)

        {

            object obj = new

            {

                client_id = clientId,

                prompt = workflow

            };


            string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);

            StringContent content = new StringContent(json, Encoding.UTF8, "application/json");

            HttpResponseMessage resp = await httpClient.PostAsync(serverUrl + "/prompt", content);

            string result = await resp.Content.ReadAsStringAsync();


            JObject data = JObject.Parse(result);

            return (string)data["prompt_id"];

        }


        public async void WatchWebSocketProgress(string promptId, Action<string> onProgress)

        {

            ClientWebSocket ws = new ClientWebSocket();

            string wsUrl = "ws://127.0.0.1:8188/ws?client_id=" + clientId;


            try

            {

                await ws.ConnectAsync(new Uri(wsUrl), CancellationToken.None);

                byte[] buffer = new byte[4096];


                while (ws.State == WebSocketState.Open)

                {

                    try

                    {

                        var result = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

                        if (result.MessageType != WebSocketMessageType.Text) continue;


                        string json = Encoding.UTF8.GetString(buffer, 0, result.Count);

                        JObject msg = JObject.Parse(json);

                        string msgType = (string)msg["type"];

                        JObject dataObj = msg["data"] as JObject;


                        if (dataObj == null) continue;


                        JToken pidToken = dataObj["prompt_id"];

                        if (pidToken == null || pidToken.ToString() != promptId) continue;


                        if (msgType == "progress")

                        {

                            int v = (int)dataObj["value"];

                            int m = (int)dataObj["max"];

                            onProgress("进度:" + v + "/" + m);

                        }

                    }

                    catch

                    {

                        break;

                    }

                }

            }

            catch

            {

            }

            finally

            {

                ws.Dispose();

            }

        }


        public async Task<bool> WaitForTaskComplete(string promptId, Action<string> onStatus, int interval = 1000)

        {

            while (true)

            {

                try

                {

                    string url = serverUrl + "/history/" + promptId;

                    string json = await httpClient.GetStringAsync(url);

                    JObject history = JObject.Parse(json);


                    if (history != null && history[promptId] != null)

                    {

                        return true;

                    }

                }

                catch { }


                onStatus("等待任务执行中...");

                await Task.Delay(interval);

            }

        }


        public async Task<JObject> GetHistory(string promptId)

        {

            string url = serverUrl + "/history/" + promptId;

            string json = await httpClient.GetStringAsync(url);

            return JObject.Parse(json);

        }


        public async Task<byte[]> GetImage(string filename)

        {

            string url = serverUrl + "/view?filename=" + filename;

            return await httpClient.GetByteArrayAsync(url);

        }

    }


    public static class ComfyUIRunner

    {

        public static async void Run(Label statusLabel, PictureBox pictureBox)

        {

            try

            {

                SetLabel(statusLabel, "加载工作流...");

                ComfyUIClient client = new ComfyUIClient();


                string jsonText = File.ReadAllText("createpic.json");

                JObject workflow = JObject.Parse(jsonText);


                JObject node3 = (JObject)workflow["3"];

                JObject inputs3 = (JObject)node3["inputs"];

                inputs3["seed"] = 123456;

                inputs3["steps"] = 28;

                inputs3["cfg"] = 9;


                JObject node4 = (JObject)workflow["4"];

                JObject inputs4 = (JObject)node4["inputs"];

                inputs4["ckpt_name"] = "anything-v5-PrtRE.safetensors";


                JObject node5 = (JObject)workflow["5"];

                JObject inputs5 = (JObject)node5["inputs"];

                inputs5["width"] = 512;

                inputs5["height"] = 512;


                JObject node6 = (JObject)workflow["6"];

                JObject inputs6 = (JObject)node6["inputs"];

                inputs6["text"] = "一位穿着汉服的漂亮女孩,超写实电影感";//beautiful scenery nature glass bottle landscape, purple galaxy bottle";


                JObject node7 = (JObject)workflow["7"];

                JObject inputs7 = (JObject)node7["inputs"];

                inputs7["text"] = "卡通风格";// "text, watermark";


                SetLabel(statusLabel, "提交任务...");

                string promptId = await client.QueuePrompt(workflow);

                SetLabel(statusLabel, "任务ID:" + promptId);


                client.WatchWebSocketProgress(promptId, msg => SetLabel(statusLabel, msg));


                bool ok = await client.WaitForTaskComplete(promptId, msg => SetLabel(statusLabel, msg));

                if (!ok)

                {

                    SetLabel(statusLabel, "任务失败");

                    return;

                }


                SetLabel(statusLabel, "任务完成,获取图片...");

                JObject history = await client.GetHistory(promptId);

                JObject promptHistory = (JObject)history[promptId];

                JObject outputs = (JObject)promptHistory["outputs"];


                foreach (JProperty prop in outputs.Properties())

                {

                    JObject node = (JObject)outputs[prop.Name];

                    JArray images = (JArray)node["images"];

                    if (images != null && images.Count > 0)

                    {

                        string filename = (string)images[0]["filename"];

                        byte[] data = await client.GetImage(filename);


                        using (MemoryStream ms = new MemoryStream(data))

                        {

                            SetImage(pictureBox, System.Drawing.Image.FromStream(ms));

                        }

                        File.WriteAllBytes("output.png", data);

                        SetLabel(statusLabel, "✅ 生成完成!");

                        break;

                    }

                }

            }

            catch (Exception ex)

            {

                SetLabel(statusLabel, "错误:" + ex.Message);

            }

        }


        private static void SetLabel(Label label, string text)

        {

            if (label.InvokeRequired)

                label.Invoke(new Action(() => label.Text = text));

            else

                label.Text = text;

        }


        private static void SetImage(PictureBox pb, System.Drawing.Image img)

        {

            if (pb.InvokeRequired)

                pb.Invoke(new Action(() => pb.Image = img));

            else

                pb.Image = img;

        }

    }

}


调用:

ComfyUIRunner.Run(this.lblStatus, this.pictureBox1);


ComfyUI秋叶整合包API如何设置授权访问?

一、自己加简易 Token 验证(本地 API 授权)

给秋叶包加一个简单 Token 校验(最实用):

进入 ComfyUI 目录,编辑 server.py

找到 def routes(self): 附近,加一个校验:

python

运行

# 自定义 API Token

API_TOKEN = "my_secret_token_123"


@app.before_request

def before_request():

    if request.path.startswith("/api/"):

        token = request.headers.get("X-API-Key")

        if token != API_TOKEN:

            return {"error": "Unauthorized"}, 401

保存,重启 ComfyUI

调用时在 Header 带:

plaintext

X-API-Key: my_secret_token_123

这样只有带正确 Token 才能访问 API,最适合程序调用。


二、公网安全暴露(反向代理 + 鉴权)

如果要把秋叶包放到公网,推荐用 Nginx + BasicAuth / JWT,不直接开放 8188。

Nginx 配置示例(BasicAuth)

nginx

server {

    listen 443 ssl;

    server_name your.domain.com;


    ssl_certificate fullchain.pem;

    ssl_certificate_key privkey.pem;


    location / {

        proxy_pass http://127.0.0.1:8188;

        proxy_set_header Upgrade $http_upgrade;

        proxy_set_header Connection "upgrade";


        # 账号密码

        auth_basic "ComfyUI Auth";

        auth_basic_user_file /etc/nginx/.htpasswd;

    }

}

生成密码文件:htpasswd -c /etc/nginx/.htpasswd admin

好处:8188 不对外,鉴权、SSL、WSS 都由 Nginx 处理。


公网安全暴露(反向代理 + 鉴权) 根据给的例子如何访问

我给你最简单、最安全、秋叶 ComfyUI 2.8.14 实测可用的一套:

公网暴露 + 账号密码鉴权 + 加密 HTTPS + 绝对安全

你照着复制就能用,我把访问方式也一起给你。

一、最终你会得到

公网地址:https://你的域名.com

访问时必须输入账号密码才能进 ComfyUI

API 调用也必须带鉴权,否则 401 拒绝

全程加密,非常安全

二、你只需要 2 个东西

一个域名(几块钱一年)

内网穿透 / 公网 IP(cpolar、natfrp、阿里云、自家宽带都行)

三、我给你 最简单可直接用的 Nginx 配置(复制即可)

1. nginx.conf 完整配置(带账号密码登录)

server {

    listen 80;

    server_name 你的域名.com;

    return 301 https://$host$request_uri;

}


server {

    listen 443 ssl;

    server_name 你的域名.com;


    # SSL 证书(你申请的免费证书)

    ssl_certificate      cert/fullchain.pem;

    ssl_certificate_key  cert/privkey.pem;


    # 基础安全配置

    ssl_protocols TLSv1.2 TLSv1.3;

    ssl_ciphers HIGH:!aNULL:!MD5;


    # 👇 这里开启账号密码访问

    auth_basic "ComfyUI Login";

    auth_basic_user_file C:/nginx/conf/.htpasswd;


    # 代理到本地 ComfyUI

    location / {

        proxy_pass http://127.0.0.1:8188;

        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;

        proxy_set_header Connection "upgrade";

        proxy_set_header Host $host;

        proxy_set_header X-Real-IP $remote_addr;

    }

}

四、创建账号密码(关键)在 nginx/conf 目录下新建一个文件 .htpasswd

内容格式:plaintext

admin:密码

例如:plaintext

test:123456

五、启动 Nginx 后你访问 ComfyUI 的方式

方式 1:浏览器访问(网页)打开:plaintexthttps://你的域名.com

会自动弹出账号密码输入框

输入你设置的账号密码 → 进入 ComfyUI方式 

2:API 访问(带鉴权)ComfyUI 的所有 API 都需要账号密码才能调用。

访问格式:plaintext

https://admin:123456@你的域名.com/api/prompt

或者在 Header 里带:

plaintext

Authorization: Basic YWRtaW46MTIzNDU2

六、最简单的公网访问示例(你直接复制)

假设:

域名:abc.com

账号:admin

密码:123456

网页访问

plaintext

https://abc.com

弹出登录框 → 输入 admin / 123456

API 访问

plaintext

https://admin:123456@abc.com/api/prompt

CURL 调用bash运行curl -u admin:123456 https://abc.com/api/prompt

七、这样做的好处(非常安全)

公网无法直接访问 8188

必须账号密码才能进

HTTPS 加密,不会被劫持

防止别人偷跑你的显卡

适合远程调用、团队共享、公网 API







Top