AIStudio SSH 公钥管理,一处配置,处处可用AIStudio SSH 公钥管理,一处配置,处处可用 ,只为更佳开发体验如何配置
Skip to content

接入托管 ComfyUI 工作流 API 服务

ComfyUI 是一套生图领域常用的工作流(workflow)编排工具,可以方便灵活的设计图片处理工作流。无问芯穹 GenStudio 提供了 ComfyUI 工作流托管服务,用户托管工作流后,可以在业务中通过 API 调用该工作流。平台负责维护工作流的运行环境,优化算力资源、推理效率。

NOTE

前置条件

请确保您已经在 GenStudio ComfyUI 托管服务上传并发布了您的工作流。如尚未将您的托管工作流发布为 API 服务,请依次完成以下操作。

  1. 上传工作流
  2. 关联运行环境
  3. 发布工作流

此外,建议通过工作流详情页的「试运行」功能在线上完成验证,预览出图效果,保证工作流可正常运行。「试运行」抽屉界面还提供对应的 API 请求体示例(CURL)。

试运行抽屉面板

学习目标

本文介绍了如何接入 GenStudio ComfyUI 服务通信的 API 端点,以及 API 的主调用流程。

您将了解:

  • 完整体验文生图的 API 调用流程(CURL)。
  • 完整体验图生图的 API 调用流程(CURL)。
  • 如何在获取托管工作流 API 的输入参数类型和范围。
  • 如何在业务流程中修改工作流参数。
  • 如何在获取结果图片时指定质量与格式。

ComfyUI API 服务入门

ComfyUI 托管工作流上线后即发布为 API 服务,支持通过 HTTP API 和 WebSocket 方式调用。

API 端点

GenStudio ComfyUI 服务提供了封装原始 ComfyUI HTTP 端点的新端点。以下是端点映射与 HTTP API 参考文档链接:

