写真相机方案

写真相机方案实现了自动化训练用户专属的Lora模型,并利用Lora模型和模板图片生成用户个性化的写真照片。模型在线服务(EAS)是PAI提供的模型服务平台。该方案定义了一套算法流程,可以部署为EAS模型在线服务,并提供了相关的调用接口,用于实现AI写真。本文为您介绍如何部署相关的EAS模型在线服务并调用接口实现AI写真。

背景信息

EAS相关功能说明

EASPAI提供的模型服务平台,在写真相机方案中,使用的核心功能包括:

  • 通过自定义镜像部署模型服务(包括核验服务训练服务预测服务),基于PAI的写真相机算法流程提供了图像核验、Lora训练和图像生成三个API接口服务,同时支持请求的负载均衡和GPU实例的自动扩缩容。

  • 该功能支持异步队列操作,可以查询和操作队列消费状态,并且可以设置队列优先级。详情请参见异步推理服务

  • 提供了PythonJavaSDK,支持透传业务定义的自定义参数。详情请参见服务调用SDK

写真相机算法流程介绍

  1. 图像核验

    初步检测图片质量是否符合要求。

  2. Lora训练

    首先对图像进行预处理和质量检测,随后利用LoRA进行自动化训练和评估,最终生成优化后的模型。

  3. 图像生成

    1. 图像预处理。

    2. 初次生成图像。

    3. 二次生成图像。

前提条件

  • 已创建专有网络,并配置公网连接。

    1. 已创建专有网络VPC、交换机和安全组。具体操作,请参见搭建IPv4专有网络创建安全组

    2. 已为该VPC创建了公网NAT网关,并为该网关绑定了弹性公网IP、配置了SNAT条目。具体操作,请参见使用公网NAT网关SNAT功能访问互联网

  • 已开通PAI-EAS并创建默认工作空间,详情请参见开通并创建默认工作空间

  • 如果使用RAM用户来部署模型,需要为RAM用户授予PAI-EAS的管理权限,详情请参见云产品依赖与授权:EAS

  • 已准备好5-20张训练图片和1张模板图片,用于模型训练和写真制作。图片格式支持.jpg.jpeg.png等。

    • 如果进行单人写真制作,模板图片中包含单张人脸即可。多张训练图片中的人脸属于同一个人。

    • 如果进行多人写真制作,模板图片中需包含多张人脸,且人脸数量与模型训练的model_id数量一致。

    • 请确保训练图片和模板图片的尺寸大于512×512像素。

使用限制

仅支持在华北2(北京)和新加坡地域使用该方案。

部署PAI-EAS模型服务

部署核验服务

  1. 进入部署服务页面。具体操作,请参见服务部署:控制台

  2. 部署服务页面,配置以下关键参数,其他参数取默认配置即可,更多参数配置说明,请参见控制台上传部署

    • 模型服务信息区域中,配置以下参数:

      参数

      描述

      服务名称

      参考界面提示,自定义服务名称。例如:photog_check。

      部署方式

      选择镜像部署服务,并打开异步服务开关。

      镜像选择

      选中镜像地址,并在文本框中输入镜像地址,取值如下:

      • 华北2(北京)的镜像地址为:registry.cn-beijing.aliyuncs.com/mybigpai/photog_pub:check.1.0.0.pub

      • 新加坡的镜像地址为:registry.ap-southeast-1.aliyuncs.com/mybigpai/photog_pub:check.1.0.0.pub

      代码配置

      单击填写代码配置,进行代码配置。支持选择以下任意一种挂载方式:

      • OSS挂载

        • 选择您自己的OSS Bucket路径。例如oss://examplebucket/

        • 挂载路径:配置为/photog_oss

      • NAS挂载

        • NAS挂载点:选择您自己的NAS文件系统和挂载点。

        • NAS源路径:配置为需要挂载的NAS中的源路径,例如/

        • 挂载路径:配置为/photog_oss

      运行命令

      • 运行命令配置为python app.py

      • 端口号配置为7860。

    • 资源部署信息区域中,配置以下参数:

      参数

      描述

      资源组种类

      选择公共资源组

      资源配置方法

      选择常规资源配置

      资源配置选择

      选择GPU下的gu30系列机型,推荐使用ml.gu7i.c32m188.1-gu30

      系统盘配置

      将额外系统盘配置为120 GB。

    • 异步服务配置区域中,配置以下参数:

      参数

      描述

      异步队列资源配置

      选择公共资源组

      异步队列占用资源

      • 最小实例数:1。

      • CPU:8核。

      • 内存:64GB。

      单一输入请求最大数据

      配置为20480 KB。避免队列中每个请求的存储空间不足。

      单一输出返回最大数据

    • 专有网络配置区域中,选择已创建的VPC、交换机和安全组。

    • 对应配置编辑区域中,添加以下配置,您可以参考下方的完整配置示例,来添加新增的参数。

      字段

      新增的参数

      metadata

      增加以下参数:

      "rpc": {
                  "keepalive": 3600000,
                  "worker_threads": 1
              }
      • keepalive:单个请求的最长处理时间,单位为毫秒,配置为3600000。

      • worker_threads:EAS每个实例中用于并发处理请求的线程数。

        默认为5,表示最先进入队列的前五个任务会被分配到同一个实例上。建议将该参数设置为1,这样可以确保请求按顺序排队处理。

      queue

      增加参数"max_delivery": 1,防止失败后多次重复投递。

      完整的配置示例如下:

      {
          "metadata": {
              "name": "photog_check",
              "instance": 1,
              "rpc": {
                  "keepalive": 3600000,
                  "worker_threads": 1
              },
              "type": "Async"
          },
          "cloud": {
              "computing": {
                  "instance_type": "ml.gu7i.c32m188.1-gu30",
                  "instances": null
              },
              "networking": {
                  "vswitch_id": "vsw-2ze4o9kww55051tf2****",
                  "security_group_id": "sg-2ze0kgiee55d0fn4****",
                  "vpc_id": "vpc-2ze5hl4ozjl4fo7q3****"
              }
          },
          "features": {
              "eas.aliyun.com/extra-ephemeral-storage": "100Gi"
          },
          "queue": {
              "cpu": 8,
              "max_delivery": 1,
              "min_replica": 1,
              "memory": 64000,
              "resource": "",
              "source": {
                  "max_payload_size_kb": 20480
              },
              "sink": {
                  "max_payload_size_kb": 20480
              }
          },
          "storage": [
              {
                  "oss": {
                      "path": "oss://examplebucket/",
                      "readOnly": false
                  },
                  "properties": {
                      "resource_type": "code"
                  },
                  "mount_path": "/photog_oss"
              }
          ],
          "containers": [
              {
                  "image": "registry.cn-beijing.aliyuncs.com/mybigpai/photog_pub:check.1.0.0.pub",
                  "script": "python app.py",
                  "port": 7860
              }
          ]
      }
  3. 单击部署

    服务状态运行中时,服务部署成功。

