ComfyUI的API使用教程

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_idstring任务ID,由客户端生成,用于标记任务是谁发起的
promptjson任务参数

返回参数:

名称类型说明
prompt_idstring任务ID
numberint当前任务序号,可用于后续获取需要等待任务数的计算
node_errorsjson错误信息

返回示例:

{
    "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_output

    return 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博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值