原始 ComfyUI 端点描述API 端点
POST /prompt提交任务(文生图示例POST /api/maas/comfy_task_api/prompt
GET /history/获取任务排队信息和生图结果POST /api/maas/comfy_task_api/get_task_info
POST /upload/image上传图像POST /api/maas/comfy_task_api/upload/image
/ws实时获取任务进度和生图结果/maas/api/comfy_task_ws_api/get_task_progress

GenStudio 的 API Base URL 为 https://cloud.infini-ai.com

为了保障服务的稳定性及合理使用,我们对 GenStudio API 服务进行了频率限制。参见 API 频率限制

API 鉴权设置

使用 API 服务,首先需要完成身份验证。请按照以下步骤获取您的 API 密钥:

  1. 复制已有的 API 密钥,或自助创建 API Key。
  2. 点击复制按钮获取密钥。您可能需要完成二次验证。

alt text

您将获取到一个格式为 sk- 前缀的 API 密钥,例如 sk-axbx5xcx9xAxbZyx。在后续的 CURL 请求中,请注意在 header 中传入自己的 API 密钥。

--header 'Authorization: Bearer sk-xxxxxxxxxxxxxxxx'

API 入参范围

由于 API 服务中的「生图任务接口」(/api/maas/comfy_task_api/prompt)定义是 基于用户上传的 ComfyUI 工作流文件动态生成的,因此,该 API 的接口定义(Schema),包括接受哪些参数、参数的数据类型、有效值范围等等,都 直接取决于用户工作流文件内部的节点配置和连接方式

由于无法为生图任务接口提供统一的 OpenAPI 规范,为了帮助用户了解自己工作流的 API 输入要求,平台会基于您的工作流验证结果,自动生成详细的参数 Schema,即「入参范围」,其中展示工作流中各个节点的有效参数范围,例如 ckpt_name 的参数支持的 Checkpoint 列表,seed 或 的取值范围等。

您可在托管工作流的详情页获取入参范围。在通过代码集成 API 服务时,可以通过编程方式处理该数据,提取节点入参的类型、范围等。

alt text

平台会在每个可传入的参数的 spec 键下返回可接受的入参范围和默认值。

"spec": {
    "default": 20,
    "min": 1,
    "max": 10000
  }

DANGER

「入参范围」仅提供数据参考,并非 ComfyUI API 请求 Body 体。

文生图任务

如果使用 GenStudio 托管图生图工作流,API 调用流程如下:

  1. 提交生图请求,将文生图任务加入队列。
  2. 轮询任务状态,直到任务完成或失败。状态 3 表示全部图片生成结束。
  3. 下载当前 Workflow 生成的所有图像。

NOTE

首次体验时,可直接下载示例工作流后进行上传,无需上传自己的工作流。

在下面的流程中,我们将使用示例工作流,通过 API 提交一个文生图任务,并获取生成的图像。

文生图示例 Workflow

示例使用以下设置:

  • 工作流 API JSON: ComfyUI 导出的文生图工作流
  • 模型:majicMIX realistic 麦橘写实_v7.safetensors
  • 采样器名称:ddim
  • 调度器:karras
  • 步骤:20
  • cfg:7
  • API 更改后的正面提示:Spiderman in a red suit standing in middle of a crowded place, skyscrapers in the background, cinematic, neon colors, realistic look
  • API 更改后的负面提示:ugly, deformed
查看示例工作流 JSON 内容
JSON
{
    "3": {
      "inputs": {
        "seed": 1,
        "steps": 20,
        "cfg": 7,
        "sampler_name": "ddim",
        "scheduler": "karras",
        "denoise": 1,
        "model": [
          "4",
          0
        ],
        "positive": [
          "6",
          0
        ],
        "negative": [
          "7",
          0
        ],
        "latent_image": [
          "5",
          0
        ]
      },
      "class_type": "KSampler",
      "_meta": {
        "title": "KSampler"
      }
    },
    "4": {
      "inputs": {
        "ckpt_name": "majicMIX realistic 麦橘写实_v7.safetensors"
      },
      "class_type": "CheckpointLoaderSimple",
      "_meta": {
        "title": "Load Checkpoint"
      }
    },
    "5": {
      "inputs": {
        "width": 512,
        "height": 512,
        "batch_size": 1
      },
      "class_type": "EmptyLatentImage",
      "_meta": {
        "title": "Empty Latent Image"
      }
    },
    "6": {
      "inputs": {
        "text": "a girl",
        "clip": [
          "4",
          1
        ]
      },
      "class_type": "CLIPTextEncode",
      "_meta": {
        "title": "CLIP Text Encode (Prompt)"
      }
    },
    "7": {
      "inputs": {
        "text": "",
        "clip": [
          "4",
          1
        ]
      },
      "class_type": "CLIPTextEncode",
      "_meta": {
        "title": "CLIP Text Encode (Prompt)"
      }
    },
    "8": {
      "inputs": {
        "samples": [
          "3",
          0
        ],
        "vae": [
          "4",
          2
        ]
      },
      "class_type": "VAEDecode",
      "_meta": {
        "title": "VAE Decode"
      }
    },
    "9": {
      "inputs": {
        "filename_prefix": "ComfyUI",
        "images": [
          "8",
          0
        ]
      },
      "class_type": "SaveImage",
      "_meta": {
        "title": "Save Image"
      }
    }
  }

提交文生图任务

使用 API 提交文生图任务,需要使用 POST /api/maas/comfy_task_api/prompt 接口。JSON 请求体中的 workflow_id 为工作流 ID。prompt 对象中包含在当前请求中修改的节点参数。

DANGER

JSON 请求体中 prompt 参数的值需要根据工作流的节点 ID 和可修改参数自行构建。

  • 请勿在 prompt 参数中直接传入 ComfyUI 导出的 Workflow API JSON 文件。
  • 请勿在 prompt 参数中直接传入 GenStudio Workflow 「查看参数」的内容。

CURL 请求可直接从试运行工作流界面中拷贝,示例如下:

shell
curl --request POST \
  --url https://cloud.infini-ai.com/api/maas/comfy_task_api/prompt \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer sk-xxxxxxxxxxxxxxxx' \
  --header 'Content-Type: application/json' \
  --data '{
    "workflow_id": "wf-c73diz7kadp6ffgn",
    "prompt": {
      "3": {
        "inputs": {
          "seed": 423710630168223,
          "steps": 20,
          "cfg": 7,
          "sampler_name": "ddim",
          "scheduler": "karras",
          "denoise": 1
        }
      },
      "4": {
        "inputs": {
          "ckpt_name": "majicMIX realistic 麦橘写实_v7.safetensors"
        }
      },
      "5": {
        "inputs": {
          "width": 512,
          "height": 512,
          "batch_size": 1
        }
      },
      "6": {
        "inputs": {
          "text": "Rabbit in a red suit standing in middle of a crowded place, skyscrapers in the background, cinematic, neon colors, realistic look"
        }
      },
      "7": {
        "inputs": {
          "text": "ugly, deformed"
        }
      }
    }
  }'

