ComfyUI部署Wan2.2,开放API,文生视频与图生视频
通义万象2.2开源了,5B模型具有文生视频和图生视频的能力。这里介绍通过ComfyUI部署wan2.2并开放API,通过url返回生成的视频。环境配置,api的worlflow配置文件获取,ComfyUI启动,配置url路径参考这里。
文生视频
这里直接给出API启动脚本:
from fastapi import FastAPI, HTTPException, Header
from fastapi import FastAPI, HTTPException, Header
from pydantic import BaseModel
import requests
import copy
import json
import os
import urllib.parse
import time
import base64API_KEY = "12345"# ---------------- 配置 ----------------
COMFYUI_API_URL = "http://127.0.0.1:8188" # ComfyUI API 地址
WORKFLOW_FILE = "text_to_video_wan22_5B_API.json" # 固定 workflow 文件
OUTPUT_DIR = "output_videos"
POLL_INTERVAL = 2 # 秒STATIC_DIR = "/var/www/static" # 存储视频的目录
SERVER_BASE_URL = "http://server_ip:9001" # 对外访问的服务器地址os.makedirs(OUTPUT_DIR, exist_ok=True)
os.makedirs(STATIC_DIR, exist_ok=True)# ---------------- 读取 workflow ----------------
with open(WORKFLOW_FILE, "r", encoding="utf-8") as f:base_workflow = json.load(f)# ---------------- 请求体定义 ----------------
class GenerateVideoRequest(BaseModel):positive: strnegative: str = ""height: int = 704width: int = 1280length: int = 121 # 视频帧数fps: int = 24# ---------------- FastAPI 实例 ----------------
app = FastAPI(title="ComfyUI Video API Server")# ---------------- 生成接口 ----------------
@app.post("/generate_video")
def generate_video(req: GenerateVideoRequest, 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 中的输入参数workflow["6"]["inputs"]["text"] = req.positiveworkflow["7"]["inputs"]["text"] = req.negativeworkflow["55"]["inputs"]["width"] = req.widthworkflow["55"]["inputs"]["height"] = req.heightworkflow["55"]["inputs"]["length"] = req.lengthworkflow["47"]["inputs"]["fps"] = req.fps # 保存 WEBMworkflow["28"]["inputs"]["fps"] = float(req.fps) # 保存 WEBP 动图# 提交任务resp = requests.post(f"{COMFYUI_API_URL}/prompt", json={"prompt": workflow})resp.raise_for_status()prompt_id = resp.json()["prompt_id"]public_urls = []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 file in output_data["images"]:filename = file["filename"]subfolder = file.get("subfolder", "")filetype = file.get("type", "output") # webm / webp / pngfile_url = (f"{COMFYUI_API_URL}/view"f"?filename={urllib.parse.quote(filename)}"f"&subfolder={urllib.parse.quote(subfolder)}"f"&type={urllib.parse.quote(filetype)}")file_data = requests.get(file_url).contentsave_path = os.path.join(STATIC_DIR, filename)with open(save_path, "wb") as f:f.write(file_data)public_url = f"{SERVER_BASE_URL}/static/{filename}"public_urls.append(public_url)if public_urls:breaktime.sleep(POLL_INTERVAL)return {"prompt_id": prompt_id, "video_urls": public_urls}
将上面的脚本保存为serve_fastapi.py,其中COMFYUI_API_URL
是启动的ComfyUI服务,WORKFLOW_FILE
是保存的workflow配置文件。使用下面的命令启动API:
uvicorn serve_fastapi:app --host 0.0.0.0 --port 9002
这里给出python访问api的脚本:
import requests
import base64
from PIL import Image
from io import BytesIOheaders = {"x-api-key": "12345"}
resp = requests.post("http://server_ip:9002/generate_video",headers=headers,json={"positive": "Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage.","negative": "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走","height": 512,"width": 768,"length": 73, # 帧数,帧率固定为24 fps}
)
print(resp.json())
api会返回可访问的生成视频的url。
图生视频
直接给出api启动脚本,与上面不同的就是图生视频需要多传如一个图像,这里以url的形式传入:
from fastapi import FastAPI, HTTPException, Header
from pydantic import BaseModel
import requests
import copy
import json
import os
import urllib.parse
import time
import base64
import tempfileAPI_KEY = "12345"# ---------------- 配置 ----------------
COMFYUI_API_URL = "http://127.0.0.1:8188" # ComfyUI API 地址
WORKFLOW_FILE = "image_to_video_wan22_5B_api.json" # 你准备好的图生视频 workflow
OUTPUT_DIR = "output_videos"
POLL_INTERVAL = 2 # 秒STATIC_DIR = "/var/www/static" # 存储视频的目录
SERVER_BASE_URL = "http://server_ip:9001" # 对外访问的服务器地址os.makedirs(OUTPUT_DIR, exist_ok=True)
os.makedirs(STATIC_DIR, exist_ok=True)# ---------------- 读取 workflow ----------------
with open(WORKFLOW_FILE, "r", encoding="utf-8") as f:base_workflow = json.load(f)# ---------------- 请求体定义 ----------------
class GenerateVideoRequest(BaseModel):image_url: str # 输入图像 URLpositive: str = "" # 可选的正向 promptnegative: str = "" # 可选的负向 promptheight: int = 704width: int = 1280length: int = 121 # 视频帧数fps: int = 24# ---------------- FastAPI 实例 ----------------
app = FastAPI(title="ComfyUI Image-to-Video API Server")# ---------------- 生成接口 ----------------
@app.post("/generate_video_i2v")
def generate_video(req: GenerateVideoRequest, 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)# ----------- 下载输入图像到临时目录,并传给 ComfyUI -----------resp = requests.get(req.image_url)if resp.status_code != 200:raise HTTPException(status_code=400, detail="Failed to download input image")tmp_path = os.path.join(STATIC_DIR, "input_image.png")with open(tmp_path, "wb") as f:f.write(resp.content)# 替换 workflow 的图像节点 (假设节点 id 是 "57")workflow["57"]["inputs"]["image"] = tmp_path# 修改其他输入if "6" in workflow: # 正向 prompt 节点workflow["6"]["inputs"]["text"] = req.positiveif "7" in workflow: # 负向 prompt 节点workflow["7"]["inputs"]["text"] = req.negativeif "55" in workflow:workflow["55"]["inputs"]["width"] = req.widthworkflow["55"]["inputs"]["height"] = req.heightworkflow["55"]["inputs"]["length"] = req.lengthif "47" in workflow:workflow["47"]["inputs"]["fps"] = req.fps # 保存 WEBMif "28" in workflow:workflow["28"]["inputs"]["fps"] = float(req.fps) # 保存 WEBP 动图# 提交任务resp = requests.post(f"{COMFYUI_API_URL}/prompt", json={"prompt": workflow})resp.raise_for_status()prompt_id = resp.json()["prompt_id"]public_urls = []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 file in output_data["images"]:filename = file["filename"]subfolder = file.get("subfolder", "")filetype = file.get("type", "output")file_url = (f"{COMFYUI_API_URL}/view"f"?filename={urllib.parse.quote(filename)}"f"&subfolder={urllib.parse.quote(subfolder)}"f"&type={urllib.parse.quote(filetype)}")file_data = requests.get(file_url).contentsave_path = os.path.join(STATIC_DIR, filename)with open(save_path, "wb") as f:f.write(file_data)public_url = f"{SERVER_BASE_URL}/static/{filename}"public_urls.append(public_url)if public_urls:breaktime.sleep(POLL_INTERVAL)return {"prompt_id": prompt_id, "video_urls": public_urls}
将上面的脚本保存为serve_fastapi_i2v.py,其中COMFYUI_API_URL
是启动的ComfyUI服务,WORKFLOW_FILE
是保存的workflow配置文件。使用下面的命令启动API:
uvicorn serve_fastapi:app --host 0.0.0.0 --port 9003
这里给出python调用api的示例:
import requestsheaders = {"x-api-key": "12345"}
resp = requests.post("http://127.0.0.1:9003/generate_video_i2v",headers=headers,json={"image_url": "https://comfyanonymous.github.io/ComfyUI_examples/chroma/fennec_girl_hug.png","positive": "a cute anime girl with fennec ears and a fluffy tail walking in a beautiful field","negative": "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走","height": 704,"width": 1280,"length": 141, # 帧数,帧率固定为24 fps}
)
print(resp.json())
图生视频的图像用url进行传入,如果是图像就在服务器上,可以直接使用路径,如果图像在本地主机,可以传到某个可访问的云服务上,开放url。api会返回生成视频的url。