部署训练服务

  1. 进入部署服务页面。具体操作,请参见服务部署:控制台

  2. 部署服务页面,配置以下关键参数,其他参数取默认配置即可,更多参数配置说明,请参见服务部署:控制台

    • 模型服务信息区域中,配置以下参数:

      参数

      描述

      服务名称

      参考界面提示,自定义服务名称。例如:photog_train_pmml。

      部署方式

      选择镜像部署服务,并打开异步服务开关。

      镜像选择

      选中镜像地址,并在文本框中输入镜像地址,取值如下:

      • 华北2(北京)的镜像地址为:registry.cn-beijing.aliyuncs.com/mybigpai/photog_pub:train.1.0.0.pub

      • 新加坡的镜像地址为:registry.ap-southeast-1.aliyuncs.com/mybigpai/photog_pub:train.1.0.0.pub

      代码配置

      单击填写代码配置,进行代码配置。支持选择以下任意一种挂载方式:

      • OSS挂载

        • 选择您自己的OSS Bucket路径,与核验服务选择的OSS路径保持一致。例如oss://examplebucket/

        • 挂载路径:配置为/photog_oss

      • NAS挂载

        • NAS挂载点:选择您自己的NAS文件系统和挂载点。

        • NAS源路径:配置为需要挂载的NAS中的源路径,例如/

        • 挂载路径:配置为/photog_oss

      运行命令

      • 运行命令配置为python app.py

      • 端口号配置为7860。

    • 资源部署信息区域中,配置以下参数:

      参数

      描述

      资源组种类

      选择公共资源组

      资源配置方法

      选择常规资源配置

      资源配置选择

      选择GPU下的gu30系列机型,推荐使用ml.gu7i.c32m188.1-gu30

      系统盘配置

      将额外系统盘配置为120 GB。

    • 异步服务配置区域中,配置以下参数:

      参数

      描述

      异步队列资源配置

      选择公共资源组

      异步队列占用资源

      • 最小实例数:1。

      • CPU:8核。

      • 内存:64GB。

      单一输入请求最大数据

      配置为20480 KB。避免队列中每个请求的存储空间不足。

      单一输出返回最大数据

    • 专有网络配置区域中,选择已创建的VPC、交换机和安全组。

    • 对应配置编辑区域中,添加以下配置,您可以参考下方的完整配置示例,来添加新增的参数。

      字段

      新增的参数

      autoscaler

      (可选)水平自动扩缩容配置,详情请参见水平自动扩缩容功能

      "behavior": {
        "scaleDown": {
          "stabilizationWindowSeconds": 60
        }
      },
      "max": 5,
      "min": 1,
      "strategies": {
                  "queue[backlog]": 1
      }

      metadata

      增加以下参数:

      "rpc": {
                  "keepalive": 3600000,
                  "worker_threads": 1
              }
      • keepalive:单个请求的最长处理时间,单位为毫秒,配置为3600000。

      • worker_threads:EAS每个实例中用于并发处理请求的线程数。

        默认为5,表示最先进入队列的前五个任务会被分配到同一个实例上。建议将该参数设置为1,这样可以确保请求按顺序排队处理。

      queue

      增加参数"max_delivery": 1,防止失败后多次重复投递。

      完整的配置示例如下:

      {
          "autoscaler": {
              "behavior": {
                  "scaleDown": {
                      "stabilizationWindowSeconds": 60
                  }
              },
              "max": 5,
              "min": 1,
              "strategies": {
                  "queue[backlog]": 1
              }
          },
          "metadata": {
              "name": "photog_train_pmml",
              "instance": 1,
              "rpc": {
                  "keepalive": 3600000,
                  "worker_threads": 1
              },
              "type": "Async"
          },
          "cloud": {
              "computing": {
                  "instance_type": "ml.gu7i.c32m188.1-gu30",
                  "instances": null
              },
              "networking": {
                  "vswitch_id": "vsw-2ze4o9kww55051tf2****",
                  "security_group_id": "sg-2ze0kgiee55d0fn4****",
                  "vpc_id": "vpc-2ze5hl4ozjl4fo7q3****"
              }
          },
          "features": {
              "eas.aliyun.com/extra-ephemeral-storage": "120Gi"
          },
          "queue": {
              "cpu": 8,
              "max_delivery": 1,
              "min_replica": 1,
              "memory": 64000,
              "resource": "",
              "source": {
                  "max_payload_size_kb": 20480
              },
              "sink": {
                  "max_payload_size_kb": 20480
              }
          },
          "storage": [
              {
                  "oss": {
                      "path": "oss://examplebucket/",
                      "readOnly": false
                  },
                  "properties": {
                      "resource_type": "code"
                  },
                  "mount_path": "/photog_oss"
              }
          ],
          "containers": [
              {
                  "image": "registry.cn-beijing.aliyuncs.com/mybigpai/photog_pub:train.1.0.0.pub",
                  "script": "python app.py",
                  "port": 7860
              }
          ]
      }
  3. 单击部署

    服务状态运行中时,服务部署成功。