200 OK 响应示例的结构如下:

JSON
{
    "code": 0,
    "msg": "Success",
    "data": {
        "prompt_id": "cft-c73egpxvlvg76yjd",
        "prompt_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZW5hbnRfaWQiOiJ0ZS1iOTA1NzU0NDI3MzUyMjYxIiwidGFza19pZCI6ImNmdC1jNzZ1anllemdlcDVwY2FsIiwiaXNzIjoiaW5maW5pIiwiZXhwIjoxNzI4Njk5OTYzfQ.yrWt9_tyKYH_0lZHuFG8l76ddFGgDMV68ZqdZtRAUHA"
    }
}

prompt_id 是提交任务后返回的唯一 ID,用于获取任务状态和结果。

prompt_token 用于在实时获取任务进度的 WebSocket API 中进行认证,Token 生成后 24 小时有效。

获取文生图任务状态和结果

使用 API 获取任务排队信息和生图结果,需要使用 POST /api/maas/comfy_task_api/get_task_info 接口。

CURL 请求正文示例如下:

shell
curl --request POST \
  --url https://cloud.infini-ai.com/api/maas/comfy_task_api/get_task_info \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer 123' \
  --header 'Content-Type: application/json' \
  --data '{
  "comfy_task_ids": [
    "cft-c73egpxvlvg76yjd"
  ],
  "url_expire_period": 1000
}'

comfy_task_ids 可接受一个任务 ID 数组。由于生图任务是异步生成,需要轮询获取任务状态和结果。

在上面的示例中,我们只传入一个任务 ID(上一步返回的 prompt_id)。设置 url_expire_period 为 1000,表示结果图片链接有效期为 1000 秒。

如果 200 OK 响应结果中某个任务 ID 的 "status": 3,表示生图已成功并可通过返回的 OSS URL 获取生图结果。响应示例如下:

JSON
{
    "code": 0,
    "msg": "Success",
    "data": {
        "comfy_task_info": [
            {
                "comfy_task_id": "cft-c73egpxvlvg76yjd",
                "status": 3,
                "queue_size": 0,
                "current_position": 0,
                "errMsg": "",
                "files": {
                    "9": [
                        "https://infini-imagegen.oss-cn-beijing.aliyuncs.com/te-b905754427352261%2Fac-c66h4ddlwutmbinv%2Fcft-c73egpxvlvg76yjd%2Fbb5c49b3-e1a8-4a46-b2ab-51aa47d9bbfc.png?Expires=1726642626\u0026OSSAccessKeyId=LTAI5tBgzFapTV38XHKZjHPa\u0026Signature=c2K4wQKbirfirwL0bgX%2FNDSF4iA%3D"
                    ]
                },
                "final_files": [
                        "https://infini-imagegen.oss-cn-beijing.aliyuncs.com/te-b905754427352261%2Fac-c66h4ddlwutmbinv%2Fcft-c76ujyezgep5pcal%2F83f2227c-9c1a-4e6a-813b-1359e2d1867e.png?Expires=1728615208&OSSAccessKeyId=LTAI5tBgzFapTV38XHKZjHPa&Signature=V1XbMwpAYXBt8eD1FN690kKcnVk%3D"
                      ],
               "progress_num": 100
            }
        ]
    }
}

status 字段为任务状态,取值范围:1-排队中,2-生成中,3-生成成功,4-生成失败,5-权限不足。

files 字段为任务结果,其中 9示例工作流 中的出图的节点 ID,它的值为一个数组,数组中的每个元素是一个图片链接。final_files 字段为最终结果。progress_num 字段为任务进度,取值范围:0-100。

NOTE

关于 API 请求和响应字段的具体描述,请查看 API 接口文档 POST /api/maas/comfy_task_api/get_task_info

在使用 curl 下载文件时,URL 必须经过解码处理,因为有时 URL 包含特殊字符或编码字符,可能会导致请求失败。以下是代码示例:

shell
# URL
url_encoded='https://infini-imagegen.oss-cn-beijing.aliyuncs.com/te-b905754427352261%2Fac-c66h4ddlwutmbinv%2Fcft-c7zd47xvlvmke3o7%2Fa2b701fd-5d4e-4aa3-b11d-ba0feb0152da.png?Expires=1725513702\u0026OSSAccessKeyId=LTAI5tBgzFapTV38XHKZjHPa\u0026Signature=%2FvJhgJceci%2FbL8nHk%2Bx%2F%2BqIroqQ%3D'
# 解码
decoded_url=$(printf '%b' "$url_encoded")
# 下载
curl -o myfile.png "$decoded_url"

