```markdown 文件 欧先生提供@全力以赴提供 # ComfyUI OpenAI API Proxy 基于 Rust 构建的高性能反向代理,将标准 OpenAI 图像/视频生成 API 调用无缝转换为 ComfyUI 后端请求。支持多后端健康检查、智能负载均衡、WebSocket 双通道、指数退避完全抖动、令牌桶限流、幂等键缓存、请求级响应缓存以及 OpenTelemetry 可观测性,为生成服务提供生产级可靠性。 ## 概述 `comfyui-openai-api` 是 OpenAI API 兼容客户端与 ComfyUI 工作流引擎之间的桥梁,核心职责: - **接收** 标准 OpenAI 格式的图像/视频生成请求 - **转换** 请求参数为 ComfyUI 工作流注入格式 - **路由** 根据配置策略将请求分发至健康的 ComfyUI 后端 - **管理** 异步任务生命周期,支持状态持久化与查询 - **交付** 符合 OpenAI API 规范的响应(Base64 编码图像/视频) 在 **LocalMiniDrama**(本地 AI 短剧全流程创作工具)等项目生态中,本代理承载着底层生成引擎的统一 API 基座角色,为从剧本到成片的完整链路提供稳定、可扩展的推理调度能力。 ## 核心特性 ### API 兼容性 - **OpenAI 图像生成** —— `POST /v1/images/generations`,同步返回 Base64 图像 - **视频生成扩展** —— `POST /v1/videos/generations`,异步返回 `task_id`,通过 `GET /v1/tasks/{task_id}` 查询结果 - **任务生命周期管理** —— 查询、列出、删除任务(`GET /v1/tasks`、`GET /v1/tasks/{task_id}`、`DELETE /v1/tasks/{task_id}`) - **模型列表** —— `GET /v1/models` 返回所有可用工作流(模型) - **后端状态查询** —— `GET /v1/backends` 查看各后端健康状态 - **健康检查** —— `GET /v1/health` 存活探针 - **视频子系统状态** —— `GET /v1/videos/health` - **Prometheus 指标** —— `GET /v1/metrics` - **API 帮助文档** —— `GET /v1/help` ### 多后端管理 - 支持配置多个 ComfyUI 后端节点,按名称 (`?backend=xxx`) 显式指定或自动选择 - **定期健康检查**:通过请求每个后端的 `/system_stats`,连续失败达阈值自动摘除,恢复后自动加入 - **负载均衡策略**:轮询(Round Robin)、最少连接数(Least Connections)、随机(Random),可在配置文件中切换 ### 前置条件 - Rust 1.70+ - ComfyUI 后端(需启用 `--api` 模式) ### 运行 ./target/release/comfyui-openai-api ## API 端点详解 所有端点均以 `/v1` 为前缀。以下是完整列表: | 端点 | 方法 | 说明 | |------|------|------| | `/v1/models` | GET | 列出所有可用模型(工作流文件名) | | `/v1/health` | GET | 简单存活检查 | | `/v1/backends` | GET | 查看所有后端健康状态 | | `/v1/images/generations` | POST | 图像生成,同步返回 | | `/v1/videos/generations` | POST | 视频生成,异步返回 `task_id` | | `/v1/tasks` | GET | 列出所有任务状态 | | `/v1/tasks/{task_id}` | GET / DELETE | 查询或删除单个任务 | | `/v1/videos/health` | GET | 视频生成子系统状态 | | `/v1/metrics` | GET | Prometheus 指标导出 | | `/v1/help` | GET | API 帮助文档(JSON) | ### 1. 图像生成 `POST /v1/images/generations` **请求示例** ```bash curl -X POST 'http://localhost:8080/v1/images/generations?backend=backend-a' \ -H 'Content-Type: application/json' \ -d '{ "model": "sdxl-workflow", "prompt": "a cat wearing a hat, masterpiece", "negative_prompt": "low quality, blurry", "size": "1024x1024", "n": 1, "seed": 42, "reference_images": [ {"name": "ref1", "data": "data:image/png;base64,iVBOR..."} ] }' ``` **请求参数(Body)** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | `model` | string | 是 | 工作流文件名(不含 `.json`) | | `prompt` | string | 否 | 正向提示词 | | `negative_prompt` | string | 否 | 负向提示词 | | `size` | string | 否 | 尺寸,如 `"1024x1024"`(可被配置文件覆盖) | | `seed` | integer | 否 | 随机种子 | | `n` | integer | 否 | 生成数量(批次大小) | | `reference_images` | array | 否 | 参考图数组 `[{name, data}]` | | `image` | array | 否 | Base64 图片字符串数组(等效于 `reference_images`) | **查询参数** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | `backend` | string | 否 | 指定后端名称,未指定时自动使用负载均衡策略 | **响应格式** ```json { "created": 1704067200, "data": [ { "b64_json": "iVBORw0KGgoAAAANSUhEUg..." } ] } ``` ### 2. 视频生成 `POST /v1/videos/generations` **请求示例** ```bash curl -X POST 'http://localhost:8080/v1/videos/generations?backend=backend-b' \ -H 'Content-Type: application/json' \ -d '{ "model": "video-workflow", "content": [ {"type": "text", "text": "a dog running in the park"}, {"type": "image_url", "image_url": {"url": "https://example.com/ref.png"}, "role": "reference_image"} ], "duration": 5, "resolution": "720p" }' ``` **请求参数(Body)** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | `model` | string | 是 | 视频工作流文件名 | | `content` | array | 是 | 内容数组,每项可为 `{"type":"text", "text":"..."}` 或 `{"type":"image_url", "image_url":{"url":"..."}, "role":"reference_image"}` | | `duration` | integer | 否 | 时长(秒),默认 5 | | `resolution` | string | 否 | `"720p"` 或 `"1080p"` | | `ratio` | string | 否 | 宽高比,如 `"16:9"` | | `local_prompts` | string | 否 | 多镜头提示词,格式 `[起始-结束]\n描述` | | `global_prompt` | string | 否 | 全局提示词 | | `guide_strengths` | array | 否 | 引导强度数组 | **响应格式** ```json { "task_id": "vid-1715432100123-789" } ``` ### 3. 任务查询 `GET /v1/tasks/{task_id}` ```bash curl http://localhost:8080/v1/tasks/vid-1715432100123-789 ``` 响应示例(处理中): ```json { "status": "processing" } ``` 响应示例(已完成): ```json { "status": "completed", "video_url": "http://backend-b:8000/view?filename=video.mp4&subfolder=&type=output", "b64_json": "..." } ``` 响应示例(失败): ```json { "status": "failed", "error": "ComfyUI node error: ..." } ``` ### 4. 列出所有任务 `GET /v1/tasks` ```bash curl http://localhost:8080/v1/tasks ``` 返回: ```json { "tasks": [ { "task_id": "vid-1715432100123-789", "status": "completed" }, { "task_id": "img-1715432100456-123", "status": "processing" } ] } ``` ### 5. 删除任务 `DELETE /v1/tasks/{task_id}` ```bash curl -X DELETE http://localhost:8080/v1/tasks/img-1715432100456-123 ``` 成功时返回 HTTP `204 No Content`。 ### 6. 其他端点 - **列出模型** `GET /v1/models` ```bash curl http://localhost:8080/v1/models ``` 响应: ```json { "object": "list", "data": [ { "id": "sdxl-workflow", "object": "model", "owned_by": "comfyui-openai-api" }, { "id": "video-workflow", "object": "model", "owned_by": "comfyui-openai-api" } ] } ``` - **后端健康状态** `GET /v1/backends` ```json { "backends": [ { "name": "backend-a", "healthy": true }, { "name": "backend-b", "healthy": false } ] } ``` - **存活探针** `GET /v1/health`:返回 `OK` - **Prometheus 指标** `GET /v1/metrics`:返回标准 Prometheus 文本格式指标。 ### 完整配置项详解 ```yaml # 日志级别:trace, debug, info, warn, error log_level: "info" # 代理服务绑定地址和端口 server: host: "0.0.0.0" port: 8080 # 多后端列表,至少需要一个后端 comfyui_backends: - name: "backend-a" # 唯一名称,用于通过 ?backend= 选择 host: "127.0.0.1" # ComfyUI 地址 port: 8000 # ComfyUI 端口 default: true # 是否默认后端(用于 WebSocket 连接) - name: "backend-b" host: "192.168.1.100" port: 8188 default: false # 代理内部设置 comfyui_backend: client_id: "comfyui-api" # WebSocket 客户端 ID workflows_folder: "./workflows" # 工作流 JSON 存放目录 use_ws: true # 是否启用 WebSocket 连接默认后端 input_dir: "./cache" # 图片缓存目录,保存上传的参考图 # 路由与运行时配置 routing: timeout_seconds: 3600 # ComfyUI 任务总超时(秒) max_payload_size_mb: 500 # 请求体最大大小(MB) Image_Width: 1280 # 图像默认宽度(可被请求中的 size 覆盖) Image_Height: 704 # 图像默认高度 video_Width: 1024 # 视频默认宽度 video_Height: 576 # 视频默认高度 fps: 24 # 默认帧率 free_model_before_video: true # 生成视频前是否调用 ComfyUI /free 释放显存 # 负载均衡策略,可选值:RoundRobin, LeastConnections, Random lb_strategy: "RoundRobin" # 令牌桶限流(可选,注释或删除则限流不生效) rate_limit: max_tokens: 60 # 桶容量 refill_rate: 1.0 # 每秒补充令牌数 # 请求级响应缓存(可选,注释或删除则缓存不生效) response_cache: ttl_secs: 600 # 缓存有效期(秒) max_entries: 500 # LRU 最大条目数 # 是否启用幂等键检查(Idempotency-Key 头) enable_idempotency: true # 优雅关闭最长等待时间(秒),超时后强制退出 graceful_shutdown_timeout_secs: 30 # 健康检查间隔(秒)与连续失败阈值 health_check_interval_secs: 15 health_check_fail_threshold: 3 ``` ## 架构与请求流程 ### 架构概览 ``` ┌──────────────────────────────────────┐ │ OpenAI 兼容客户端 │ │ (Python, JS, curl, LocalMiniDrama) │ └────────────────┬─────────────────────┘ │ HTTP POST /v1/images/generations ▼ ┌──────────────────────────────────────┐ │ comfyui-openai-api │ │ ┌──────────┐ ┌────────────────┐ │ │ │ 限流器 │ │ 幂等键检查 │ │ │ └──────────┘ └────────────────┘ │ │ ┌──────────┐ ┌────────────────┐ │ │ │ 工作流 │ │ 后端池 & LB │ │ │ │ 注入器 │ │ + 健康检查 │ │ │ └──────────┘ └────────────────┘ │ │ ┌──────────────────────────────┐ │ │ │ WebSocket / HTTP 轮询 │ │ │ │ (全抖动退避) │ │ │ └──────────────────────────────┘ │ └────────────────┬─────────────────────┘ │ ▼ ┌──────────────────────────────────────┐ │ ComfyUI 后端 A (健康) │ │ ComfyUI 后端 B (健康) │ │ ComfyUI 后端 C (不健康,已摘除) │ └──────────────────────────────────────┘ ``` ## 与 LocalMiniDrama 的生态协同 - **统一生成接口**:`LocalMiniDrama` 通过标准 OpenAI API 调用本代理,无需关心底层 ComfyUI 工作流细节。 - **批量分镜生成**:逐镜生成流程可借助多后端负载均衡实现并行加速。 - **角色一致性**:通过 `X-Consistent-Role` 头与种子追踪器联动,保持同一角色多分镜外貌一致。 - **视频模型支持**:内置豆包 Seedance、通义万相、Vidu 等工作流注入兼容,覆盖短剧制作的多模型需求。 ## 故障排查 | 现象 | 可能原因 | 排查方法 | |------|---------|---------| | 502 Bad Gateway | ComfyUI 后端不可达 | 检查 `comfyui_backends` 配置中 host/port 是否正确,确认 ComfyUI 已启动 `--api` | | 404 Workflow not found | `model` 参数对应的工作流文件不存在 | 确认 `workflows_folder` 目录下存在 `{model}.json` 文件 | | 400 Invalid request | 请求体格式错误或 Base64 解码失败 | 检查 JSON 格式,验证 Base64 编码有效性 | | 504 Timeout | 生成时间超过 `timeout_seconds` | 增大超时值或检查 ComfyUI 日志中的节点错误信息 | | 429 Too Many Requests | 触发令牌桶限流 | 调整 `rate_limit` 配置或降低请求频率 | | 后端被摘除 | 健康检查连续失败 | 检查 ComfyUI `/system_stats` 是否正常返回,网络连通性 | ## 版本历史 ### v0.3.0 - 🏗️ 模块化架构重构,拆分 handlers/backend/transport/middleware/cache/workflows - 🔄 多后端健康检查与负载均衡(RoundRobin / LeastConnections / Random) - 🔒 令牌桶限流中间件 - 🆔 幂等键支持 - 💾 请求级 LRU 响应缓存 - 📡 OpenTelemetry 分布式追踪 - 🧹 优雅关闭与任务排水 - 🌱 角色种子稳定性追踪器 - 📋 新增 `/v1/models`、`/v1/backends`、`/v1/tasks` 列表与删除等端点 ### v0.2.0 - 视频生成支持 - 多后端手动路由 - 任务持久化(tasks.json) - PromptRelayEncode / LTXVAddGuideMulti 节点注入 ### v0.1.0 - 初始版本,OpenAI 图像生成兼容 ## 贡献指南 欢迎通过 Issue 和 Pull Request 参与贡献。请遵循以下准则: - 为新增的公共函数和模块添加文档注释 - 面向用户的功能改动需同步更新配置示例和 API 文档(即本 README 与 /v1/help 端点) - 针对多种工作流配置进行测试 - 遵循现有代码风格和模块组织方式