部署预测服务

  1. 进入部署服务页面。具体操作,请参见服务部署:控制台

  2. 部署服务页面,配置以下关键参数,其他参数取默认配置即可,更多参数配置说明,请参见服务部署:控制台

    • 模型服务信息区域中,配置以下参数:

      参数

      描述

      服务名称

      参考界面提示,自定义服务名称。例如:photog_pre_pmml。

      部署方式

      选择镜像部署服务,并打开异步服务开关。

      镜像选择

      选中镜像地址,并在文本框中输入镜像地址。需要同时配置AI写真预测服务和WebUI预测服务镜像地址,在该区域中只需要配置AI写真预测服务镜像地址,WebUI预测服务镜像地址在对应配置编辑区域进行配置。支持配置的镜像列表如下,本方案选择华北2(北京)地域的镜像地址。

      • 华北2(北京)镜像地址:

        • AI写真预测服务:registry.cn-beijing.aliyuncs.com/mybigpai/photog_pub:infer.1.0.0.pub

        • WebUI预测服务:eas-registry-vpc.cn-beijing.cr.aliyuncs.com/pai-eas/stable-diffusion-webui:3.2

      • 新加坡镜像地址:

        • AI写真预测服务:registry.ap-southeast-1.aliyuncs.com/mybigpai/photog_pub:infer.1.0.0.pub

        • WebUI预测服务:eas-registry-vpc.ap-southeast-1.cr.aliyuncs.com/pai-eas/stable-diffusion-webui:3.2

      代码配置

      单击填写代码配置,进行代码配置。支持选择以下任意一种挂载方式,本方案选择OSS挂载。

      • OSS挂载

        • 选择您自己的OSS Bucket路径,与核验服务选择的OSS路径保持一致。例如oss://examplebucket/

        • 挂载路径:配置为/photog_oss

      • NAS挂载

        • NAS挂载点:选择您自己的NAS文件系统和挂载点。

        • NAS源路径:配置为需要挂载的NAS中的源路径,例如/

        • 挂载路径:配置为/photog_oss

      您需要下载并解压WebUI所需的模型文件,并将其按照下图布局方式存放到您的OSS Bucket路径oss://examplebucket/photog_oss/webuiNAS路径/photog_oss/webui中。关于如何将文件上传到OSS Bucket路径,详情请参见命令行工具ossutil 1.0。关于如何将文件上传到NAS路径,详情请参见快速入门(Linux)文件管理image.png

      环境变量

      单击填写环境变量,配置以下两个环境变量:

      • 变量名:URL,变量值:http://127.0.0.1:8000

      • 变量名:AUTHORIZATION,变量值:=

      运行命令

      • 运行命令配置为python app.py

      • 端口号配置为7860。

    • 资源部署信息区域中,配置以下参数:

      参数

      描述

      资源组种类

      选择公共资源组

      资源配置方法

      选择常规资源配置

      资源配置选择

      选择GPU下的gu30系列机型,推荐使用ml.gu7i.c32m188.1-gu30

      系统盘配置

      将额外系统盘配置为120 GB。

    • 异步服务配置区域中,配置以下参数:

      参数

      描述

      异步队列资源配置

      选择公共资源组

      异步队列占用资源

      • 最小实例数:1。

      • CPU:8核。

      • 内存:64GB。

      单一输入请求最大数据

      配置为20480 KB。避免队列中每个请求的存储空间不足。

      单一输出返回最大数据

    • 专有网络配置区域中,选择已创建的VPC、交换机和安全组。

    • 对应配置编辑区域中,添加以下配置,您可以参考下方的完整配置示例,来添加新增的参数。

      字段

      新增的参数

      metadata

      增加以下参数:

      "rpc": {
                  "keepalive": 3600000,
                  "worker_threads": 1
              }
      • keepalive:单个请求的最长处理时间,单位为毫秒,配置为3600000。

      • worker_threads:EAS每个实例中用于并发处理请求的线程数。

        默认为5,表示最先进入队列的前五个任务会被分配到同一个实例上。建议将该参数设置为1,这样可以确保请求按顺序排队处理。

      containers

      增加以下参数:

      {
                  "image": "eas-registry-vpc.cn-beijing.cr.aliyuncs.com/pai-eas/stable-diffusion-webui:3.2",
                  "port": 8000,
                  "script": "./webui.sh --listen --port 8000 --skip-version-check --no-hashing --no-download-sd-model --skip-install --api --filebrowser --sd-dynamic-cache --data-dir /photog_oss/photog/webui/"
              }

      分别表示WebUI预测服务镜像以及对应的运行命令和端口号。

      queue

      增加参数"max_delivery": 1,防止失败后多次重复投递。

      完整的配置示例如下:

      {
          "metadata": {
              "name": "photog_pre_pmml",
              "instance": 1,
              "rpc": {
                  "keepalive": 3600000,
                  "worker_threads": 1
              },
              "type": "Async"
          },
          "cloud": {
              "computing": {
                  "instance_type": "ecs.gn6v-c8g1.2xlarge",
                  "instances": null
              },
              "networking": {
                  "vswitch_id": "vsw-2ze4o9kww55051tf2****",
                  "security_group_id": "sg-2ze0kgiee55d0fn4****",
                  "vpc_id": "vpc-2ze5hl4ozjl4fo7q3****"
              }
          },
          "features": {
              "eas.aliyun.com/extra-ephemeral-storage": "120Gi"
          },
          "queue": {
              "cpu": 8,
              "max_delivery": 1,
              "min_replica": 1,
              "memory": 64000,
              "resource": "",
              "source": {
                  "max_payload_size_kb": 20480
              },
              "sink": {
                  "max_payload_size_kb": 20480
              }
          },
          "storage": [
              {
                  "oss": {
                      "path": "oss://examplebucket/",
                      "readOnly": false
                  },
                  "properties": {
                      "resource_type": "code"
                  },
                  "mount_path": "/photog_oss"
              }
          ],
          "containers": [
              {
                  "image": "registry.cn-beijing.aliyuncs.com/mybigpai/photog_pub:infer.1.0.0.pub",
                  "env": [
                      {
                          "name": "URL",
                          "value": "http://127.0.0.1:8000"
                      },
                      {
                          "name": "AUTHORIZATION",
                          "value": "="
                      }
                  ],
                  "script": "python app.py",
                  "port": 7861
              },
              {
                  "image": "eas-registry-vpc.cn-beijing.cr.aliyuncs.com/pai-eas/stable-diffusion-webui:3.2",
                  "port": 8000,
                  "script": "./webui.sh --listen --port 8000 --skip-version-check --no-hashing --no-download-sd-model --skip-install --api --filebrowser --sd-dynamic-cache --data-dir /photog_oss/photog/webui/"
              }
          ]
      }
  3. 单击部署

    服务状态运行中时,服务部署成功。

调用接口