以下是结果图片:

alt text

图生图任务

如果使用 GenStudio 托管图生图工作流,API 调用流程如下:

  1. 准备需要输入的图片。
    • 调用 ComfyUI API 服务的图片上传接口,将图片上传至 GenStudio 服务,供后续提交任务时引用;
    • 或者您可以自备 OSS 图片链接(阿里云/亚马逊),提交任务时直接为 LoadImage / LoadImageMask 节点传入 OSS 图片链接。
  2. 提交生图请求,将图生图任务加入队列。
  3. 轮询任务状态,直到任务完成或失败。状态 3 表示全部图片生成结束。
  4. 下载当前 Workflow 生成的所有图像。

下面我们将使用示例工作流,以文生图的生成结果作为输入,通过 API 提交一个图生图任务,并获取修改后的图像。

图生图示例 Workflow

示例使用以下设置:

  • 工作流 API JSON: ComfyUI 导出的图生图工作流
  • 模型:majicMIX realistic 麦橘写实_v7.safetensors
  • 采样器名称:ddim
  • 调度器:karras
  • 步骤:30
  • cfg:9
  • API 更改后的正面提示:Spiderwoman dressed entirely in monochromatic, pure black suit standing in middle of a crowded place, skyscrapers in the background, cinematic, neon colors, realistic look
  • API 更改后的负面提示:ugly, deformed, red, reddish, blue

上传图片至 GenStudio(可选)

TIP

GenStudio 支持直接为 LoadImage / LoadImageMask 节点传入 OSS 图片链接。支持阿里云 OSS 与亚马逊 S3。如果您的输入图片已自行上传至第三方 OSS,则无需单独调用上传图片接口。请跳过本节,执行下一步骤。

向上传图片接口发送 CURL 请求,其中 --form 是 curl 命令中用于发送 multipart/form-data 格式数据的参数。@ 符号的在 curl 命令表示这是一个文件路径,而不是普通的值。GenStudio 收到图片文件后将存入 OSS,返回 image_id 供其他接口引用。

shell
curl --request POST \
  --url https://cloud.infini-ai.com/api/maas/comfy_task_api/upload/image \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer sk-xxxxxxxxxxxxxxxx' \
  --header 'Content-Type: multipart/form-data' \
  --form source_file=@/Users/janedoe/spiderman-in-red-suit.png

示例中使用的是 macOS/Linux 的路径格式,Windows 用户需要使用不同的格式(如 C:\Users\janedoe\pictures\spiderman-in-red-suit.png)

IMPORTANT

如果您更习惯使用 Apifox/Postman 等工具,请务必正确设置 source_file 参数的类型为 file。推荐您直接导入 GenStudio 提供的 OpenAPI 规范文件,避免手动配置接口导致错误。详见与 Apifix/Postman 集成

200 OK 响应示例的结构如下:

JSON
{
    "code": 0,
    "msg": "Success",
    "data": {
        "image_id": "te-b905754427352261/ac-c66h4ddlwutmbinv/sui-c73eqoorz56qaq7q.png"
    }
}

提交图生图任务

使用 API 提交图生图任务,需要使用 POST /api/maas/comfy_task_api/prompt 接口。JSON 请求体中的 workflow_id 为工作流 ID。prompt 对象中包含在当前请求中修改的节点参数。

DANGER

JSON 请求体中 prompt 参数的值需要根据工作流的节点 ID 和可修改参数自行构建。

  • 请勿在 prompt 参数中直接传入 ComfyUI 导出的 Workflow API JSON 文件。
  • 请勿在 prompt 参数中直接传入 GenStudio Workflow 「查看参数」的内容。

CURL 请求可直接从试运行工作流界面中拷贝,示例如下:

