使用 ComfyUI 封装文生图 python 接口
参考文章: 使用python调用comfyui-api,实现出图自由
环境要求
- 操作系统
Windows - python版本
3.9 - 运行中的 ComfyUI 服务
ComfyUI 部署 Kolors 教程链接: Linux 使用 ComfyUI 本地部署快手可图 Kolors 大模型
导出 API json 文件
- 编辑工作流完成后,导出 API 文件,如图:
使用 flask 封装接口
- 使用 pycharm 新建 python 项目 ComfyUIService
- 在 pycharm 终端安装依赖
pip install flask, websocket-client
- 创建 app.py 文件
import json
import os
import websocket # NOTE: websocket-client (https://github.com/websocket-client/websocket-client)
import uuid
import urllib.request
import urllib.parse
import random
from flask import Flask, request, jsonify, send_file
app = Flask(__name__)
# 设置工作目录和项目相关的路径
client_id = str(uuid.uuid4()) # 生成一个唯一的客户端ID
WORKING_DIR = 'output'
SageMaker_ComfyUI = WORKING_DIR
COMFYUI_ENDPOINT = '10.213.13.246:8188'
server_address = COMFYUI_ENDPOINT
workflowfile = 'C:/Users/PC0214/Downloads/kolors_example_api_v3.json'
kolors_text_encode_key = '12'
kolors_sampler_key = '14'
# 定义一个函数来显示GIF图片
def show_gif(fname):
import base64
from IPython import display
with open(fname, 'rb') as fd:
b64 = base64.b64encode(fd.read()).decode('ascii')
return display.HTML(f'<img src="data:image/gif;base64,{b64}" />')
# 定义一个函数向服务器队列发送提示信息
def queue_prompt(prompt):
p = {"prompt": prompt, "client_id": client_id}
data = json.dumps(p).encode('utf-8')
req = urllib.request.Request("http://{}/prompt".format(server_address), data=data)
return json.loads(urllib.request.urlopen(req).read())
# 定义一个函数来获取图片
def get_image(filename, subfolder, folder_type):
data = {"filename": filename, "subfolder": subfolder, "type": folder_type}
url_values = urllib.parse.urlencode(data)
with urllib.request.urlopen("http://{}/view?{}".format(server_address, url_values)) as response:
return response.read()
# 定义一个函数来获取历史记录
def get_history(prompt_id):
with urllib.request.urlopen("http://{}/history/{}".format(server_address, prompt_id)) as response:
return json.loads(response.read())
# 定义一个函数来获取图片,这涉及到监听WebSocket消息
def get_images(ws, prompt):
prompt_id = queue_prompt(prompt)['prompt_id']
print('prompt')
print(prompt)
print('prompt_id:{}'.format(prompt_id))
output_images = {}
while True:
out = ws.recv()
if isinstance(out, str):
message = json.loads(out)
if message['type'] == 'executing':
data = message['data']
if data['node'] is None and data['prompt_id'] == prompt_id:
print('执行完成')
break # 执行完成
else:
continue # 预览为二进制数据
history = get_history(prompt_id)[prompt_id]
print(history)
for o in history['outputs']:
for node_id in history['outputs']:
node_output = history['outputs'][node_id]
# 图片分支
if 'images' in node_output:
images_output = []
for image in node_output['images']:
image_data = get_image(image['filename'], image['subfolder'], image['type'])
images_output.append(image_data)
output_images[node_id] = images_output
# 视频分支
if 'videos' in node_output:
videos_output = []
for video in node_output['videos']:
video_data = get_image(video['filename'], video['subfolder'], video['type'])
videos_output.append(video_data)
output_images[node_id] = videos_output
print('获取图片完成')
print(output_images)
return output_images
# 解析工作流并获取图片
def parse_worflow(ws, prompt, seed, workflowfile, width, height):
workflowfile = workflowfile
print('workflowfile:'+workflowfile)
with open(workflowfile, 'r', encoding="utf-8") as workflow_api_txt2gif_file:
prompt_data = json.load(workflow_api_txt2gif_file)
# 设置文本提示
print(f'生成图片关键词是:{prompt}')
prompt_data[kolors_text_encode_key]["inputs"]["prompt"] = prompt
prompt_data[kolors_sampler_key]["inputs"]["width"] = width
prompt_data[kolors_sampler_key]["inputs"]["height"] = height
prompt_data[kolors_sampler_key]["inputs"]["seed"] = seed
return get_images(ws, prompt_data)
# 生成图像并显示
def generate_clip(prompt, seed, workflowfile, idx, width, height):
print('seed:'+str(seed))
ws = websocket.WebSocket()
ws.connect("ws://{}/ws?clientId={}".format(server_address, client_id))
images = parse_worflow(ws, prompt, seed, workflowfile, width, height)
output_images = []
for node_id in images:
for image_data in images[node_id]:
from datetime import datetime
# 获取当前时间,并格式化为 YYYYMMDDHHMMSS 的格式
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
# 使用格式化的时间戳在文件名中
GIF_LOCATION = "{}/{}_{}_{}.png".format(SageMaker_ComfyUI, idx, seed, timestamp)
print('GIF_LOCATION:'+GIF_LOCATION)
with open(GIF_LOCATION, "wb") as binary_file:
# 写入二进制文件
binary_file.write(image_data)
# show_gif(GIF_LOCATION)
output_images.append(GIF_LOCATION)
print("{} DONE!!!".format(GIF_LOCATION))
return output_images
@app.route('/generateImgByPrompt', methods=["POST"])
def generate_img_by_prompt():
params = request.get_json()
if params is None:
return "参数不能为空", 400
prompt = params.get('prompt')
width = params.get('width')
height = params.get('height')
if prompt is None or width is None or height is None:
return "prompt|width|height 都不能为空", 400
# 1000102404233412
seed = random.randint(1, 1000000000000)
idx = 1
output_images = generate_clip(prompt, seed, workflowfile, idx, width, height)
output_image = output_images[0]
try:
response = send_file(output_image)
# os.remove(output_image)
return response
except FileNotFoundError:
return "文件不存在", 404
if __name__ == '__main__':
app.run(host='0.0.0.0',
threaded=True,
debug=False,
port=6663)
- 修改 app.py 配置
COMFYUI_ENDPOINT = '10.213.13.246:8188' # 你的 ComfyUI 服务的地址
workflowfile = 'C:/Users/PC0214/Downloads/kolors_example_api_v3.json' # 前面步骤导出的 API json 文件路径
kolors_text_encode_key = '12' # text encode 下标索引(需要根据你导出的 API json 文件替换)
kolors_sampler_key = '14' # sampler 下标索引(需要根据你导出的 API json 文件替换)
- 启动 app.py
调用接口
- 接口url
127.0.0.1:6663/generateImgByPrompt
- 接口参数(POST请求,json格式)
{
"prompt": "使用灰黑色调帮我生成一张日系可爱女生真人海报,使用广角镜头把背景拍大点,女生占海报的三分之一大小就好,女生齐肩短发,倚着窗户含笑看着我",
"width": 512,
"height": 512
}
- 示例