步骤一:调用图像核验接口

  1. 首先您需要在PAI-EAS模型在线服务页面,单击核验服务的服务方式列下的调用信息,在异步调用页签,获取服务访问地址和Token。image.png

  2. 使用如下代码创建输入队列进行图片核验,并获取队列信息。

    调用示例如下:

    Python SDK

    import json
    from eas_prediction import QueueClient
    
    # 创建输入队列对象,用于写入输入数据。
    input_queue = QueueClient('182848887922****.cn-shanghai.pai-eas.aliyuncs.com', 'photog_check')
    input_queue.set_token('<token>')
    input_queue.init()
    
    datas = json.dumps(
        {
           'request_id'    : 12345,
           'images'        : ["xx.jpg", "xx.jpg"], # urls, a list
           'configure'     : {
                'face_reconize' : True, # Judge whether all pictures are of a person
            }
        }
    )
    
    index, request_id = input_queue.put(f'{datas}')
    print(index, request_id)
    
    # 查看输入队列的详情。
    attrs = input_queue.attributes()
    print(attrs)

    其中关键配置说明如下:

    关键配置

    描述

    默认值

    是否必填

    input_queue

    配置为已获取的核验服务的访问地址,请参考上述代码示例进行配置,STRING类型。

    <token>

    替换为已获取的核验服务的Token,STRING类型。

    request_id

    请求ID,STRING类型。

    images

    配置为模型训练使用图片的URL地址,LIST类型。

    configure

    face_reconize

    判断多张图片中的人脸是否为同一个人,BOOL类型。

    False

    Java SDK

    import com.aliyun.openservices.eas.predict.http.HttpConfig;
    import com.aliyun.openservices.eas.predict.http.QueueClient;
    import com.aliyun.openservices.eas.predict.queue_client.QueueUser;
    import org.apache.commons.lang3.tuple.Pair;
    
    public class AsyncTest {
        public static void main(String[] args) throws Exception {
            /** 创建队列服务客户端 */
            String queueEndpoint = "182848887922****.cn-shanghai.pai-eas.aliyuncs.com";
            String inputQueueName = "photog_check";
            String queueToken = "YmE3NDkyMzdiMzNmMGM3ZmE4ZmNjZDk0M2NiMDA3OTZmNzc1MT****==";
    
            QueueClient inputQueue =
                new QueueClient(queueEndpoint, inputQueueName, queueToken, new HttpConfig(), new QueueUser());
    
            /** 请求数据 */
            String data = "{\n" +
                "    'request_id': 12345,\n" +
                "    'images'    : [\"xx.jpg\", \"xx.jpg\"],\n" +
                "    'configure' : {\n" +
                "        'face_reconize' : True,\n" +
                "    }\n" +
                "}";
            Pair<Long, String> entry = inputQueue.put(data.getBytes(), null);
            System.out.println(String.format("index = %s, request id = %s", entry.getKey(), entry.getValue()));
    
            // 查看输入队列的详情
            System.out.println(inputQueue.attributes());
    
            /** 关闭客户端 */
            inputQueue.shutdown();
        }
    }

    其中:

    关键配置

    描述

    默认值

    是否必填

    queueEndpoint

    配置为已获取的核验服务的访问地址,STRING类型。

    inputQueueName

    配置为核验服务的名称,STRING类型。

    queueToken

    替换为已获取的核验服务的Token,STRING类型。

    request_id

    请求ID,STRING类型。

    images

    配置为模型训练使用图片的URL地址,LIST类型。

    configure

    face_reconize

    判断多张图片中的人脸是否为同一个人,BOOL类型。

    False

    系统返回结果如下:

    Python SDK

    1 6bdea119-01f3-4728-b3d3-b0af366ad3eb
    {'consumers.list.[0]': 'Id: photog_check.photog-check-738569a9-798897bdf5-76****, Index: 0, Pending: 0, Status: Running, Idle: 1h10m4.997s, Window: 1, Slots: 1, AutoCommit: false', 'consumers.stats.total': '1', 'consumers.status.total': '1', 'groups.list.[0]': 'Id: photog_check, Index: 1, Pending: 1, Delivered: 2, Consumers: 1', 'meta.header.group': 'X-EAS-QueueService-Gid', 'meta.header.priority': 'X-EAS-QueueService-Priority', 'meta.header.user': 'X-EAS-QueueService-Uid', 'meta.name': 'photog-check-queue-95e006df', 'meta.state': 'Normal', 'stream.approxMaxLength': '1439', 'stream.firstEntry': '1', 'stream.lastEntry': '1', 'stream.length': '1', 'stream.maxPayloadBytes': '20971520'}

    Java SDK

    index = 2, request id = 61132b43-a527-40dc-89bb-a9a48316ddea
    {"meta.header.priority":"X-EAS-QueueService-Priority","consumers.status.total":"1","stream.firstEntry":"2","stream.maxPayloadBytes":"20971520","consumers.stats.total":"1","stream.approxMaxLength":"1439","stream.length":"1","groups.list.[0]":"Id: photog_check, Index: 2, Pending: 1, Delivered: 3, Consumers: 1","meta.header.group":"X-EAS-QueueService-Gid","stream.lastEntry":"2","consumers.list.[0]":"Id: photog_check.photog-check-738569a9-798897bdf5-76j48, Index: 2, Pending: 0, Status: Running, Idle: 19m11.174s, Window: 1, Slots: 1, AutoCommit: false","meta.name":"photog-check-queue-95e006df","meta.state":"Normal","meta.header.user":"X-EAS-QueueService-Uid"}
    
    Process finished with exit code 0

    其中:

    • index:表示该请求是EAS中的第几个请求。

    • request_id:表示该请求的ID,后续使用该ID获取输出结果。

    • 其他内容表示输入队列详情。

  3. 使用如下代码创建输出队列并获取返回结果,通过返回结果来确认图片是否符合要求。

    调用示例如下:

    Python SDK

    # 创建输出队列对象,用于订阅读取输出结果数据。
    sink_queue = QueueClient('182848887922****.cn-shanghai.pai-eas.aliyuncs.com', 'photog_check/sink')
    sink_queue.set_token('<token>')
    sink_queue.init()
    
    sink_queue.get(request_id, auto_delete=True)[0].data.decode('utf-8')

    其中:

    • sink_queue:配置为已获取的核验服务的访问地址。

    • <token>:替换为已获取的核验服务的Token。

    • auto_delete:默认为True。如果在查询队列时直接使用request_id,但没有设置auto_delete参数,那么将会删除该队列的结果。由于输出队列通常需要删除队列内容,建议将auto_delete参数设置为True。

    Java SDK

    import com.aliyun.openservices.eas.predict.http.HttpConfig;
    import com.aliyun.openservices.eas.predict.http.QueueClient;
    import com.aliyun.openservices.eas.predict.queue_client.DataFrame;
    import com.aliyun.openservices.eas.predict.queue_client.QueueUser;
    import org.apache.commons.lang3.tuple.Pair;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class AsyncPhotoTest {
        public static void main(String[] args) throws Exception {
            /** 创建队列服务客户端 */
            String queueEndpoint = "166233998075****.cn-beijing.pai-eas.aliyuncs.com";
            String inputQueueName = "photog_check";
            String sinkQueueName = String.format("%s/sink", inputQueueName);
            String queueToken = "YjczMzFlYmRkMDU4YmZmMGQ4NTEwODA4NDk3NmFhODE5N2ExMzEy****";
    
            QueueClient inputQueue =
                new QueueClient(queueEndpoint, inputQueueName, queueToken, new HttpConfig(), new QueueUser());
            QueueClient sinkQueue =
                new QueueClient(queueEndpoint, sinkQueueName, queueToken, new HttpConfig(), new QueueUser());
    
            /** 请求数据 */
            String data = "{\n" +
                "  \"request_id\": 12345,\n" +
                "  \"images\": [\"xx.jpg\", \"xx.jpg\"],\n" +
                "  \"configure\": {\n" +
                "    \"face_reconize\": true\n" +
                "  }\n" +
                "}";
            Pair<Long, String> entry = inputQueue.put(data.getBytes(), null);
            Long index = entry.getKey();
            final String requestId = entry.getValue();
            System.out.println(String.format("index = %d, request id = %s", index, requestId));
    
            // 查看输入队列的详情
            System.out.println(inputQueue.attributes());
    
            // 查看输入数据
            Map<String, String> tags =
                new HashMap<String, String>() {
                    {
                        put("requestId", requestId);
                    }
                };
            DataFrame[] dfs = inputQueue.get(0, 1L, 0, false, tags);
            if (dfs.length > 0) {
                System.out.println(String.format("Successfully get input data = %s, index = %d, tags = %s", new String(dfs[0].getData()), dfs[0].getIndex(), dfs[0].getTags()));
            } else {
                System.out.println("no data");
            }
    
            // 查看输出数据
            while (true) {
                dfs = sinkQueue.get(0, 1L, 0, true, tags);
                if (dfs.length > 0) {
                    System.out.println(String.format("Successfully get sink data = %s, tags = %s", new String(dfs[0].getData()), dfs[0].getTags()));
                    break;
                } else {
                    System.out.println("no data");
                    Thread.sleep(5000);
                }
            }
    
            /** 关闭客户端 */
            inputQueue.shutdown();
            sinkQueue.shutdown();
        }
    }

    其中:

    • queueEndpoint:配置为已获取的核验服务访问地址。

    • inputQueueName:配置为核验服务的名称。

    • queueToken:替换为已获取的核验服务的Token。

    • image:配置为模型训练使用的图片的URL地址。

    系统返回如下结果:

    Python SDK

    '{"request_id": "12345", "code": "OK", "message": "success", "data": {"request_id": 12345, "images": ["xx.jpg", "https://xxx.oss-cn-beijing.aliyuncs.com/photog/user_images/foto/train/0.jpg"], "configure": {"face_reconize": true}, "cost_time": 9.820043325424194, "check_results": [{"url": "https://xx-cn-beijing.aliyuncs.com/photog/user_images/foto/train/1.jpg", "message": "success", "code": 1, "frontal": true}, {"url": "https://xx-cn-beijing.aliyuncs.com/photog/user_images/foto/train/0.jpg", "message": "success", "code": 1, "frontal": false}]}}'

    Java SDK

    Successfully get sink data = {"request_id": "12345", "code": "OK", "message": "success", "data": {"request_id": 12345, "images": ["xx.jpg", "xx.jpg"], "configure": {"face_reconize": true}, "cost_time": 0.2047882080078125, "check_results": [{"url": "https://xx-cn-beijing.aliyuncs.com/photog/user_images/foto/train/1.jpg", "message": "success", "code": 1, "frontal": true}, {"url": "https://xx-cn-beijing.aliyuncs.com/photog/user_images/foto/train/0.jpg", "message": "success", "code": 1, "frontal": false}]}}

    参数说明如下:

    参数

    描述

    request_id

    请求ID,STRING类型。

    code

    请求状态码,STRING类型:

    • OK:表示已完成核验。

    • error:表示未完成核验。

    message

    请求状态的详细信息。如果返回结果为success表示执行成功,对于其他返回结果,请根据具体的返回内容来确定。

    data

    返回内容详情,内部字段说明如下:

    • check_results:表示输入的每张图片的检测结果。

      • url:图片的URL地址。

      • message:图片检测详情。success表示核验成功。更多关于message返回结果的可能取值和对应的code,请参见message详情

      • frontal:图片是否为正面。

    • cost_time:本次API调用花费的服务端计算时长。

    • images:核验的图片URL列表,List类型。

    • request_id:请求流水号,STRING类型。

    message详情

    message可能值

    code

    描述

    success

    1

    表示符合要求。

    Image decode error

    2

    无法下载或解码图像。

    Number of face is not 1

    3

    人脸数量不为1。

    Image detect error

    4

    人脸检测异常。

    Image encoding error

    5

    将人脸编码为特征向量时出错,表示无法检测到人脸。

    This photo is not the same person in photos

    6

    如果只出现了这个错误,表示多张图片中的人脸不属于同一个人。

