StabilityMatrix + ComfyUI → Web API:从本地跑图到对外提供服务
用 StabilityMatrix 管理 ComfyUI 环境,开启 --listen 模式,封装成 REST API,再套一层 FastAPI/Express,让任何人都能通过 HTTP 调用你的 AI 画图服务。
你在本地装了 StabilityMatrix,跑 ComfyUI,出图效果不错。但每次都要开浏览器拖节点,没有办法给别人用,也没有办法接进自己的产品。
这篇文章解决这件事:把本地的 ComfyUI 变成一个真正可以调用的 API 服务,别人发一个 HTTP 请求,你这边返回图片。
一、环境:用 StabilityMatrix 管理
StabilityMatrix 是 Windows/macOS/Linux 上最好用的 AI 模型包管理器。它帮你解决:
- Python 虚拟环境隔离(不污染系统)
- ComfyUI / A1111 / Forge 一键安装升级
- 模型下载到统一目录
- 启动参数 GUI 配置
安装流程:
- 去 github.com/LykosAI/StabilityMatrix/releases 下载最新版
- 首次启动选存储目录(建议独立盘,模型很大)
- 点 Add Package → ComfyUI,安装
- 安装完成后先点一次「Launch」确认能正常出图
二、开启 API 模式
ComfyUI 内置 HTTP API,但默认只监听 127.0.0.1。要对外(或容器内)暴露,需要加启动参数。
在 StabilityMatrix 里加参数:
点 ComfyUI 右边的 ⚙️ → Extra Launch Arguments,加入:
--listen 0.0.0.0 --port 8188
⚠️
0.0.0.0代表监听所有网卡。局域网内可用,公网暴露要套一层鉴权。
启动后,局域网内任何机器都能访问 http://你的IP:8188。
验证 API 可用:
curl http://localhost:8188/system_stats
返回 JSON 说明 API 已就绪。
三、理解 ComfyUI 的 API 结构
ComfyUI 的 API 很简洁,核心就三个端点:
| 端点 | 方法 | 作用 |
|---|---|---|
/prompt | POST | 提交 workflow,返回 prompt_id |
/history/{prompt_id} | GET | 查询任务状态 + 结果 |
/view | GET | 下载输出图片 |
提交 Workflow 的 payload 格式:
先在 ComfyUI 网页界面设计好 workflow,然后点右上角 Save (API format),保存为 workflow_api.json。
这个 JSON 就是你的请求 body:
{
"prompt": { ...你的 workflow_api.json 内容... },
"client_id": "my-app-001"
}
轮询等结果:
import requests, time
def generate(workflow: dict, host="http://localhost:8188"):
r = requests.post(f"{host}/prompt", json={"prompt": workflow, "client_id": "demo"})
pid = r.json()["prompt_id"]
while True:
h = requests.get(f"{host}/history/{pid}").json()
if pid in h:
output = h[pid]["outputs"]
# output 里有 images 列表
img = output[list(output.keys())[0]]["images"][0]
return requests.get(f"{host}/view", params=img).content
time.sleep(1)
四、封装成自己的 API(FastAPI)
直接暴露 ComfyUI 的原始 API 太难用了:调用方需要懂 workflow 格式,参数分散。
套一层 FastAPI,把参数抽象成业务接口:
# app.py
from fastapi import FastAPI
from fastapi.responses import Response
import json, requests, time, copy
app = FastAPI()
COMFY = "http://localhost:8188"
# 加载 workflow 模板
with open("workflow_api.json") as f:
WORKFLOW_TPL = json.load(f)
@app.post("/generate")
def generate(prompt: str, width: int = 512, height: int = 512, steps: int = 20):
wf = copy.deepcopy(WORKFLOW_TPL)
# 找到 KSampler 节点,修改参数
for node in wf.values():
if node["class_type"] == "KSampler":
node["inputs"]["steps"] = steps
if node["class_type"] == "EmptyLatentImage":
node["inputs"]["width"] = width
node["inputs"]["height"] = height
if node["class_type"] == "CLIPTextEncode" and "positive" in str(node):
node["inputs"]["text"] = prompt
# 提交并等待
r = requests.post(f"{COMFY}/prompt", json={"prompt": wf, "client_id": "api"})
pid = r.json()["prompt_id"]
while True:
h = requests.get(f"{COMFY}/history/{pid}").json()
if pid in h:
imgs = list(h[pid]["outputs"].values())[0]["images"]
img_data = requests.get(f"{COMFY}/view", params=imgs[0]).content
return Response(content=img_data, media_type="image/png")
time.sleep(1)
启动:
pip install fastapi uvicorn requests
uvicorn app:app --host 0.0.0.0 --port 8000
现在你的 API:
curl "http://localhost:8000/generate?prompt=a+cat+in+space&width=768&height=768" \
--output cat.png
五、加鉴权(API Key)
对外服务不能裸跑,加一个简单的 Bearer token 校验:
from fastapi import Header, HTTPException
API_KEYS = {"sk-your-key-here", "sk-another-key"}
def verify(authorization: str = Header(...)):
token = authorization.removeprefix("Bearer ").strip()
if token not in API_KEYS:
raise HTTPException(status_code=401, detail="Unauthorized")
@app.post("/generate")
def generate(prompt: str, _=Depends(verify)):
...
调用时带上 header:
curl -H "Authorization: Bearer sk-your-key-here" \
"http://localhost:8000/generate?prompt=a+cat+in+space" \
--output result.png
六、让外网能用(内网穿透 / 反向代理)
本机跑,想让外网朋友用,有几种方案:
方案 A:Cloudflare Tunnel(推荐,免费)
# 安装 cloudflared
winget install Cloudflare.cloudflared
# 登录
cloudflared tunnel login
# 创建隧道
cloudflared tunnel create comfyui-api
# 运行
cloudflared tunnel --url http://localhost:8000
会给你一个 *.trycloudflare.com 域名,绑自己的域名也行。
方案 B:nginx 反向代理(有公网 IP)
server {
listen 443 ssl;
server_name api.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 120s; # 出图可能要等一会儿
}
}
方案 C:ngrok(最快,测试用)
ngrok http 8000
七、WebSocket 实时进度(可选)
等图的时候前端干等体验差。ComfyUI 支持 WebSocket 推送进度:
const ws = new WebSocket(`ws://localhost:8188/ws?clientId=my-app`);
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (msg.type === "progress") {
console.log(`进度:${msg.data.value}/${msg.data.max}`);
}
if (msg.type === "executing" && msg.data.node === null) {
console.log("完成!");
}
};
前端可以实时显示进度条,体验直接拉满。
总结
| 步骤 | 工具 | 作用 |
|---|---|---|
| 环境管理 | StabilityMatrix | Python 隔离 + ComfyUI 安装 |
| API 暴露 | --listen 0.0.0.0 | ComfyUI 内置 HTTP API |
| 业务封装 | FastAPI | 抽象参数,隐藏 workflow 细节 |
| 鉴权 | Bearer token | 防止滥用 |
| 对外暴露 | Cloudflare Tunnel | 免费、安全、不需要公网 IP |
| 实时进度 | WebSocket | 更好的用户体验 |
整套下来,你就有了一个:自己的 AI 出图 API,可以接进任何产品,可以分享给朋友,可以包一层前端做成 Web App。
Posted by Seraph @ u14.co · May 2026