shell
curl --request POST \
  --url https://cloud.infini-ai.com/api/maas/comfy_task_api/prompt \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer sk-xxxxxxxxxxxxxxxx' \
  --header 'Content-Type: application/json' \
  --data '{
    "workflow_id": "wf-c73epllu4i3bxvzr",
    "prompt": {
      "3": {
        "inputs": {
          "seed": 423710630168223,
          "steps": 30,
          "cfg": 9,
          "sampler_name": "ddim",
          "scheduler": "karras",
          "denoise": 0.6
        }
      },
      "4": {
        "inputs": {
          "ckpt_name": "majicMIX realistic 麦橘写实_v7.safetensors"
        }
      },
      "6": {
        "inputs": {
          "text": "Spiderwoman dressed entirely in monochromatic, pure black suit standing in middle of a crowded place, skyscrapers in the background, cinematic, neon colors, realistic look"
        }
      },
      "7": {
        "inputs": {
          "text": "ugly, deformed, red, reddish, blue"
        }
      },
      "10": {
        "inputs": {
          "image": "te-b905754427352261/ac-c66h4ddlwutmbinv/sui-c73eqoorz56qaq7q.png"
        }
      }
    }
  }'

200 OK 响应示例的结构如下:

JSON
{
    "code": 0,
    "msg": "Success",
    "data": {
        "prompt_id": "cft-c73e5ci6dwb5wfhl"
    }
}

prompt_id 是提交任务后返回的唯一 ID,用于获取任务状态和结果。

获取图生图任务状态和结果

使用 API 获取任务排队信息和生图结果,需要使用 POST /api/maas/comfy_task_api/get_task_info 接口。

CURL 请求正文示例如下:

shell
curl --request POST \
  --url https://cloud.infini-ai.com/api/maas/comfy_task_api/get_task_info \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer sk-xxxxxxxxxxxxxxxx' \
  --header 'Content-Type: application/json' \
  --data '{
  "comfy_task_ids": [
    "cft-c73e5ci6dwb5wfhl"
  ],
  "url_expire_period": 1000
}'

comfy_task_ids 可接受一个任务 ID 数组。由于生图任务是异步生成,需要轮询获取任务状态和结果。

在上面的示例中,我们只传入一个任务 ID(上一步返回的 prompt_id)。设置 url_expire_period 为 1000,表示结果图片链接有效期为 1000 秒。

如果 200 OK 响应结果中某个任务 ID 的 "status": 3,表示生图已成功并可通过返回的 OSS URL 获取生图结果。响应示例如下:

JSON
{
    "code": 0,
    "msg": "Success",
    "data": {
        "comfy_task_info": [
            {
                "comfy_task_id": "cft-c73e5ci6dwb5wfhl",
                "status": 3,
                "queue_size": 0,
                "current_position": 0,
                "errMsg": "",
                "files": {
                    "9": [
                        "https://infini-imagegen.oss-cn-beijing.aliyuncs.com/te-b905754427352261%2Fac-c66h4ddlwutmbinv%2Fcft-c73e5ci6dwb5wfhl%2F4e066af5-79df-40ab-8a2d-57012b3f94b3.png?Expires=1726654989\u0026OSSAccessKeyId=LTAI5tBgzFapTV38XHKZjHPa\u0026Signature=28hPa004ivIW4WX%2BpueVTvQcLXw%3D"
                    ]
                },
                "final_files": [
                    "https://infini-imagegen.oss-cn-beijing.aliyuncs.com/te-b905754427352261%2Fac-c66h4ddlwutmbinv%2Fcft-c76ujyezgep5pcal%2F83f2227c-9c1a-4e6a-813b-1359e2d1867e.png?Expires=1728615208&OSSAccessKeyId=LTAI5tBgzFapTV38XHKZjHPa&Signature=V1XbMwpAYXBt8eD1FN690kKcnVk%3D"
                ],
                "progress_num": 100
            }
        ]
    }
}

status 字段为任务状态,取值范围:1-排队中,2-生成中,3-生成成功,4-生成失败,5-权限不足。

files 字段为任务结果,其中 9示例工作流 中的出图的节点 ID,它的值为一个数组,数组中的每个元素是一个图片链接。final_files 字段为最终结果。progress_num 字段为任务进度,取值范围:0-100。

NOTE

关于 API 请求和响应字段的具体描述,请查看 API 接口文档 POST /api/maas/comfy_task_api/get_task_info

在使用 curl 下载文件时,URL 必须经过解码处理,因为有时 URL 包含特殊字符或编码字符,可能会导致请求失败。以下是代码示例:

