把 ComfyUI 做成局域网出图服务:API 调用与队列管理

把 ComfyUI 做成局域网出图服务:API 调用与队列管理

内容标识:本文为 AI 辅助生成内容。依据 《人工智能生成合成内容标识办法》2025-09-01,已添加显式标识(本声明)与隐式标识(文件元数据 / 图片 ComfyUI 元信息)。文中技术细节与结论均由作者复核确认。

我在上一篇里把 ComfyUI 在本机跑通了(见 ComfyUI 本地部署指南),但真正的价值在于:显卡只有一块,要用图的人和脚本却有很多。与其每人装一套环境,不如把 ComfyUI 当成一个「局域网出图服务」——任何机器发一个 HTTP 请求就能排队出图。这篇记录改造过程和脚本侧的队列、超时、重试处理。

第一步:让 ComfyUI 监听局域网

ComfyUI 默认只监听本机回环地址 127.0.0.1,局域网其它机器访问不到。启动时加 --listen 参数即可:

python main.py --listen 0.0.0.0 --port 8188

启动后日志里会提示监听地址变为 0.0.0.0:8188,局域网内用 http://<服务器IP>:8188 就能打开界面。

注意开放监听等于把出图接口暴露给整个网段,没有任何鉴权。建议在路由器或主机防火墙层面做白名单,只允许可信网段访问。

第二步:拿到 API 格式的工作流 JSON

ComfyUI 界面上拖拽出来的工作流,默认保存的 JSON 是给前端画布用的,不能直接提交给 API。需要在设置里开启「开发者模式选项」(Dev Mode),保存按钮旁才会出现「Save (API Format)」,导出的才是后端可执行的节点图。

导出的 API JSON 是一个以节点 ID 为键的字典,每个节点包含 class_type 和 inputs。提交前通常要在脚本里动态改几个参数,比如提示词、种子和出图尺寸:

wf["6"]["inputs"]["text"] = prompt          # CLIP Text Encode 的提示词
wf["3"]["inputs"]["seed"] = random.randint(0, 2**32 - 1)  # KSampler 随机种子

第三步:提交任务并轮询结果

核心 API 只有三个:POST /prompt 提交、GET /history/{prompt_id} 查结果、GET /view 下载图片。ComfyUI 服务端自带队列,提交后立即返回 prompt_id,不必自己抢锁:

import requests, time

BASE = "http://10.11.200.172:8188"  # 换成你的服务器地址

def queue_prompt(workflow):
    r = requests.post(f"{BASE}/prompt",
                      json={"prompt": workflow}, timeout=10)
    r.raise_for_status()
    return r.json()["prompt_id"]

def wait_result(pid, timeout=180):
    deadline = time.time() + timeout
    while time.time() < deadline:
        h = requests.get(f"{BASE}/history/{pid}", timeout=10).json()
        if pid in h:
            return h[pid]["outputs"]
        time.sleep(2)
    raise TimeoutError(f"出图超时: {pid}")

拿到 outputs 后,遍历节点输出里的 images 字段,用 GET /view?filename=...&amp;type=output 把图片拉回来保存即可。

第四步:客户端侧的排队与重试

服务端队列只管「排队执行」,不管「失败补偿」。脚本侧要自己兜底三件事:

  1. 提交重试:网络抖动导致 POST /prompt 失败时,指数退避重试 3 次(间隔 2s/4s/8s),仍失败则放弃并记录。
  2. 超时判定:wait_result 超时后不要直接重提交——任务可能还在队列里。先 GET /queue 确认任务是否仍在排队或执行中,避免同一任务提交两遍白白翻倍占卡。
  3. 失败识别:history 里若出现 status.status_str == &quot;error&quot;,取出 messages 里的报错(常见是显存不足、模型路径错),按错误类型决定是否值得重试。
def queue_status(pid):
    q = requests.get(f"{BASE}/queue", timeout=10).json()
    running = [x[1] for x in q.get("queue_running", [])]
    pending = [x[1] for x in q.get("queue_pending", [])]
    return pid in running, pid in pending

如果有多台客户端并发提交,建议给每个客户端分配独立的 client_id,配合 WebSocket(/ws)可以拿到逐节点的执行进度,做进度条或看板时很有用;纯轮询方案不接 WebSocket 也完全够用。

总结

把 ComfyUI 服务化只需要三步:加 --listen 开放监听、导出 API 格式工作流、用 POST /prompt + GET /history 提交轮询。真正的工程量在客户端——超时判定要先查 /queue 防止重复提交,失败要区分「可重试的网络错」和「无意义的参数错」。这套接口稳定之后,任何脚本、定时任务甚至其他服务都能共享这块显卡,这才是本地出图环境的正确打开方式。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注