部署Qwen-Image,通过API返回可访问的图像URL
场景:当我们在本地部署了图像生成模型Qwen-Image的API服务之后,常见的API响应返回可能是生成图像的base64编码,或者二进制流。这种方式是将图像数据通过API直接返回给用户。而很多场景下,我们希望API能直接返回一个生成图像的URL。这个帖子将介绍,如何在服务器上,将生成的图像保存到指定目录,并将该目录开放可访问。
实现方式:FastAPI完成图像生成的调用,将生成图像保存到指定路径,返回URL;Nginx实现静态资源映射,将指定路径开放访问。
调整FastAPI
基于前面的部署,调整FastAPI启动脚本:
from fastapi import FastAPI
from pydantic import BaseModel
import requests
import copy
import json
import os
import urllib.parse
import time
from fastapi import HTTPException, Header
import base64
API_KEY = "12345"# ---------------- 配置 ----------------
COMFYUI_API_URL = "http://127.0.0.1:8188" # ComfyUI API 地址
WORKFLOW_FILE = "image_qwen_image_api.json" # 固定 workflow 文件
OUTPUT_DIR = "output_images"
POLL_INTERVAL = 1 # 秒STATIC_DIR = "/var/www/static" # 存储图片的目录
SERVER_BASE_URL = "http://server_ip:9001" # 对外访问的服务器地址os.makedirs(OUTPUT_DIR, exist_ok=True)# ---------------- 读取 workflow ----------------
with open(WORKFLOW_FILE, "r", encoding="utf-8") as f:base_workflow = json.load(f)# ---------------- 请求体定义 ----------------
class GenerateRequest(BaseModel):positive: strnegative: str = ""height: int = 512 # -1 表示随机width: int = 512# ---------------- FastAPI 实例 ----------------
app = FastAPI(title="ComfyUI API Server")# ---------------- 生成接口 ----------------
@app.post("/generate")
def generate(req: GenerateRequest, x_api_key: str = Header(None)):if x_api_key != API_KEY:raise HTTPException(status_code=401, detail="Invalid API Key")workflow = copy.deepcopy(base_workflow)# 替换 workflow 中的 prompt 和 seedworkflow["6"]["inputs"]["text"] = req.positiveworkflow["7"]["inputs"]["text"] = req.negative workflow["58"]["inputs"]["width"] = req.widthworkflow["58"]["inputs"]["height"] = req.height# 提交任务到 ComfyUI APIresp = requests.post(f"{COMFYUI_API_URL}/prompt", json={"prompt": workflow})resp.raise_for_status()prompt_id = resp.json()["prompt_id"]images_base64 = []while True:history = requests.get(f"{COMFYUI_API_URL}/history/{prompt_id}").json()if prompt_id in history:outputs = history[prompt_id].get("outputs", {})for node_id, output_data in outputs.items():if "images" in output_data:for img in output_data["images"]:filename = img["filename"]subfolder = img.get("subfolder", "")filetype = img.get("type", "png")img_url = (f"{COMFYUI_API_URL}/view"f"?filename={urllib.parse.quote(filename)}"f"&subfolder={urllib.parse.quote(subfolder)}"f"&type={urllib.parse.quote(filetype)}")img_data = requests.get(img_url).content# 保存到指定路径下save_path = os.path.join(STATIC_DIR, filename)with open(save_path, "wb") as f:f.write(img_data)# 返回的URLpublic_url = f"{SERVER_BASE_URL}/static/{filename}"img_b64 = base64.b64encode(img_data).decode("utf-8")images_base64.append(img_b64)if images_base64:breaktime.sleep(POLL_INTERVAL)return {"prompt_id": prompt_id, "image_url": public_url}
其中STATIC_DIR = "/var/www/static"
即指定的保存生成图像的路径,也是将开放访问的目录,SERVER_BASE_URL = "http://server_ip:9001"
则是配置的url,包括服务器ip和端口。调用API将返回{'prompt_id': 'xxx', 'image_url': 'http://server_ip:9001/static/image.png'}
。
配置Nginx
下面配置Nginx实现静态资源映射。新建一个配置文件:
sudo nano /etc/nginx/conf.d/static_files.conf
在该文件中写入:
server {listen 9001; # 端口server_name _; # _为默认匹配所有 Hostlocation /static/ { # alias /var/www/static/; # 这里是指定开放访问的目录,建议选择这个,不会存在权限问题autoindex off; # 是否开启目录浏览# 若开启,用户可访问static下所有文件,否则,只能访问当前文件}
}
重启Nginx:sudo systemctl reload nginx
,检查Nginx是否正常工作:sudo nginx -t
。
到此为止,用户可以通过http://server_ip:9001/static/image.png
访问你存放在/var/www/static/
目录下的文件了。这部分和图像生成API无关,只是将返回方式改成了url。
注意
:Nginx使用的端口注意不能和FastAPI冲突,否则Nginx启动不了。当你在浏览器中打http://server_ip:9001/static/image.png
,如果显示403 Forbidden,则要么是指定的访问目录存在权限问题,建议用上面的目录;或者是配置文件里路径没写完整,最后的/
不能忘。