在Dify调用EAS部署的ComfyUI服务

通过将PAI-EAS部署的通义万相(ComfyUI)服务作为工具集成到Dify,可以将复杂的创作流程自动化。本文将介绍服务的部署与集成,实现从文本到多媒体内容的端到端生成。

方案概述

本方案的核心是利用Dify作为应用编排器,调用部署在PAI-EAS上的ComfyUI推理服务。ComfyUI的推理任务是异步执行的,因此整个调用链路如下:

  1. 提交任务:DifyEAS服务发送一个POST请求,请求体中包含ComfyUI工作流的JSON描述。EAS接收任务后,会立即返回一个唯一的prompt_id

  2. 轮询状态:Dify使用上一步获取的prompt_id,通过GET请求循环查询(轮询)任务的执行状态。EAS会返回任务是否完成、成功或失败等信息。

  3. 获取结果:判断任务成功执行后,再次发起GET请求获得最终结果,其中包含了生成文件在OSS上的文件名。Dify将文件名与OSS访问地址拼接,最终向用户展示完整的图片或视频链接。

完整工作流示例如下:

image

步骤一:(可选)部署Dify

说明

若已有Dify环境,可跳过本节。本文以计算巢部署Dify社区单机版为例。

  1. 进入计算巢Dify社区版服务详情页,单击开始部署

  2. 根据需求选择配置。对于基础演示,可选择单机版模板,实例类型选择ecs.u1-c1m2.xlarge,并设置实例密码,选择一个可用区。

  3. 单击下一步:确认订单,在跳转页面单击立即创建

  4. 服务部署完成后,单击详情,在概览页签的立即使用区域,找到dify访问链接。注册账号后登录就能创建dify应用。image

步骤二:部署万相ComfyUI

  1. 进入ModelGallery,在搜索框中输入通义万相2.1-文生视频-1.3B,单击卡片进入模型详情页。

  2. 单击右上角部署,在配置页面进行以下设置,其余保持默认。

    • 部署方式:选择ComfyUI > 标准部署

    • 服务配置:在JSON编辑器中,配置storage.oss.path参数,将其值修改为实际的OSS路径(例如:oss://examplebucket/wan)。此路径将作为ComfyUI的工作目录用于存放生成的内容。关于OSS操作,请参见OSS控制台快速入门image

  3. 单击部署。等待约3分钟,当服务状态变为运行中,表示部署成功。

  4. 单击服务名称进入详情页,在概览页面的基本信息区域,单击查看调用信息。获取EAS服务的公网调用地址和访问Token,用于在Dify中调用服务。

    image

步骤三:创建Dify应用

Dify导入示例DSL文件wan-comfyui-dify.yml,本文以此说明调用ComfyUI的关键节点设置。

image

1. 设置环境变量

  • OSS_URL:生成文件的访问路径。本文ComfyUI工作目录为oss://examplebucket/wan,因此设为https://examplebucket.oss-cn-hangzhou.aliyuncs.com/wan/output。其中oss-cn-hangzhou.aliyuncs.comOSS杭州的外网Endpoint,其他地域请参见OSS地域和访问域名

  • EAS_Token:步骤二中获取的服务Token。

  • EAS_URL:步骤二中获取的服务公网调用地址。

image

2. 开始节点设置输入变量

将正反向提示词等动态参数设为变量,供每次调用时输入。

dify开始节点

3. 配置POST请求(获取Prompt ID)

3.1 设置请求地址

EAS_URL后追加/prompt构成POST请求地址。

image

3.2 构造并发起POST请求

配置URL、HEADERSBODY。其中BODY为导出的ComfyUI工作流JSON(创建及导出参见WebUI使用),并将需要动态修改的参数(如提示词、种子数等)替换为Dify中的变量。

post请求

3.3 获取Prompt ID

从返回结果中提取prompt_id,用于后续轮询结果。

def main(arg: str) -> dict:
    data = json.loads(arg)
    return {"result": data["prompt_id"]}

image

4. 配置轮询逻辑(获取推理结果)

使用prompt_id循环发起GET请求,检查任务状态。

4.1 设置请求地址

EAS_URL后追加history/<prompt_id>构成GET请求地址。其中<prompt_id>为上一步的结果。

image

4.2 根据prompt_id发起GET请求

image

4.3 延时等待

在每次轮询之间插入一个代码节点,执行time.sleep(12)等操作,以避免过于频繁的请求。

import time

def main()-> dict:
    time.sleep(12)
    return {
        "result": ""
    }

image

4.4 判断执行结束

返回结果中有prompt_id表示推理已完成。

image

5. 拼接文件地址并展示结果

任务完成后,从最终的轮询结果中提取文件名,并与环境变量中的OSS_URL拼接,形成可公开访问的文件链接,并在Dify的“结束”节点中展示。

5.1 获取推理结果

该节点配置与4.2的节点配置相同。

image

5.2 提取文件名

import json

def main(input_str: str) -> dict:
    data = json.loads(input_str)
    images = []
    image_names = []
    first_key = next(iter(data))
    status = data[first_key]["status"]
    
    if status["completed"] and status["status_str"] == "success":
        images = data[first_key]["outputs"]["28"]["images"]
    
    for img in images:
        image_names.append(img["filename"])
    
    # 将列表转换为字符串
    image_names_str = ",".join(image_names)
    
    return {
        "result": image_names_str,
    }

image

5.3 拼接文件访问地址

将文件名拼接至OSS_URL,形成可访问的公网链接,并在Dify应用结果中展示。

重要

需确保OSS bucket已设置为公共读权限,详情见Bucket ACL

image

文件地址

步骤四:测试应用

Dify单击右上角预览,输入正反向提示词,对话框中输入1(工作流未使用该字段,可随意输入),发送之后,等待视频生成。

测试结果

生产应用建议

  • 安全性:在生产环境中,将OSS Bucket设置为公共读存在数据安全风险。建议限制只允许特定IPVPC访问,详情见Bucket Policy

  • 稳定性与成本:合理设置轮询的等待时间。过短的间隔会增加API调用次数和服务器负载,可能产生不必要的费用;过长的间隔则会增加用户的等待时间。建议根据您任务的平均耗时进行调整。

常见问题

  1. 为什么无法访问生成的图片或视频链接?

    请检查以下几点:

    • OSS Bucket是否已设置为公共读权限。

    • Dify中配置的OSS_URL环境变量是否正确,特别是OSS访问域名是否与Bucket所在地域匹配。

  2. 工作流一直卡在轮询步骤怎么办?

    这通常意味着EAS服务端的任务未能成功完成。请登录PAI控制台,查看对应EAS服务的实时日志,排查是否有运行时错误。