步骤二:调用Lora训练接口

  1. 首先您需要在PAI-EAS模型在线服务页面,单击训练服务的服务方式列下的调用信息,在异步调用页签,获取服务访问地址和Token。image.png

  2. 使用如下代码创建输入队列进行Lora训练并获取队列信息。

    调用示例如下:

    Python SDK

    photog_train_pmmln import json
    from eas_prediction import QueueClient
    
    # 创建输入队列对象,用于写入输入数据。
    input_queue = QueueClient('182848887922****.cn-shanghai.pai-eas.aliyuncs.com', 'photog_train_pmml')
    input_queue.set_token('<token>')
    input_queue.init()
    
    datas = json.dumps(
        {
            'request_id'    : 12345,
            'images'        : ["xx.jpg", "xx.jpg"], # urls
            'configure'     : {
                'user_id'   : "zhoumo", # user id
            }
        }
    )
    
    index, request_id = input_queue.put(f'{datas}')
    print(index, request_id)
    
    # 查看输入队列的详情。
    attrs = input_queue.attributes()
    print(attrs)

    其中关键配置说明如下:

    关键配置

    描述

    默认值

    是否必填

    input_queue

    配置为已获取的训练服务的访问地址,请参考上述代码示例进行配置,STRING类型。

    <token>

    替换为已获取训练服务的Token,STRING类型。

    request_id

    请求ID。STRING类型。

    images

    配置为训练图片的URL地址,LIST类型。

    configure

    user_id

    用户的ID,STRING类型。

    sex

    训练图片中人物的性别。

    secret

    max_train_steps

    总训练步数。

    400

    val_save_checkpointing_steps

    训练的验证步数。

    50

    Java SDK

    import com.aliyun.openservices.eas.predict.http.HttpConfig;
    import com.aliyun.openservices.eas.predict.http.QueueClient;
    import com.aliyun.openservices.eas.predict.queue_client.QueueUser;
    import org.apache.commons.lang3.tuple.Pair;
    
    public class AsyncTest {
        public static void main(String[] args) throws Exception {
            /** 创建队列服务客户端 */
            String queueEndpoint = "182848887922****.cn-shanghai.pai-eas.aliyuncs.com";
            String inputQueueName = "photog_train_pmml";
            String queueToken = "YmE3NDkyMzdiMzNmMGM3ZmE4ZmNjZDk0M2NiMDA3OTZmNzc1MT****==";
    
            QueueClient inputQueue =
                new QueueClient(queueEndpoint, inputQueueName, queueToken, new HttpConfig(), new QueueUser());
    
            /** 请求数据 */
            String data = "{\n" +
                "        'request_id'    : 12345,\n" +
                "        'images'        : [\"xx.jpg\", \"xx.jpg\"],\n" +
                "        'configure'     : {\n" +
                "            'user_id'   : \"zhoumo\",\n" +
                "        }\n" +
                "    }";
            Pair<Long, String> entry = inputQueue.put(data.getBytes(), null);
            System.out.println(String.format("index = %s, request id = %s", entry.getKey(), entry.getValue()));
    
            // 查看输入队列的详情
            System.out.println(inputQueue.attributes());
    
            /** 关闭客户端 */
            inputQueue.shutdown();
        }
    }

    其中关键配置说明如下:

    关键配置

    描述

    默认值

    是否必填

    queueEndpoint

    配置为已获取的训练服务的访问地址,STRING类型。

    inputQueueName

    配置为训练服务的名称,STRING类型。

    queueToken

    替换为已获取训练服务的Token,STRING类型。

    request_id

    请求ID。STRING类型。

    images

    配置为训练图片的URL地址,LIST类型。

    configure

    user_id

    用户的ID,STRING类型。

    sex

    训练图片中人物的性别。

    secret

    max_train_steps

    总训练步数。

    400

    val_save_checkpointing_steps

    训练的验证步数。

    50

    系统返回如下结果:

    Python SDK

    2 bb4ce34d-47e4-425d-bee7-b806e29c6d78
    {'consumers.list.[0]': 'Id: photog_train_pmml.photog-train-pmml-78550f91-7545766654-jpdtp, Index: 2, Pending: 0, Status: Running, Idle: 18h46m24.039s, Window: 1, Slots: 1, AutoCommit: false', 'consumers.stats.total': '1', 'consumers.status.total': '1', 'groups.list.[0]': 'Id: photog_train_pmmln, Index: 2, Pending: 1, Delivered: 3, Consumers: 1', 'meta.header.group': 'X-EAS-QueueService-Gid', 'meta.header.priority': 'X-EAS-QueueService-Priority', 'meta.header.user': 'X-EAS-QueueService-Uid', 'meta.name': 'photog-train-pmmln-queue-7a5e7cc6', 'meta.state': 'Normal', 'stream.approxMaxLength': '1438', 'stream.firstEntry': '2', 'stream.lastEntry': '2', 'stream.length': '1', 'stream.maxPayloadBytes': '20971520'}

    Java SDK

    index = 3, request id = ec3b7c21-c395-4490-ae42-8f66d06e9d4d
    {"meta.header.priority":"X-EAS-QueueService-Priority","consumers.status.total":"1","stream.firstEntry":"3","stream.maxPayloadBytes":"20971520","consumers.stats.total":"1","stream.approxMaxLength":"1438","stream.length":"1","groups.list.[0]":"Id: photog_train_pmml, Index: 3, Pending: 1, Delivered: 4, Consumers: 1","meta.header.group":"X-EAS-QueueService-Gid","stream.lastEntry":"3","consumers.list.[0]":"Id: photog_train_pmmln.photog-train-pmmln-78550f91-7545766654-jpdtp, Index: 3, Pending: 0, Status: Running, Idle: 2h30m57.08s, Window: 1, Slots: 1, AutoCommit: false","meta.name":"photog-train-pmmln-queue-7a5e7cc6","meta.state":"Normal","meta.header.user":"X-EAS-QueueService-Uid"}
    
    Process finished with exit code 0

    其中:

    • index:表示该请求是EAS中的第几个请求。

    • request_id:表示该请求的ID,后续使用该ID获取输出结果。

    • 其他内容表示获取的队列信息。

  3. 使用以下代码,创建输出队列并订阅读取输出结果数据,以判断模型训练是否成功。

    调用示例如下:

    Python SDK

    # 创建输出队列对象,用于订阅读取输出结果数据。
    sink_queue = QueueClient('182848887922****.cn-shanghai.pai-eas.aliyuncs.com', 'photog_train_pmml/sink')
    sink_queue.set_token('<token>')
    sink_queue.init()
    
    sink_queue.get(request_id, auto_delete=True)[0].data.decode('utf-8')

    其中:

    • sink_queue:配置为已获取的训练服务访问地址。

    • <token>:替换为已获取训练服务的Token。

    Java SDK

    import com.aliyun.openservices.eas.predict.http.HttpConfig;
    import com.aliyun.openservices.eas.predict.http.QueueClient;
    import com.aliyun.openservices.eas.predict.queue_client.DataFrame;
    import com.aliyun.openservices.eas.predict.queue_client.QueueUser;
    import org.apache.commons.lang3.tuple.Pair;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class AsyncPhotoTest {
        public static void main(String[] args) throws Exception {
            /** 创建队列服务客户端 */
            String queueEndpoint = "166233998075****.cn-beijing.pai-eas.aliyuncs.com";
            String inputQueueName = "photog_train_pmml";
            String sinkQueueName = String.format("%s/sink", inputQueueName);
            String queueToken = "N2E2YWI0Y2MyNjZmNjdlMWFmZjNhOTM5M2E5ZGNlMGY1NDQwZGYw****";
    
            QueueClient inputQueue =
                    new QueueClient(queueEndpoint, inputQueueName, queueToken, new HttpConfig(), new QueueUser());
            QueueClient sinkQueue =
                    new QueueClient(queueEndpoint, sinkQueueName, queueToken, new HttpConfig(), new QueueUser());
    
            /** 请求数据 */
            String data = "{\n" +
                    "  \"request_id\": 12345,\n" +
                    "  \"images\": [\"xx.jpg\", \"xx.jpg\"],\n" +
                    "  \"configure\": {\n" +
                    "    \"user_id\": \"zhoumo\"\n" +
                    "  }\n" +
                    "}";
            Pair<Long, String> entry = inputQueue.put(data.getBytes(), null);
            Long index = entry.getKey();
            final String requestId = entry.getValue();
            System.out.println(String.format("index = %d, request id = %s", index, requestId));
    
            // 查看输入队列的详情
            System.out.println(inputQueue.attributes());
    
            // 查看输入数据
            Map<String, String> tags =
                    new HashMap<String, String>() {
                        {
                            put("requestId", requestId);
                        }
                    };
            DataFrame[] dfs = inputQueue.get(0, 1L, 0, false, tags);
            if (dfs.length > 0) {
                System.out.println(String.format("Successfully get data = %s, index = %d, tags = %s", new String(dfs[0].getData()), dfs[0].getIndex(), dfs[0].getTags()));
            } else {
                System.out.println("no data");
            }
    
            // 查看输出数据
            while (true) {
                dfs = sinkQueue.get(0, 1L, 0, true, tags);
                if (dfs.length > 0) {
                    System.out.println(String.format("Successfully get data = %s, tags = %s", new String(dfs[0].getData()), dfs[0].getTags()));
                    break;
                } else {
                    System.out.println("no data");
                }
            }
    
            /** 关闭客户端 */
            inputQueue.shutdown();
            sinkQueue.shutdown();
        }
    }

    其中:

    • queueEndpoint:配置为已获取的训练服务的访问地址。

    • inputQueueName:配置为训练服务的名称。

    • queueToken:替换为已获取的训练服务的Token。

    • images:配置为模型训练使用图片的URL地址。

    系统返回结果如下:

    Python SDK

    '{"request_id": "12345", "code": "OK", "message": "success", "data": {"user_id": "zhoumo", "cost_time": 272.7406361103058}}'
    说明

    当返回结果中的code502时,表示训练正在进行中。

    Java SDK

    ...
    no data
    no data
    Successfully get data = {"request_id": "12345", "code": "OK", "message": "success", "data": {"user_id": "zhoumo", "cost_time": 260.7540729045868}}
    说明

    当返回结果中显示no data时,表示训练正在进行中。

    参数说明如下:

    参数

    描述

    request_id

    请求ID,STRING类型。

    code

    是否已完成训练:

    • OK:表示已完成训练。

    • error:表示未完成训练。

    message

    返回的运行情况详细信息。success表示模型训练成功。

    data

    返回内容详情,内部字段说明如下:

    • user_id:用户ID。

    • cost_time:本次API调用花费的服务端计算时长。