shell
# URL
url_encoded='https://infini-imagegen.oss-cn-beijing.aliyuncs.com/te-b905754427352261%2Fac-c66h4ddlwutmbinv%2Fcft-c73e5ci6dwb5wfhl%2F4e066af5-79df-40ab-8a2d-57012b3f94b3.png?Expires=1726654989\u0026OSSAccessKeyId=LTAI5tBgzFapTV38XHKZjHPa\u0026Signature=28hPa004ivIW4WX%2BpueVTvQcLXw%3D'
# 解码
decoded_url=$(printf '%b' "$url_encoded")
# 下载
curl -o spiderman-in-blue-suit.png "$decoded_url"

以下是结果图片:

alt text

实时获取任务进度

您可以使用 WebSocket API 获取并显示 ComfyUI 任务的实时进度。以下使用 Javascript 讲解基本流程。

WebSocket 连接信息

API URL:

wss://cloud.infini-ai.com/maas/api/comfy_task_ws_api/get_task_progress

鉴权 Token

创建生图任务后,POST /api/maas/comfy_task_api/prompt 接口会返回 prompt_token,有效期 24 小时。

Step 0 建立 WebSocket 连接

建立 WebSocket 连接时,需要发送 Token。Token 需要附加在 URL 后面,以 ?authorization= 分隔。

javascript
const promptToken = 'your_prompt_token_here'; // 替换为实际的 prompt_token
const socket = new WebSocket(`wss://cloud.infini-ai.com/api/maas/comfy_task_ws_api/get_task_progress?authorization=${promptToken}`);

socket.onopen = () => {
  console.log('WebSocket 连接已建立');
};

NOTE

不支持在建立 WebSocket 连接时后发送 Token。Token 必须作为 URL 参数包含在初始连接请求中。

Step 1 接收和处理任务进度

连接建立后,会收到 WebSocket 消息事件。消息事件中包含任务进度、状态、已生成数据,您需要解析并显示进度、并获取生成的结果。

javascript
socket.onmessage = (event) => {
  const data = JSON.parse(event.data);
  const taskInfo = data.comfy_task_info;
  
  // 显示任务进度
  displayTaskProgress(taskInfo);
};

function displayTaskProgress(taskInfo) {
  const progressElement = document.getElementById('task-progress');
  progressElement.innerHTML = `
    <p>任务ID: ${taskInfo.comfy_task_id}</p>
    <p>状态: ${getStatusText(taskInfo.status)}</p>
    <p>进度: ${taskInfo.progress_num}%</p>
    <p>队列位置: ${taskInfo.current_position} / ${taskInfo.queue_size}</p>
  `;
  
  // 当状态为3时,记录"开始生成图片"
  if (taskInfo.status === 3) {
    console.log("开始生成图片");
  }
  
  // 始终获取 files 中的 URL
  if (taskInfo.files) {
    Object.values(taskInfo.files).forEach(urls => {
      displayResultFiles(urls.map(decodeAndCleanUrl));
    });
  }
  
  // 只有在 progress_num 等于 100 时才获取 final_files 中的 URL
  if (taskInfo.progress_num === 100 && taskInfo.final_files) {
    displayResultFiles(taskInfo.final_files.map(decodeAndCleanUrl));
  }
}

function getStatusText(status) {
  const statusMap = {
    1: '排队中',
    2: '生成中',
    3: '生成成功',
    4: '生成失败'
  };
  return statusMap[status] || '未知状态';
}

function displayResultFiles(files) {
  const filesElement = document.getElementById('result-files');
  filesElement.innerHTML += files.map(file => `<img src="${file}" alt="结果图片">`).join('');
}

// 直接返回的 OSS 链接包含 \u 编码,请解码后使用。
function decodeAndCleanUrl(url) {
  // 解码 URL
  let decodedUrl = decodeURIComponent(url);
  
  // 替换 \u 编码
  decodedUrl = decodedUrl.replace(/\\u[\dA-F]{4}/gi, match => 
    String.fromCharCode(parseInt(match.replace(/\\u/g, ''), 16))
  );
  
  return decodedUrl;
}

消息中的 comfy_task_info 字段的结构如下,字段描述可参考 API 文档中的 ComfyTaskInfo

