ComfyUI的api接口文档:comfyui-api.md · YY/wailikeji-chatgpt - Gitee.com
1、调用API的使用流程
1)用户设计好工作流
2)将工作流保存为API形式的json内容
3)调用ComfyUI的API,输入json内容作为prompts参数传入,得到最终结果
2、绘图接口:POST/prompt
注意:该接口只做绘图任务的下发,然后返回任务ID信息。并不会直接返回最终的结果图!
与webui的api不同的是,comfyui的api并没有单独区分文生图、图生图的接口,而是所有的绘图任务的下发全部都使用POST /prompt。那具体是文生图、图生图、又或者是换脸、倒推关键词等,取决于你的参数!
需要上传的参数只有两个请求参数:
名称 | 类型 | 必选 | 说明 |
client_id | string | 是 | 任务ID,由客户端生成,用于标记任务是谁发起的 |
prompt | json | 是 | 任务参数 |
返回参数:
名称 | 类型 | 说明 |
prompt_id | string | 任务ID |
number | int | 当前任务序号,可用于后续获取需要等待任务数的计算 |
node_errors | json | 错误信息 |
返回示例:
{"prompt_id": "bd2cfa2c-de87-4258-89cc-d8791bc13a61","number": 501,"node_errors": {}
}
使用说明:
clientId:任务ID,由客户端生成,用于标记任务是谁发起的,相当于告诉comfyui,该绘图任务是由用户A发起的,后续comfyui就会通过websocket将属于用户A的绘图信息推送给你。
3、websocket:/ws?clientId=XXXXXXXX
client_id后面的参数即为上面/prompt接口中上传给comfyui的client_id,假如没有上传client_id,那comfyui就不知道连上该websocket的用户是谁,也就无法进行信息推送!comfyui拿到client_id后,即可知道当前是哪个用户,后续就会通过websocket将属于该用户的绘图信息精准推送给他。
注意:websocket只需做监听处理,无需通过websocket向comfyui发送任何消息。
websocket数据解析:
主要有两种数据格式:
1、文本数据,文本数据主要通知以下几个绘图信息:
通知任务变更、当前执行的步骤、进度
2、二进制数据,即图片预览信息
(1)任务变更通知
{"type":"status","data":{"status":{"exec_info":{"queue_remaining":7}}}
}
当你收到type为status信息时,这是comfyui在告诉你,当前任务数发生变更,queue_remaining是指当前还有多少个任务需要处理。
注意,此处的queue_remaining并不是告诉你在你的任务之前还有多少个任务需要处理!而是总的!
所以,当还没轮到你的绘图任务时,显示还需等待多少个任务,你就需要借助comfyui的另一个接口:GET /queue:获取详细任务队列信息,正在运行的以及挂起的。该接口会返回挂起的任务信息,其中有prompt_id信息和number信息,你可以根据这number信息获取到当前任务排在第几位。
(2)当前任务开始执行
{"type":"execution_start","data":{"prompt_id":"3935f7c3-ec38-4d94-843f-86fe86c6d384"}
}
当你收到type为execution_start信息时,这是comfyui在告诉你,你的任务id,prompt_id为“3935f7c3-ec38-4d94-843f-86fe86c6d384”的任务当前正在被执行
(3)当前任务执行的步骤信息
{"type":"executing","data":{"node":"5","prompt_id":"3935f7c3-ec38-4d94-843f-86fe86c6d384"}
}
当你收到type为executing信息时,这是comfyui在告诉你,你的任务id,prompt_id为“3935f7c3-ec38-4d94-843f-86fe86c6d384”的任务当前正在执行节点5的步骤。
(4)当前进度信息
{"type":"progress","data":{"value":1,"max":10}
}
当你收到type为progress信息时,这是comfyui在告诉你,当前步骤执行的进度,value是当前的步数,max是总的步数。
(5)绘图结束
{"type":"executing","data":{"node":null,"prompt_id":"37099310-a790-44f4-8d13-4f4d5f69c891"}
}
绘图结束时,type类型仍然是executing,和前面的(3)是一样的,区别主要在于node为null,也就是当type=executing,且node=null的时候,说明流程已经跑完,此时需要通过接口GET /history/{prompt_id}获取输出的图片信息。底下是通过history获取到的图片信息。
{"37099310-a790-44f4-8d13-4f4d5f69c891": {略。。。。。。。。。。"outputs": {"18": {"images": [{"filename": "ComfyUI_temp_slqio_00001_.png","subfolder": "","type": "temp"},{"filename": "ComfyUI_temp_slqio_00002_.png","subfolder": "","type": "temp"},{"filename": "ComfyUI_temp_slqio_00003_.png","subfolder": "","type": "temp"},{"filename": "ComfyUI_temp_slqio_00004_.png","subfolder": "","type": "temp"}]},"22": {"images": [{"filename": "ComfyUI_temp_rfvdr_00001_.png","subfolder": "","type": "temp"},{"filename": "ComfyUI_temp_rfvdr_00002_.png","subfolder": "","type": "temp"},{"filename": "ComfyUI_temp_rfvdr_00003_.png","subfolder": "","type": "temp"},{"filename": "ComfyUI_temp_rfvdr_00004_.png","subfolder": "","type": "temp"}]},"24": {"images": [{"filename": "ComfyUI_00702_.png","subfolder": "","type": "output"},{"filename": "ComfyUI_00703_.png","subfolder": "","type": "output"},{"filename": "ComfyUI_00704_.png","subfolder": "","type": "output"},{"filename": "ComfyUI_00705_.png","subfolder": "","type": "output"}]}}}
}
outputs中的内容就是最终生成的图片信息。
4、基于python的代码实战
按照websocket库:pip install websocket-client
import websocket
import uuid
import json
import urllib.request
import urllib.parse
from PIL import Image
import io# 设置服务器地址和客户端
server_address = "127.0.0.1:18188"
client_id = str(uuid.uuid4())# 定义向服务器发送提示的函数
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']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:break # 执行完成else:continue # 预览是二进制数据history = get_history(prompt_id)[prompt_id]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_outputreturn output_images# 示例JSON字符串,表示要使用的提示
prompt_text = """
{"1": {"inputs": {"ckpt_name": "realcartoonXL_v5.safetensors"},"class_type": "CheckpointLoaderSimple","_meta": {"title": "加载检查点"}},"2": {"inputs": {"lora_name": "t_realcartoon.safetensors","strength_model": 0.7000000000000001,"strength_clip": 0.7000000000000001,"model": ["1",0],"clip": ["1",1]},"class_type": "LoraLoader","_meta": {"title": "加载LoRA"}},"3": {"inputs": {"seed": 152656324223018,"steps": 20,"cfg": 8,"sampler_name": "euler","scheduler": "normal","denoise": 1,"model": ["2",0],"positive": ["8",0],"negative": ["9",0],"latent_image": ["6",0]},"class_type": "KSampler","_meta": {"title": "K采样器"}},"4": {"inputs": {"samples": ["3",0],"vae": ["1",2]},"class_type": "VAEDecode","_meta": {"title": "VAE解码"}},"5": {"inputs": {"filename_prefix": "ComfyUI","images": ["4",0]},"class_type": "SaveImage","_meta": {"title": "保存图像"}},"6": {"inputs": {"width": 512,"height": 512,"batch_size": 1},"class_type": "EmptyLatentImage","_meta": {"title": "空潜空间图像"}},"7": {"inputs": {"stop_at_clip_layer": -2,"clip": ["2",1]},"class_type": "CLIPSetLastLayer","_meta": {"title": "设置CLIP最后一层"}},"8": {"inputs": {"text": "t<lora:t_realcartoon:1> Running beside the beach","clip": ["7",0]},"class_type": "CLIPTextEncode","_meta": {"title": "CLIP文本编码(提示)"}},"9": {"inputs": {"text": "","clip": ["7",0]},"class_type": "CLIPTextEncode","_meta": {"title": "CLIP文本编码(提示)"}}
}"""# 将示例JSON字符串解析为Python字典,并根据需要修改其中的文本提示和种子值
prompt = json.loads(prompt_text)
prompt["8"]["inputs"]["text"] = "t<lora:t_realcartoon:1> Running beside the beach"
prompt["3"]["inputs"]["seed"] = 1# 创建一个WebSocket连接到服务器
ws = websocket.WebSocket()
ws.connect("ws://{}/ws?clientId={}".format(server_address, client_id))# 调用get_images()函数来获取图像
images = get_images(ws, prompt)# 显示图片
for node_id in images:for image_data in images[node_id]:image = Image.open(io.BytesIO(image_data))image.show()input("")
本文参考:
stable diffusion comfyui的api使用教程_comfyui api-CSDN博客
ComfiUI API调用随记_comfyui api-CSDN博客