步骤三:调用图像生成接口

  1. 首先您需要在PAI-EAS模型在线服务页面,单击预测服务的服务方式列下的调用信息,在异步调用页签,获取服务访问地址和Token。image.png

  2. 使用如下代码创建输入队列进行图片预测,并获取队列信息。

    调用示例如下:

    Python SDK

    import json
    from eas_prediction import QueueClient
    
    # 创建输入队列对象,用于写入输入数据。
    input_queue = QueueClient('182848887922****.cn-shanghai.pai-eas.aliyuncs.com', 'photog_pre_pmml')
    input_queue.set_token('<token>')
    input_queue.init()
    
    datas = json.dumps({
        'request_id'    : 12345, 
        'template_image': "xx.jpg", 
        'configure'     : { 
            'user_id'   : "zhoumo", # threshold to get tags.
        } 
    })
    
    index, request_id = input_queue.put(f'{datas}')
    print(index, request_id)
    
    # 查看输入队列的详情。
    attrs = input_queue.attributes()
    print(attrs)
    
    # 利用request_id查询某个特定的请求
    print(input_queue.get(request_id, auto_delete=False)[0].data.decode('utf-8'))

    其中关键配置说明如下:

    关键配置

    描述

    默认值

    是否必填

    input_queue

    配置为已获取的预测服务的访问地址,请参考上述代码示例进行配置,STRING类型。

    <token>

    替换为已获取预测服务的Token,STRING类型。

    request_id

    请求ID。STRING类型。

    template_image

    配置为模型训练使用的图片的URL地址。

    configure

    user_id

    用户的ID,STRING类型。

    sex

    训练图片中人物的性别,STRING类型。

    secret

    first_diffusion_steps

    第一次diffusion的步数,INT类型。

    50

    first_denoising_strength

    第一次diffusion的强度,FLOAT类型。

    0.45

    second_diffusion_steps

    第二次diffusion的步数,INT类型。

    20

    second_denoising_strength

    第二次diffusion的强度,FLOAT类型。

    0.30

    more_like_me_before

    第一次人脸融合比例,值越大越像,FLOAT类型。

    0.50

    more_like_me

    第二次人脸融合比例,值越大越像,FLOAT类型。

    0.50

    mask_region

    STRING类型,取值如下:

    • edge:表示第二次diffusion只对边缘重建。

    • face:表示代表第二次diffusion对整个脸部重建。

    edge

    crop_face_preprocess

    是否在裁剪人像区域后进行重建。BOOL类型。

    True

    apply_face_fusion_before

    是否进行第一次脸部融合,BOOL类型。

    True

    apply_face_fusion_after

    是否进行第二次脸部融合,BOOL类型。

    True

    color_shift_middle

    是否进行第一次脸部色彩平衡,BOOL类型。

    True

    color_shift_last

    是否进行第二次脸部色彩平衡,BOOL类型。

    True

    background_restore

    是否对背景进行重建,BOOL类型。

    False

    skin_retouching_bool

    是否进行皮肤平滑,BOOL类型。

    True

    photo_enhancement_bool

    是否进行人像增强,BOOL类型。

    True

    photo_enhancement_method

    人像增强方式,取值如下:

    • photo_fix

    • super_resolution

    photo_fix

    makeup_transfer

    是否进行妆容迁移,BOOL类型。

    False

    makeup_transfer_ratio

    妆容迁移比例,FLOAT类型。

    0.50

    Java SDK

    import com.aliyun.openservices.eas.predict.http.HttpConfig;
    import com.aliyun.openservices.eas.predict.http.QueueClient;
    import com.aliyun.openservices.eas.predict.queue_client.DataFrame;
    import com.aliyun.openservices.eas.predict.queue_client.QueueUser;
    import org.apache.commons.lang3.tuple.Pair;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class AsyncTest {
        public static void main(String[] args) throws Exception {
            /** 创建队列服务客户端 */
            String queueEndpoint = "166233998075****.cn-beijing.pai-eas.aliyuncs.com";
            String inputQueueName = "photog_pre_pmml";
            String queueToken = "NjViMTI2NGQxZWQxYTI1NGE5MGQ1YTQ5Y2Y2MGZjY2VlZTVmNWE1****";
    
            QueueClient inputQueue =
                    new QueueClient(queueEndpoint, inputQueueName, queueToken, new HttpConfig(), new QueueUser());
    
            /** 请求数据 */
            String data = "{\n" +
                    "    'request_id'    : 12345, \n" +
                    "    'template_image': \"xx.jpg\", \n" +
                    "    'configure'     : { \n" +
                    "        'user_id'   : \"zhoumo\",\n" +
                    "    } \n" +
                    "}";
            Pair<Long, String> entry = inputQueue.put(data.getBytes(), null);
            System.out.println(String.format("index = %s, request id = %s", entry.getKey(), entry.getValue()));
    
            // 查看输入队列的详情
            System.out.println(inputQueue.attributes());
    
            // 利用request_id查询某个特定的请求
            final String requestId = entry.getValue();
            Map<String, String> tags =
                    new HashMap<String, String>() {
                        {
                            put("requestId", requestId);
                        }
                    };
            DataFrame df = inputQueue.get(0, 1L, 0, false, tags)[0];
            System.out.println(String.format("Successfully get data = %s, tags = %s", new String(df.getData()), df.getTags()));
    
            /** 关闭客户端 */
            inputQueue.shutdown();
        }
    }

    其中关键配置说明如下:

    关键配置

    描述

    默认值

    是否必填

    queueEndpoint

    配置为已获取的预测服务的访问地址,STRING类型。

    inputQueueName

    配置为预测服务的名称。

    queueToken

    替换为已获取预测服务的Token,STRING类型。

    request_id

    请求ID。STRING类型。

    template_image

    配置为模型训练使用的图片的URL地址。

    configure

    user_id

    用户的ID,STRING类型。

    sex

    训练图片中人物的性别,STRING类型。

    secret

    first_diffusion_steps

    第一次diffusion的步数,INT类型。

    50

    first_denoising_strength

    第一次diffusion的强度,FLOAT类型。

    0.45

    second_diffusion_steps

    第二次diffusion的步数,INT类型。

    20

    second_denoising_strength

    第二次diffusion的强度,FLOAT类型。

    0.30

    more_like_me_before

    第一次人脸融合比例,值越大越像,FLOAT类型。

    0.50

    more_like_me

    第二次人脸融合比例,值越大越像,FLOAT类型。

    0.50

    mask_region

    STRING类型,取值如下:

    • edge:表示第二次diffusion只对边缘重建。

    • face:表示代表第二次diffusion对整个脸部重建。

    edge

    crop_face_preprocess

    是否在裁剪人像区域后进行重建,并开启大图功能。BOOL类型。

    True

    apply_face_fusion_before

    是否进行第一次脸部融合,BOOL类型。

    True

    apply_face_fusion_after

    是否进行第二次脸部融合,BOOL类型。

    True

    color_shift_middle

    是否进行第一次脸部色彩平衡,BOOL类型。

    True

    color_shift_last

    是否进行第二次脸部色彩平衡,BOOL类型。

    True

    background_restore

    是否对背景进行重建,BOOL类型。

    False

    skin_retouching_bool

    是否进行皮肤平滑,BOOL类型。

    True

    photo_enhancement_bool

    是否进行人像增强,BOOL类型。

    True

    photo_enhancement_method

    人像增强方式,取值如下:

    • photo_fix

    • super_resolution

    photo_fix

    makeup_transfer

    是否进行妆容迁移,BOOL类型。

    False

    makeup_transfer_ratio

    妆容迁移比例,FLOAT类型。

    0.50

    系统返回如下结果:

    Python SDK

    1 069173d0-dce9-4ed6-913e-cc5fdda38764
    {'consumers.list.[0]': 'Id: photog_pre_pmml.photog-pre-pmml-835253f3-686f87d4f-d****, Index: 0, Pending: 0, Status: Running, Idle: 21h41m4.995s, Window: 1, Slots: 1, AutoCommit: false', 'consumers.stats.total': '1', 'consumers.status.total': '1', 'groups.list.[0]': 'Id: photog_pre_pmml, Index: 1, Pending: 1, Delivered: 2, Consumers: 1', 'meta.header.group': 'X-EAS-QueueService-Gid', 'meta.header.priority': 'X-EAS-QueueService-Priority', 'meta.header.user': 'X-EAS-QueueService-Uid', 'meta.name': 'photog-pre-pmml-queue-912f2cdb', 'meta.state': 'Normal', 'stream.approxMaxLength': '1439', 'stream.firstEntry': '1', 'stream.lastEntry': '1', 'stream.length': '1', 'stream.maxPayloadBytes': '20971520'}
    {"request_id": 12345, "template_image": "https://xx.oss-cn-beijing.aliyuncs.com/photog/user_images/foto/train/1.jpg", "configure": {"user_id": "zhoumo"}}

    Java SDK

    index = 4, request id = 996cb029-133e-4f18-bb03-e696fc6ae4a1
    {"meta.header.priority":"X-EAS-QueueService-Priority","consumers.status.total":"1","stream.firstEntry":"4","stream.maxPayloadBytes":"20971520","consumers.stats.total":"1","stream.approxMaxLength":"1436","stream.length":"1","groups.list.[0]":"Id: photog_pre_pmml, Index: 4, Pending: 1, Delivered: 5, Consumers: 1","meta.header.group":"X-EAS-QueueService-Gid","stream.lastEntry":"4","consumers.list.[0]":"Id: photog_pre_pmml.photog-pre-pmml-835253f3-686f87d4f-d****, Index: 4, Pending: 0, Status: Running, Idle: 2m12.017s, Window: 1, Slots: 1, AutoCommit: false","meta.name":"photog-pre-pmml-queue-912f2cdb","meta.state":"Normal","meta.header.user":"X-EAS-QueueService-Uid"}
    Successfully get data = {
        'request_id'    : 12345, 
        'template_image': "https://xx.oss-cn-beijing.aliyuncs.com/photog/user_images/foto/train/1.jpg", 
        'configure'     : { 
            'user_id'   : "zhoumo",
        } 
    }, tags = {requestId=996cb029-133e-4f18-bb03-e696fc6ae4a1, ts@source=169778191****}
    
    Process finished with exit code 0

    其中:

    • index:表示该请求是EAS中的第几个请求。

    • request_id:表示该请求的ID,后续使用该ID获取输出结果。

    • 其他内容表示获取的队列信息。

  3. 使用以下代码,创建输出队列并获取返回结果。在返回结果中,您可以查看获取到的Base64编码图片。

    调用示例如下:

    Python SDK

    # 创建输出队列对象,用于订阅读取输出结果数据。
    sink_queue = QueueClient('182848887922****.cn-shanghai.pai-eas.aliyuncs.com', 'photog_pre_pmml/sink')
    sink_queue.set_token('<token>')
    sink_queue.init()
    
    sink_queue.get(request_id, auto_delete=True)[0].data.decode('utf-8')

    其中:

    • sink_queue:配置为已获取的预测服务的访问地址。

    • <token>:替换为已获取的预测服务的Token。

    Java SDK

    import com.aliyun.openservices.eas.predict.http.HttpConfig;
    import com.aliyun.openservices.eas.predict.http.QueueClient;
    import com.aliyun.openservices.eas.predict.queue_client.DataFrame;
    import com.aliyun.openservices.eas.predict.queue_client.QueueUser;
    import org.apache.commons.lang3.tuple.Pair;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class AsyncPhotoTest {
        public static void main(String[] args) throws Exception {
            /** 创建队列服务客户端 */
            String queueEndpoint = "166233998075****.cn-beijing.pai-eas.aliyuncs.com";
            String inputQueueName = "photog_pre_pmml";
            String sinkQueueName = String.format("%s/sink", inputQueueName);
            String queueToken = "NjViMTI2NGQxZWQxYTI1NGE5MGQ1YTQ5Y2Y2MGZjY2VlZTVmNWE1****";
    
            QueueClient inputQueue =
                    new QueueClient(queueEndpoint, inputQueueName, queueToken, new HttpConfig(), new QueueUser());
            QueueClient sinkQueue =
                    new QueueClient(queueEndpoint, sinkQueueName, queueToken, new HttpConfig(), new QueueUser());
    
            /** 请求数据 */
            String data = "{\n" +
                    "  \"request_id\": 12345,\n" +
                    "  \"template_image\": \"xx.jpg\",\n" +
                    "  \"configure\": {\n" +
                    "    \"user_id\": \"zhoumo\"\n" +
                    "  }\n" +
                    "}";
            Pair<Long, String> entry = inputQueue.put(data.getBytes(), null);
            Long index = entry.getKey();
            final String requestId = entry.getValue();
            System.out.println(String.format("index = %d, request id = %s", index, requestId));
    
            // 查看输入队列的详情
            System.out.println(inputQueue.attributes());
    
            // 查看输入数据
            Map<String, String> tags =
                    new HashMap<String, String>() {
                        {
                            put("requestId", requestId);
                        }
                    };
            DataFrame[] dfs = inputQueue.get(0, 1L, 0, false, tags);
            if (dfs.length > 0) {
                System.out.println(String.format("Successfully get data = %s, index = %d, tags = %s", new String(dfs[0].getData()), dfs[0].getIndex(), dfs[0].getTags()));
            } else {
                System.out.println("no data");
            }
    
            // 查看输出数据
            while (true) {
                dfs = sinkQueue.get(0, 1L, 0, true, tags);
                if (dfs.length > 0) {
                    System.out.println(String.format("Successfully get data = %s, tags = %s", new String(dfs[0].getData()), dfs[0].getTags()));
                    break;
                } else {
                    System.out.println("no data");
                }
            }
    
            /** 关闭客户端 */
            inputQueue.shutdown();
            sinkQueue.shutdown();
        }
    }

    其中:

    • queueEndpoint:配置为已获取的预测服务的访问地址。

    • inputQueueName:配置为预测服务的名称。

    • queueToken:替换为已获取的预测服务的Token。

    • template_image:配置为图片的URL地址。

    系统返回如下结果:

    Python SDK

    '{"request_id": "12345", "code": "OK", "message": "success", "data": {"user_id": "zhoumo", "image": "iVBORw*****CYII=", "cost_time": 329.69798278808594}}'
    说明

    当返回结果中的code502时,表示正在生成图片。

    Java SDK

    ...
    no data
    no data
    Successfully get data = {"request_id": "12345", "code": "OK", "message": "success", "data": {"user_id": "zhoumo", "image": "iVBORw0KGgoAAA****ABJRU5ErkJggg==", "cost_time": 21.584840059280396}}
    说明

    当返回结果中显示no data时,表示正在生成图片。

    参数说明如下:

    参数

    描述

    request_id

    请求ID,STRING类型。

    code

    请求状态码:

    • OK:表示请求成功。

    • error:表示请求失败。

    message

    请求状态的详细信息。如果返回结果为success表示执行成功,对于其他返回结果,请根据具体的返回内容来确定。

    data

    返回内容详情。内部字段说明如下:

    • user_id:用户ID。

    • image:生成的Base64编码图片。

    • cost_time:消耗的时间,FLOAT类型。