2026/6/20 10:56:29
网站建设
项目流程
php网站语言切换功能如何做,163企业邮箱服务器怎么设置,南京网站建,学摄影的网站有哪些Qwen-Image-2512-ComfyUI API集成#xff1a;Flask调用封装代码实例
1. 为什么需要把ComfyUI变成API服务
你有没有遇到过这样的情况#xff1a;在ComfyUI界面里点点选选#xff0c;生成一张图很顺手#xff0c;但想把它嵌进自己的网页、小程序或者自动化流程里#xff0…Qwen-Image-2512-ComfyUI API集成Flask调用封装代码实例1. 为什么需要把ComfyUI变成API服务你有没有遇到过这样的情况在ComfyUI界面里点点选选生成一张图很顺手但想把它嵌进自己的网页、小程序或者自动化流程里就卡住了ComfyUI默认是图形界面不直接对外提供HTTP接口。而真实项目中我们往往需要让图片生成功能“被调用”——比如电商后台批量生成商品图、内容平台自动配图、甚至接进企业微信机器人发图。这时候Qwen-Image-2512-ComfyUI这个镜像就很有价值它已经预装了阿里最新版的Qwen-Image模型2512版本还集成了ComfyUI环境4090D单卡就能跑起来。但光有镜像还不够得让它“听懂”程序发来的请求。本文不讲怎么从零搭环境也不重复部署步骤而是聚焦一个工程师真正要落地的事用Flask写一套轻量、稳定、可复用的API封装层把ComfyUI变成你随时能POST调用的服务。整套方案完全本地运行不依赖云服务代码简洁不到150行支持传入提示词、尺寸、采样步数等常用参数返回生成图的URL或base64。你不需要改ComfyUI源码也不用碰Node.js只要会写Python就能快速接入。2. 环境准备与服务结构设计2.1 镜像基础确认你已按说明完成镜像部署在4090D单卡机器上拉起镜像运行/root/1键启动.sh通过“我的算力”进入 ComfyUI 网页端确认工作流可正常出图。这说明后端服务ComfyUI的/prompt接口已在本地http://127.0.0.1:8188运行。这是整个API封装的前提——我们不是重写推理而是做一层“翻译调度”。2.2 Flask服务定位与职责划分我们不替代ComfyUI而是站在它肩膀上构建能力模块职责你不用管的你需要控制的ComfyUI原生服务执行节点计算、加载模型、渲染图像模型权重路径、显存分配、节点逻辑仅需确保其/prompt接口可访问Flask API层接收HTTP请求 → 校验参数 → 构造ComfyUI Prompt JSON → 发送请求 → 轮询结果 → 返回图片请求超时重试策略、日志格式、错误码定义请求字段映射、默认值设定、响应结构简单说Flask是“前台接待员”ComfyUI是“后台画师”。接待员负责听懂客户说什么解析JSON、填好工单构造Prompt、催进度轮询、最后把画作交到客户手上返回图片。2.3 依赖安装与目录结构在镜像内执行建议在/root下新建qwen-api目录pip install flask requests pillow推荐目录结构如下清晰、易维护qwen-api/ ├── app.py # 主服务入口 ├── workflow_api.json # 从ComfyUI导出的API工作流关键 ├── utils.py # 图片处理、路径管理等工具函数 └── static/ └── outputs/ # 自动生成的图片存放目录ComfyUI默认输出路径注意workflow_api.json不是手写的而是从ComfyUI网页端导出的。打开内置工作流 → 点右上角「Queue Prompt」旁的「Save as API」→ 下载JSON文件放入项目根目录。这是保证API调用和界面操作效果一致的核心。3. 核心代码实现详解3.1 工作流JSON的关键字段解析打开你导出的workflow_api.json找到类似这样的节点6: { inputs: { text: A cat wearing sunglasses, summer vibe, clip: [12, 1] }, class_type: CLIPTextEncode }, 8: { inputs: { width: 1024, height: 1024, batch_size: 1 }, class_type: KSampler }我们要动态替换的就是这些inputs里的值。Flask收到请求后会提取prompt、width、height等参数精准注入到对应节点ID如6、8的inputs中。不是全文本替换而是基于节点ID的字典级更新——这才是稳定可靠的做法。3.2 Flask主服务app.py# app.py from flask import Flask, request, jsonify, send_file import requests import json import time import os from pathlib import Path from utils import get_image_path, save_workflow_with_params app Flask(__name__) # ComfyUI服务地址镜像内默认 COMFYUI_URL http://127.0.0.1:8188 # 加载原始工作流模板 with open(workflow_api.json, r, encodingutf-8) as f: WORKFLOW_TEMPLATE json.load(f) app.route(/generate, methods[POST]) def generate_image(): try: data request.get_json() prompt data.get(prompt, ).strip() if not prompt: return jsonify({error: prompt is required}), 400 # 提取参数设置默认值 width int(data.get(width, 1024)) height int(data.get(height, 1024)) steps int(data.get(steps, 30)) seed int(data.get(seed, -1)) # 动态注入参数到工作流核心逻辑 workflow save_workflow_with_params( WORKFLOW_TEMPLATE, promptprompt, widthwidth, heightheight, stepssteps, seedseed ) # 发送Prompt请求 resp requests.post( f{COMFYUI_URL}/prompt, json{prompt: workflow}, timeout5 ) resp.raise_for_status() queue_resp resp.json() prompt_id queue_resp[prompt_id] # 轮询获取结果最多等待90秒 for _ in range(90): history requests.get(f{COMFYUI_URL}/history/{prompt_id}).json() if prompt_id in history and outputs in history[prompt_id]: output list(history[prompt_id][outputs].values())[0] if images in output: img_info output[images][0] img_path get_image_path(img_info) if os.path.exists(img_path): # 返回图片URL假设Nginx已配置static代理 return jsonify({ status: success, image_url: f/static/outputs/{img_info[subfolder]}/{img_info[filename]}, prompt_id: prompt_id }) time.sleep(1) return jsonify({error: timeout waiting for image}), 504 except requests.exceptions.RequestException as e: return jsonify({error: fcomfyui request failed: {str(e)}}), 502 except Exception as e: return jsonify({error: fserver error: {str(e)}}), 500 if __name__ __main__: app.run(host0.0.0.0, port5000, debugFalse)这段代码做了四件关键事安全校验检查prompt非空参数类型转换防崩精准注入调用save_workflow_with_params只改目标节点不动其他逻辑异步等待用/history/{id}轮询避免长连接阻塞错误分层网络失败返回502超时返回504代码异常返回500——便于前端区分处理。3.3 参数注入工具utils.py# utils.py import json import os from pathlib import Path def save_workflow_with_params(workflow, **kwargs): 根据节点ID将参数注入到指定位置 # CLIPTextEncode节点通常ID为6或类似按你导出的JSON调整 if prompt in kwargs and 6 in workflow: workflow[6][inputs][text] kwargs[prompt] # KSampler节点控制尺寸、步数、随机种子 if 8 in workflow: # 假设KSampler节点ID是8 if width in kwargs: workflow[8][inputs][width] kwargs[width] if height in kwargs: workflow[8][inputs][height] kwargs[height] if steps in kwargs: workflow[8][inputs][steps] kwargs[steps] if seed in kwargs: workflow[8][inputs][seed] kwargs[seed] # 其他节点可依此类推如VAEDecode、SaveImage等 return workflow def get_image_path(img_info): 根据ComfyUI返回的image info拼出本地绝对路径 base_dir /root/comfyui/output # ComfyUI默认输出目录 subfolder img_info.get(subfolder, ) filename img_info[filename] return os.path.join(base_dir, subfolder, filename)关键提醒节点ID如6、8必须和你导出的workflow_api.json中实际ID严格一致。打开JSON文件搜索class_type: CLIPTextEncode和class_type: KSampler看它们前面的数字ID是多少然后在utils.py里对应修改。这是唯一需要你手动核对的地方。4. 启动服务与调用验证4.1 启动Flask服务在qwen-api/目录下执行nohup python app.py api.log 21 服务将在http://你的服务器IP:5000/generate监听POST请求。4.2 用curl测试最简验证curl -X POST http://localhost:5000/generate \ -H Content-Type: application/json \ -d { prompt: a cyberpunk cityscape at night, neon lights, rain, cinematic, width: 1024, height: 576, steps: 25 }成功响应示例{ status: success, image_url: /static/outputs/ComfyUI_2024-06-15/IMG_00001.png, prompt_id: abc123def456 }4.3 前端调用示例JavaScriptasync function callQwenAPI(prompt) { const res await fetch(http://your-server-ip:5000/generate, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ prompt: prompt, width: 1024, height: 1024 }) }); const data await res.json(); if (data.status success) { document.getElementById(result-img).src data.image_url; } }5. 实用技巧与避坑指南5.1 如何让生成图直接返回base64免静态服务如果你不想配Nginx代理静态文件想让API直接返回图片数据只需修改app.py中成功分支# 替换原来的 jsonify(...) 部分 with open(img_path, rb) as f: img_data f.read() import base64 encoded base64.b64encode(img_data).decode(utf-8) return jsonify({ status: success, image_base64: fdata:image/png;base64,{encoded}, prompt_id: prompt_id })这样前端拿到base64字符串直接赋给img src...即可显示零配置。5.2 多模型切换支持扩展思路Qwen-Image-2512只是起点。ComfyUI支持加载多个模型。你可以在workflow_api.json中把模型加载节点如CheckpointLoaderSimple的ckpt_name字段改为一个变量占位符然后在save_workflow_with_params里根据请求参数动态替换# 在workflow中预留 4: { inputs: { ckpt_name: {{model_name}} }, class_type: CheckpointLoaderSimple } # 注入时 if model_name in kwargs: workflow[4][inputs][ckpt_name] kwargs[model_name]再配合一个/models接口返回可用模型列表就能做成真正的多模型API网关。5.3 常见问题速查Q调用返回502但ComfyUI网页能出图A检查COMFYUI_URL是否正确必须是127.0.0.1:8188不能写localhost或外网IP确认/root/comfyui目录下output子目录有写入权限。Q轮询一直超时history里没outputsA打开ComfyUI网页看右下角WebSocket状态是否绿色检查workflow_api.json中SaveImage节点的filename_prefix是否为ComfyUI默认值否则路径拼接会失败。Q中文提示词乱码或不生效A确保workflow_api.json中CLIPTextEncode节点的text字段是UTF-8编码Flask接收JSON时加request.get_json(forceTrue)强制解码。6. 总结本文带你走通了一条从“能用”到“好用”的关键路径Qwen-Image-2512-ComfyUI镜像本身解决了模型和环境问题而Flask API封装则解决了工程集成问题。你学到的不是一段孤立代码而是一种可复用的方法论——不侵入原系统所有改动都在API层ComfyUI保持原样强可维护性参数注入逻辑集中增删字段只需改utils.py真生产就绪包含超时控制、错误分类、路径安全校验平滑可扩展base64返回、多模型支持、鉴权接入都只需几行代码。下一步你可以把这套API注册进你的内部服务发现系统加上Prometheus监控再用Swagger生成文档——Qwen-Image就真正成为你技术栈里一个标准的AI能力模块了。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。