JSON
{
  "comfy_task_info": {
    "comfy_task_id": "cft-c76vnohm2zwmmoyj",
    "status": 3,
    "queue_size": 0,
    "current_position": 0,
    "errMsg": "",
    "files": {
      "9": [
        "https://infini-imagegen.oss-cn-beijing.aliyuncs.com/te-b905754427352261%2Fac-c66h4ddlwutmbinv%2Fcft-c76u7vyh7k2wlozr%2F7c27a442-31f9-40e3-920c-5a5acd3816c1.png?Expires=1728644139&OSSAccessKeyId=LTAI5tBgzFapTV38XHKZjHPa&Signature=IKntIayj43Fq%2BbJ6djzxuDuAc%2Bw%3D"
      ]
    },
    "final_files": [
      "https://infini-imagegen.oss-cn-beijing.aliyuncs.com/te-b905754427352261%2Fac-c66h4ddlwutmbinv%2Fcft-c76u7vyh7k2wlozr%2F7c27a442-31f9-40e3-920c-5a5acd3816c1.png?Expires=1728644139&OSSAccessKeyId=LTAI5tBgzFapTV38XHKZjHPa&Signature=IKntIayj43Fq%2BbJ6djzxuDuAc%2Bw%3D"
    ],
    "progress_num": 100
  }
}

NOTE

  • 直接返回的 OSS 链接包含 \u 编码,请解码后使用。可参见示例代码中的 decodeAndCleanUrl 函数。
  • 文件 URL 的有效期为 10 分钟,请及时处理或显示结果文件。
  • 每次进度更新都会发送全量文件信息,注意优化界面更新逻辑,避免不必要的重绘。
  • 如果达到 100 或者任务失败,连接会自动关闭。如果一直没有达到 100,连接会保持,您也可以设置一个没有进度更新的超时时间,主动断开。
  • 暂不限制 WebSocket 连接数量。

图片后处理

在获取 ComfyUI 生成的图片结果时,可指定 image_post_process_cmd 参数,对图片进行实时处理。此参数会您指定的图片处理指令透传给阿里云对象存储服务 (OSS),实现图片格式转换和质量变换等操作。API Response 返回的 OSS 链接将自动包含您指定的图片处理参数,当您通过该链接访问图片时,阿里云 OSS 服务将根据参数实时处理图片并返回结果。

目前支持的处理操作:

您需要在调用 POST /api/maas/comfy_task_api/get_task_info 接口时传入 image_post_process_cmd 参数。具体结构与用法请参考 API 文档。

常见问题

支持什么 ComfyUI 节点?

平台预置的 ComfyUI 运行环境中包含部分常用模型和节点。预置环境中支持的 Checkpoint 和自定义节点: ComfyUI HTTP API 参考文档

如果预置环境无法运行您的 Workflow,GenStudio 支持定制私有环境。请联系无问芯穹

为何 ComfyUI 服务生图任务接口没有统一的 OpenAPI 规范?

由于 ComfyUI 工作流 API 服务的「生图任务接口」(/api/maas/comfy_task_api/prompt)定义是 完全基于用户上传的 ComfyUI 工作流文件动态生成的,因此,该 API 的接口定义(Schema),包括接受哪些参数、参数的数据类型、有效值范围等等,都直接取决于用户工作流文件内部的节点配置和连接方式

为何无法提供统一的 OpenAPI 规范?

与传统的 API 平台类似,ComfyUI 工作流 HTTP API 提供一份统一的 OpenAPI (Swagger) 规范文档,描述所有可用的 API 接口、请求参数、响应格式等等。

然而,对于 ComfyUI 工作流 HTTP API 的「提交生图任务」接口来说,无法在 OpenAPI 规范提供细致的参数描述,原因在于

  • 用户工作流的差异性:ComfyUI 的强大之处在于其高度的灵活性和可定制性。每个用户可以根据自己的需求,自由地设计和构建完全不同的工作流。不同的工作流会包含不同的节点、不同的参数,以及不同的输入输出结构。
  • API 接口的动态生成:「生图任务接口」定义是在用户工作流文件关联环境后,平台动态分析工作流结构,并根据工作流内部的节点参数自动生成的。这意味着,每个用户上传的工作流,都会生成一套独一无二的 API 接口。

平台提供的「入参范围」的作用

为了帮助用户了解自己工作流的「生图任务接口」(/api/maas/comfy_task_api/prompt) API 输入要求,我们的平台采取了以下方案:

  1. 工作流文件验证:平台会对用户上传的 ComfyUI 工作流文件进行深度验证,分析工作流的节点结构和参数信息。
  2. 动态生成参数 Schema:基于验证结果,平台 自动生成详细的参数 Schema。Schema 中会明确列出:
    • API 接受的所有输入参数名称。
    • 每个参数的数据类型 (例如,字符串、整数、浮点数、枚举值等)。
    • 每个参数的有效值范围或枚举值列表 (例如,模型名称的下拉选项、数值参数的最小值/最大值等)。
    • 参数的验证规则 (例如,是否必填、数据格式要求等)。
  3. Web 控制台展示「入参范围」:平台将生成的参数 Schema 以 **「入参范围」**的形式,直观地展示在 Web 控制台上。用户可以在工作流详情页面找到这份数据表。

如何使用「入参范围」?

这份「入参范围」 就是您特定工作流的「生图任务接口」API 入参规范说明文档。

  • 了解 API 输入参数:详细列出了您的工作流 API 接受的所有输入参数,以及每个参数的名称和含义。
  • 掌握参数数据类型和有效值:清晰地标明每个参数的数据类型和有效值范围 (或枚举值)。这可以帮助您构建正确的 API 请求,避免因参数类型错误或值超出范围导致的请求失败。
  • 查看参数验证规则:展示参数的验证规则,例如哪些参数是必填的,哪些参数有特定的格式要求。这可以帮助您确保 API 请求的完整性和有效性。
  • 编程方式读取验证规则:可一键复制 JSON 格式的「入参范围」数据,便于在代码中处理。

API 服务可以直接传入工作流 API JSON 吗?

不支持。

  • ComfyUI 工作流 API 服务的提交生图任务接口定义了专门的输入格式。请参考 POST /api/maas/comfy_task_api/prompt 接口构造请求体。

    请勿将 ComfyUI 直接导出的 API Format JSON 作为提交生图任务接口 prompt 参数的值。

    GenStudio 托管工作流「入参范围」展示的 JSON 也不能直接作为该接口 prompt 参数的值。

  • ComfyUI 工作流托管服务仅支持在控制台网页上新增托管工作流,不支持以 API 方式创建新的托管工作流。

以下 Diff 以文生图工作流为例,展示了 ComfyUI 导出的 API Format JSON(修改前)与 prompt 参数值(修改后)的差异:

JSON
{
    "3": {
      "inputs": {
        "seed": 1, 
        "seed": 423710630168223, 
        "steps": 20,
        "cfg": 7,
        "sampler_name": "ddim",
        "scheduler": "karras",
        "denoise": 1,
        "model": [ 
          "4", 
          0
        ], 
        "positive": [ 
          "6", 
          0
        ], 
        "negative": [ 
          "7", 
          0
        ], 
        "latent_image": [ 
          "5", 
          0
        ] 
      },
      "class_type": "KSampler", 
      "_meta": { 
        "title": "KSampler"
      } 
    },
    "4": {
      "inputs": {
        "ckpt_name": "majicMIX realistic 麦橘写实_v7.safetensors"
      },
      "class_type": "CheckpointLoaderSimple", 
      "_meta": { 
        "title": "Load Checkpoint"
      } 
    },
    "5": {
      "inputs": {
        "width": 512,
        "height": 512,
        "batch_size": 1
      },
      "class_type": "EmptyLatentImage", 
      "_meta": { 
        "title": "Empty Latent Image"
      } 
    },
    "6": {
      "inputs": {
        "text": "a girl", 
        "text": "Rabbit in a red suit standing in middle of a crowded place, skyscrapers in the background, cinematic, neon colors, realistic look", 
        "clip": [ 
          "4", 
          1
        ] 
      },
      "class_type": "CLIPTextEncode", 
      "_meta": { 
        "title": "CLIP Text Encode (Prompt)"
      } 
    },
    "7": {
      "inputs": {
        "text": "", 
        "text": "ugly, deformed", 
        "clip": [ 
          "4", 
          1
        ] 
      },
      "class_type": "CLIPTextEncode", 
      "_meta": { 
        "title": "CLIP Text Encode (Prompt)"
      } 
    },
    "8": { 
      "inputs": { 
        "samples": [ 
          "3", 
          0
        ], 
        "vae": [ 
          "4", 
          2
        ] 
      }, 
      "class_type": "VAEDecode", 
      "_meta": { 
        "title": "VAE Decode"
      } 
    }, 
    "9": { 
      "inputs": { 
        "filename_prefix": "ComfyUI", 
        "images": [ 
          "8", 
          0
        ] 
      }, 
      "class_type": "SaveImage", 
      "_meta": { 
        "title": "Save Image"
      } 
    } 
  }