全部产品
Search
文档中心

人工智能平台 PAI:5分钟使用EAS部署Stable Diffusion API服务

更新时间:Apr 07, 2024

Stable Diffusion(SD) API服务支持同步和异步两种部署模式。服务部署成功后,您可以发送同步或异步接口请求,并根据请求结果验证模型效果。本文为您介绍如何通过EAS以同步或异步的方式部署和调用SD API服务,以及额外支持的API可选参数。

前提条件

部署同步服务

支持以下两种部署方式,您可以根据使用场景选择合适的部署方式。初次部署时,推荐使用方式一。

部署方式一:控制台一键部署

  1. 进入PAI-EAS 模型在线服务页面。

    1. 登录PAI控制台

    2. 在左侧导航栏单击工作空间列表,在工作空间列表页面中单击待操作的工作空间名称,进入对应工作空间内。

    3. 在工作空间页面的左侧导航栏选择模型部署>模型在线服务(EAS),进入PAI-EAS 模型在线服务页面。image.png

  2. PAI-EAS 模型在线服务页面,单击部署服务,在自定义部署区域中,单击立刻部署

  3. 部署服务页面,配置以下关键参数。

    参数

    描述

    服务名称

    自定义服务名称。本案例使用的示例值为:sdapi_demo

    部署方式

    选择镜像部署服务

    镜像选择

    PAI平台镜像列表中选择stable-diffusion-webui;镜像版本选择3.2

    说明

    由于版本迭代迅速,部署时镜像版本选择最高版本即可。

    模型配置

    单击填写模型配置,进行模型配置。

    • 建议同时配置OSS挂载和NAS挂载。其中OSS路径用来存放生成的图片,NAS路径用来存放模型。

    • 您也可以单独使用OSS挂载或NAS挂载。

      • 当选择NAS挂载时,切换模型和出图速度更快。

      • 当选择OSS挂载时,OSS上传文件更方便,但是切换模型和出图速度比NAS慢很多。

    同时配置OSS挂载和NAS挂载时,配置方法如下:

    • OSS挂载

      • 将OSS路径配置为已创建的OSS Bucket路径。

      • 挂载路径配置为:/code/stable-diffusion-webui/data-oss

    • NAS挂载

      • NAS挂载点:选择已创建的NAS文件系统和挂载点。

      • NAS源路径:配置为/

      • 挂载路径:配置为/code/stable-diffusion-webui/data-nas

    运行命令

    将运行命令更新为以下配置:./webui.sh --listen --port=8000 --skip-version-check --no-hashing --no-download-sd-model --skip-install --api --filebrowser --data-dir data-nas

    端口号:配置为8000。

    资源组种类

    选择公共资源组

    资源配置方法

    选择常规资源配置

    资源配置选择

    选择GPU类型,实例规格推荐使用ml.gu7i.c16m60.1-gu30(性价比最高)。

    专有网络配置

    系统会自动匹配与NAS所在VPC相连通的专有网络,无需进行额外的修改。

  4. 单击部署,持续时间大约为5分钟,即可完成模型部署。

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

部署方式二:JSON独立部署

  1. 按照部署方式一的操作步骤,打开部署服务页面。

  2. 对应配置编辑区域单击JSON独立部署,然后在编辑框中配置以下内容。

    {
        "metadata": {
            "instance": 1,
            "name": "sd_v32",
        },
        "containers": [
            {
                "image": "eas-registry-vpc.<region>.cr.aliyuncs.com/pai-eas/stable-diffusion-webui:3.2",
                "script": "./webui.sh --listen --port=8000 --skip-version-check --no-hashing --no-download-sd-model --skip-install --api --filebrowser --data-dir data-nas",
                "port": 8000
            }
        ],
        "cloud": {
            "computing": {
                "instance_type": "ml.gu7i.c16m60.1-gu30",
                "instances": null
            },
            "networking": {
                "vpc_id": "vpc-t4nmd6nebhlwwexk2****",
                "vswitch_id": "vsw-t4nfue2s10q2i0ae3****",
                "security_group_id": "sg-t4n85ksesuiq3wez****"
            }
        },
        "storage": [
            {
                "oss": {
                    "path": "oss://examplebucket/data-oss",
                    "readOnly": false
                },
                "properties": {
                    "resource_type": "model"
                },
                "mount_path": "/code/stable-diffusion-webui/data-oss"
            },
            {
                "nfs": {
                    "path": "/",
                    "server": "726434****-aws0.ap-southeast-1.nas.aliyuncs.com"
                },
                "properties": {
                    "resource_type": "model"
                },
                "mount_path": "/code/stable-diffusion-webui/data-nas"
            }
        ]
    } 

    其中:

    • metadata.name:自定义模型服务名称。

    • containers.image:其中<region>需要替换为当前地域ID。关于如何查询地域ID,请参见地域和可用区

    • cloud.networking:配置专有网络,包括vpc_id(专有网络ID)、vswitch_id(交换机ID)和security_group_id(安全组ID),且配置的专有网络需要与通用型NAS文件系统一致。

    • storage.oss.path:配置为已创建的OSS Bucket路径。

    • storage.nfs.server:配置为已创建的NAS文件系统。

  3. 单击部署,持续时间大约为5分钟,即可完成模型部署。

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

调用同步服务

同步服务部署成功后,您可以参照以下操作步骤发送同步接口请求。

  1. 查询调用信息。

    服务部署成功后,单击服务方式列下的调用信息,在调用信息对话框中的公网地址调用页签查询服务访问地址和Token。image.png

  2. 使用以下几种方式发送同步接口请求。

    使用curl命令发送服务请求

    示例如下:

    curl --location --request POST '<service_url>/sdapi/v1/txt2img' \
    --header 'Authorization: <token>' \
    --header 'Content-Type: application/json' \
    --data-raw '{
      "prompt":"cut dog ",
      "steps":20
    }'

    其中:

    • <service_url>:替换为步骤1中查询到的服务访问地址。

    • <token>:替换为步骤1中查询到的服务Token。

    命令执行成功后,系统会返回图片的Base64位编码。

    使用Python发送服务请求

    参考API发送服务请求。

    • 示例1:使用如下Python代码发送服务请求,返回图片文件。

      import requests
      import io
      import base64
      from PIL import Image, PngImagePlugin
      
      url = "<service_url>"
      
      payload = {
          "prompt": "puppy dog",
          "steps": 20,
          "n_iter": 2
      }
      
      session = requests.session()
      session.headers.update({"Authorization": "<token>"})
      
      
      response = session.post(url=f'{url}/sdapi/v1/txt2img', json=payload)
      if response.status_code != 200:
          raise Exception(response.content)
      
      data = response.json()
      
      # 同步接口可直接返回图片的base64,但推荐使用返回图片地址。
      for idx, im in enumerate(data['images']):
          image = Image.open(io.BytesIO(base64.b64decode(im.split(",", 1)[0])))
      
          png_payload = {
              "image": "data:image/png;base64," + im
          }
          resp = session.post(url=f'{url}/sdapi/v1/png-info', json=png_payload)
      
          pnginfo = PngImagePlugin.PngInfo()
          pnginfo.add_text("parameters", resp.json().get("info"))
          image.save(f'output-{idx}.png', pnginfo=pnginfo)
      

      其中:

      • <service_url>:替换为步骤1中查询到的服务访问地址。

      • <token>:替换为步骤1中查询到的服务Token。

      代码执行成功后,系统会在当前所在目录返回图片文件。

    • 示例二:使用如下Python代码发送服务请求,返回图片地址。

      import requests
      import oss2
      
      url = "<service_url>"
      # 对应部署EAS服务时,storage挂载OSS文件夹对应的mount_path。
      mount_path = "/code/stable-diffusion-webui/data-oss"
      # 对应部署EAS服务时,storage中选择的OSS地址。
      oss_url = "oss://examplebucket/data-oss"
      
      # 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
      auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>')
      # Endpoint以杭州为例,其它Region请按实际情况填写。
      bucket = oss2.Bucket(auth, '<endpoint>', '<examplebucket>')
      
      
      payload = {
          "alwayson_scripts": {
              "sd_model_checkpoint": "deliberate_v2.safetensors",
              "save_dir": "/code/stable-diffusion-webui/data-oss/outputs"
          },
          "steps": 30,
          "prompt": "girls",
          "batch_size": 1,
          "n_iter": 2,
          "width": 576,
          "height": 576,
          "negative_prompt": "ugly, out of frame"
      }
      
      
      session = requests.session()
      session.headers.update({"Authorization": "<token>"})
      
      
      response = session.post(url=f'{url}/sdapi/v1/txt2img', json=payload)
      if response.status_code != 200:
          raise Exception(response.content)
      
      data = response.json()
      
      for idx, path in enumerate(data['parameters']['image_url'].split(',')):
          url = path.replace(mount_path, oss_url)
          print(idx, path, url)
      
          # 下载OSS文件到本地文件。
          bucket.get_object_to_file(url[len("oss://<examplebucket>/"):], f'output-{idx}.png')
      

      其中:

      • <service_url>:替换为步骤1中查询到的服务访问地址。

      • <token>:替换为步骤1中查询到的服务Token。

      • auth:将<yourAccessKeyId><yourAccessKeySecret>替换为阿里云账户的AccessKey ID和AccessKey Secret。

      • <endpoint>:表示OSS对外服务的访问域名,例如华东1(杭州)配置为http://oss-cn-hangzhou.aliyuncs.com。更多详细内容,请参见访问域名和数据中心

      • <examplebucket>:替换为已创建的OSS Bucket名称。

      代码执行成功后,系统返回如下结果。您可以前往OSS控制台,在部署服务时配置的OSS路径中查看已生成的图片。

      0 /code/stable-diffusion-webui/data-oss/outputs/txt2img-grids/2023-08-03/grid-b2565642-8ec0-4250-aa9e-f8402e7b87f7.png oss://examplebucket/aohai-singapore/outputs/txt2img-grids/2023-08-03/grid-b2565642-8ec0-4250-aa9e-f8402e7b87f7.png
      1 /code/stable-diffusion-webui/data-oss/outputs/txt2img-images/2023-08-03/dc380f1f-efa0-4681-9b1a-298e2513b929-4084873146.png oss://examplebucket/aohai-singapore/outputs/txt2img-images/2023-08-03/dc380f1f-efa0-4681-9b1a-298e2513b929-4084873146.png
      2 /code/stable-diffusion-webui/data-oss/outputs/txt2img-images/2023-08-03/3df9fd96-7c5a-487a-8e43-24f87c042806-4084873147.png oss://examplebucket/aohai-singapore/outputs/txt2img-images/2023-08-03/3df9fd96-7c5a-487a-8e43-24f87c042806-4084873147.png

    此外,您还可以在请求数据中使用Lora和Controlnet数据格式,以实现特定的功能。

    请求数据中使用Lora模型配置

    发送服务请求时,您可以直接在请求体上加入<lora:yaeMikoRealistic_Genshin:1000>来增加Lora。更多详细内容,请参见Lora

    请求体配置示例如下:

    {
      "prompt":"girls <lora:yaeMikoRealistic_Genshin:1>",
      "steps":20,
      "save_images":true
    }

    请求数据中使用Controlnet数据格式

    API请求数据中使用Controlnet数据格式可以方便地对图像进行一些常见的变换操作,比如使图像保持水平或垂直等。具体配置方法,请参见txt2img使用controlnet的数据格式

此外,EAS基于原生SDWebUI接口支持了一些新特性,您可以在请求数据中添加一些可选参数用于实现更加丰富的功能或定制化需求。具体操作,请参见API额外支持的参数

部署异步服务

为了解决大量请求导致的排队等待问题,EAS内置了队列服务可以协助您管理大量请求。您可以使用异步调用方式推送请求,并订阅相关结果,以获得更高效的请求处理体验。部署异步服务的具体操作步骤如下:

  1. 进入部署服务页面,具体操作,请参见部署同步服务

  2. 对应配置编辑区域单击JSON独立部署,然后在编辑框中配置以下内容。更多关于队列服务的配置详情,请参见部署异步推理服务

    {
        "metadata": {
            "name": "sd_async",
            "instance": 1,
            "rpc.work_threads": 1,
            "type": "Async"
        },
        "cloud": {
            "computing": {
                "instance_type": "ml.gu7i.c16m60.1-gu30",
                "instances": null
            },
            "networking": {
                "vpc_id": "vpc-bp1t2wukzskw9139n****",
                "vswitch_id": "vsw-bp12utkudylvp4c70****",
                "security_group_id": "sg-bp11nqxfd0iq6v5g****"
            }
        },
        "queue": {
            "cpu": 1,
            "max_delivery": 1,
            "memory": 4000,
            "resource": ""
        },
        "storage": [
            {
                "oss": {
                    "path": "oss://examplebucket/aohai-singapore/",
                    "readOnly": false
                },
                "properties": {
                    "resource_type": "model"
                },
                "mount_path": "/code/stable-diffusion-webui/data-oss"
            },
            {
                "nfs": {
                    "path": "/",
                    "server": "0c9624****-fgh60.cn-hangzhou.nas.aliyuncs.com"
                },
                "properties": {
                    "resource_type": "model"
                },
                "mount_path": "/code/stable-diffusion-webui/data-nas"
            }
        ],
        "containers": [
            {
                "image": "eas-registry-vpc.cn-hangzhou.cr.aliyuncs.com/pai-eas/stable-diffusion-webui:3.2",
                "script": "./webui.sh --listen --port 8000 --skip-version-check --no-hashing --no-download-sd-model --skip-install --api --nowebui --time-log",
                "port": 8000
            }
        ]
    } 

    相较于同步服务的部署,以下是异步服务的配置变更。更多关于关键参数的配置详情,请参见部署方式二:JSON独立部署

    • 删除以下参数:

      • metadata.enable_webservice

      • 删除containers.script中配置的--filebrowser,加快服务启动速度。

    • 新增以下参数:

      • metadata.type:配置为Async。

      • metadata.rpc.work_threads:配置为1,单个实例只允许并发处理一个请求。

      • queue.max_delivery:配置为1,消息处理错误后不允许重试。

      • containers.script配置中新增--nowebui(加快启动速度)和--time-log(记录接口响应时间)。

  3. 单击部署,等待一段时间即可完成模型部署。

调用异步服务

异步服务部署成功后,您可以根据实际需求选择发送同步接口请求或异步接口请求。发送同步接口请求时,客户端会同步等待结果返回。发送异步接口请求时,客户端不再同步等待结果,通过订阅的方式在请求计算完成后等待服务端的结果推送。关于发送同步接口请求和异步接口请求的更多内容,请参见部署异步推理服务

发送异步接口请求并订阅结果

  1. 查询调用信息。

    服务部署成功后,单击服务方式列下的调用信息,在调用信息对话框中的异步调用页签,在公网输入请求地址页签查询服务访问地址和Token。image.png

  2. 异步推送请求。

    说明
    • 异步队列对输入请求和输出结果的大小都有限制,通常不建议超过8 KB。因此,在发送请求时,需要满足以下两个条件:

      • 如果请求数据中包含图片,建议使用URL来传递图片信息。SDWebUI内部会自动下载并解析这些图片数据。

      • 为了确保返回结果中没有原始图片数据,建议您使用save_dir来指定生成图片的保存路径。具体操作,请参见API额外支持的参数

    • 默认情况下,EAS无法连接互联网。如果您使用image_link参数配置的图片链接是互联网图片地址,为了能够正常访问这些图片,您需要参考配置网络连通公网连接及白名单配置进行公网链接配置。

    使用Python SDK

    示例代码如下:

    import requests
    
    url = "<service_url>"
    session = requests.session()
    session.headers.update({"Authorization": "<token>"})
    
    prompts = ["cute dog", "cute cat", "cute girl"]
    
    for i in range(5):
        p = prompts[i % len(prompts)]
        payload = {
            "prompt": p,
            "steps": 20,
            "alwayson_scripts": {
                "save_dir": "/code/stable-diffusion-webui/data-oss/outputs/txt2img"
            },
        }
        response = session.post(url=f'{url}/sdapi/v1/txt2img?task_id=txt2img_{i}', json=payload)
        if response.status_code != 200:
            exit(f"send request error:{response.content}")
        else:
            print(f"send {p} success, index is {response.content}")
    
    
    for i in range(5):
        p = prompts[i % len(prompts)]
        payload = {
            "prompt": p,
            "steps": 20,
            "alwayson_scripts": {
                "save_dir": "/code/stable-diffusion-webui/data-oss/outputs/img2img",
                "image_link": "https://eas-cache-cn-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/stable-diffusion-cache/tests/boy.png",
            },
        }
        response = session.post(url=f'{url}/sdapi/v1/img2img?task_id=img2img_{i}', json=payload)
        if response.status_code != 200:
            exit(f"send request error:{response.content}")
        else:
            print(f"send {p} success, index is {response.content}")
    

    其中:

    • <service_url>:替换为步骤1中查询到的服务访问地址。

    • <token>:替换为步骤1中查询到的服务Token。

    说明
    • 可以支持WebUI服务的所有POST接口,按照需求请求对应路径。

    • 如果您需要在该服务中透传业务属性,可以使用url参数的方式指定属性标签。例如,您可以在response的url参数中添加参数?task_id=task_abc来指定标签为task_id,并且该信息会在服务的输出结果中的tags字段中体现。

    代码执行成功后,系统输出如下结果。您的结果以实际为准。image.png

    使用Java SDK

    示例代码如下。使用Java编写客户端代码时,需要使用Maven管理项目。因此,您必须在pom.xml文件中添加客户端所需的依赖包。具体操作,请参见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;
    
    import java.util.HashMap;
    
    public class SDWebuiAsyncPutTest {
        public static void main(String[] args) throws Exception {
            // 创建队列服务客户端。
            String queueEndpoint = "http://166233998075****.cn-hangzhou.pai-eas.aliyuncs.com";
            String queueToken = "xxxxx==";
            // 输入队列为服务名+自定义请求path。
            String inputQueueName = "<service_name>/sdapi/v1/txt2img";
    
            // 输入队列,往输入队列添加数据,推理服务会自动从输入队列中读取请求数据。
            QueueClient inputQueue =
                new QueueClient(queueEndpoint, inputQueueName, queueToken, new HttpConfig(), new QueueUser());
            // 清除队列数据!!! 请谨慎使用。
            // input_queue.clear();
    
            // 往输入队列添加数据。
            int count = 5;
            for (int i = 0; i < count; ++i) {
                // 请求数据。
                String data = "{\n" +
                    "    \"prompt\": \"cute dog\", \n" +
                    "    \"steps\":20,\n" +
                    "    \"alwayson_scripts\":{\n" +
                    "        \"save_dir\":\"/code/stable-diffusion-webui/data-oss/outputs/txt2img\"\n" +
                    "    }\n" +
                    "  }";
                // 自定义tag。
                HashMap<String, String> map = new HashMap<String, String>(1);
                map.put("task_id", "txt2img_" + i);
                Pair<Long, String> entry = inputQueue.put(data.getBytes(), map);
    
                System.out.println(String.format("send success, index is %d, request_id is %s", entry.getKey(), entry.getValue()));
                // 队列服务支持多优先级队列,可通过put函数设置数据优先级,默认优先级为0, 高优先数据可设置优先级为1。
                //  inputQueue.put(data.getBytes(), 0L, null);
            }
            // 关闭客户端。
            inputQueue.shutdown();
    
    
            inputQueueName = "<service_name>/sdapi/v1/img2img";
            inputQueue =
                new QueueClient(queueEndpoint, inputQueueName, queueToken, new HttpConfig(), new QueueUser());
            for (int i = 0; i < count; ++i) {
                // 请求数据。
                String data = "{\n" +
                    "    \"prompt\": \"cute dog\", \n" +
                    "    \"steps\":20,\n" +
                    "    \"alwayson_scripts\":{\n" +
                    "        \"save_dir\":\"/code/stable-diffusion-webui/data-oss/outputs/img2img\",\n" +
                    "        \"image_link\":\"https://eas-cache-cn-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/stable-diffusion-cache/tests/boy.png\"\n" +
                    "    }\n" +
                    "  }";
                HashMap<String, String> map = new HashMap<String, String>(1);
                map.put("task_id", "img2img_" + i);
                Pair<Long, String> entry = inputQueue.put(data.getBytes(), map);
    
                System.out.println(String.format("send success, index is %d, requestId is %s", entry.getKey(), entry.getValue()));
            }
    
            // 关闭客户端。
            inputQueue.shutdown();
        }
    }

    其中:

    • queueEndpoint:配置为步骤1中获取的服务访问地址。请参考示例代码进行相应的配置。

    • queueToken:配置为步骤1中获取的服务Token信息。

    • <service_name>:替换为已部署的异步服务名称。

    说明

    如果您需要在服务中透传业务属性,可以在put函数中设置tag参数。在示例中,您可以参考自定义tag的用法。这些信息会在输出结果的tags属性中体现。

    代码执行成功后,系统输出如下结果。您的结果以实际为准。

    send success, index is 21, request_id is 05ca7786-c24e-4645-8538-83d235e791fe
    send success, index is 22, request_id is 639b257a-7902-448d-afd5-f2641ab77025
    send success, index is 23, request_id is d6b2e127-eba3-4414-8e6c-c3690e0a487c
    send success, index is 24, request_id is 8becf191-962d-4177-8a11-7e4a450e36a7
    send success, index is 25, request_id is 862b2d8e-5499-4476-b3a5-943d18614fc5
    send success, index is 26, requestId is 9774a4ff-f4c8-40b7-ba43-0b1c1d3241b0
    send success, index is 27, requestId is fa536d7a-7799-43f1-947f-71973bf7b221
    send success, index is 28, requestId is e69bdd32-5c7b-4c8f-ba3e-e69d2054bf65
    send success, index is 29, requestId is c138bd8f-be45-4a47-a330-745fd1569534
    send success, index is 30, requestId is c583d4f8-8558-4c8d-95f7-9c3981494007
    
    Process finished with exit code 0
  3. 异步订阅结果。

    使用Python SDK

    示例代码如下:

    import json
    import oss2
    
    from eas_prediction import QueueClient
    
    sink_queue = QueueClient('139699392458****.cn-hangzhou.pai-eas.aliyuncs.com', 'sd_async/sink')
    sink_queue.set_token('<token>')
    sink_queue.init()
    
    mount_path = "/code/stable-diffusion-webui/data-oss"
    oss_url = "oss://<examplebucket>/aohai-singapore"
    # 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
    auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>')
    # Endpoint以杭州为例,其它Region请按实际情况填写。
    bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<examplebucket>')
    
    
    watcher = sink_queue.watch(0, 5, auto_commit=False)
    for x in watcher.run():
        if 'task_id' in x.tags:
            print('index {} task_id is {}'.format(x.index, x.tags['task_id']))
        print(f'index {x.index} data is {x.data}')
        sink_queue.commit(x.index)
        try:
            data = json.loads(x.data.decode('utf-8'))
            for idx, path in enumerate(data['parameters']['image_url'].split(',')):
                url = path.replace(mount_path, oss_url)
                # 下载OSS文件到本地文件。
                bucket.get_object_to_file(url[len("oss://<examplebucket>/"):], f'{x.index}-output-{idx}.png')
                print(f'save {url} to {x.index}-output-{idx}.png')
        except Exception as e:
            print(f'index {x.index} process data error {e}')
    

    其中:

    • sink_queue:您需要更新该参数配置的服务访问地址和名称。如何查询服务访问地址,请参见查询调用信息。请参考示例代码进行相应的配置。

    • <token>:配置为步骤1中获取的服务Token信息。

    • oss_url:替换为部署服务时配置的OSS路径。

    • <examplebucket>:替换为已创建的OSS Bucket名称。

    • bucket:本方案以杭州地域为例配置了Endpoint,如果您在其他地域部署的服务,需要根据实际情况进行配置。更多详细内容,请参见访问域名和数据中心

    说明
    • 需要主动进行commit操作,也可以设置auto_commit=True来自动进行commit操作。

    • 如果consumer不再消费数据,需要及时关闭以释放资源。

    • 您也可以使用curl命令或者调用同步接口来获取订阅接口,详情请参见部署异步推理服务

    代码执行成功后,系统输出如下结果。您的结果以实际为准。您可以前往OSS控制台,在部署服务时配置的OSS路径中查看已生成的图片。

    index 1 task_id is txt2img_0
    index 1 data is b'{"images":[],"parameters":{"id_task":null,"status":0,"image_url":"/code/stable-diffusion-webui/data-oss/outputs/txt2img/txt2img-images/2023-08-16/ad2e270b-dfcc-4ec3-8718-f19824857834-919429454.png","seed":"919429454","error_msg":"","total_time":88.55384421348572},"info":""}'
    save oss://<examplebucket>/aohai-singapore/outputs/txt2img/txt2img-images/2023-08-16/ad2e270b-dfcc-4ec3-8718-f19824857834-919429454.png to 1-output-0.png
    index 2 task_id is txt2img_1
    index 2 data is b'{"images":[],"parameters":{"id_task":null,"status":0,"image_url":"/code/stable-diffusion-webui/data-oss/outputs/txt2img/txt2img-images/2023-08-16/374ceae2-deb5-4448-b213-cfdb11a53892-3273662200.png","seed":"3273662200","error_msg":"","total_time":2.76196551322937},"info":""}'
    save oss://<examplebucket>/aohai-singapore/outputs/txt2img/txt2img-images/2023-08-16/374ceae2-deb5-4448-b213-cfdb11a53892-3273662200.png to 2-output-0.png
    index 3 task_id is txt2img_2
    index 3 data is b'{"images":[],"parameters":{"id_task":null,"status":0,"image_url":"/code/stable-diffusion-webui/data-oss/outputs/txt2img/txt2img-images/2023-08-16/a37a0384-2ed4-42f9-9166-fe0fd80c624c-210444956.png","seed":"210444956","error_msg":"","total_time":2.7492804527282715},"info":""}'
    save oss://<examplebucket>/aohai-singapore/outputs/txt2img/txt2img-images/2023-08-16/a37a0384-2ed4-42f9-9166-fe0fd80c624c-210444956.png to 3-output-0.png
    index 4 task_id is txt2img_3
    index 4 data is b'{"images":[],"parameters":{"id_task":null,"status":0,"image_url":"/code/stable-diffusion-webui/data-oss/outputs/txt2img/txt2img-images/2023-08-16/482dcc64-4848-48f8-b9fd-7f0d3992f1ae-198191449.png","seed":"198191449","error_msg":"","total_time":2.8161191940307617},"info":""}'
    save oss://<examplebucket>/aohai-singapore/outputs/txt2img/txt2img-images/2023-08-16/482dcc64-4848-48f8-b9fd-7f0d3992f1ae-198191449.png to 4-output-0.png

    使用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 com.aliyun.openservices.eas.predict.queue_client.WebSocketWatcher;
    
    public class SDWebuiAsyncWatchTest {
        public static void main(String[] args) throws Exception {
            // 创建队列服务客户端。
            String queueEndpoint = "http://166233998075****.cn-hangzhou.pai-eas.aliyuncs.com";
            String queueToken = "xxxxx==";
            // 输出队列名为 服务名+"/sink"。
            String sinkQueueName = "<service_name>/sink";
    
            // 输出队列,推理服务处理输入数据后会将结果写入输出队列。
            QueueClient sinkQueue =
                new QueueClient(queueEndpoint, sinkQueueName, queueToken, new HttpConfig(), new QueueUser());
    
            // 清除队列数据!!! 请谨慎使用。
            //  sinkQueue.clear();
    
            // 订阅队列,获取队列数据。
            WebSocketWatcher watcher = sinkQueue.watch(0L, 5L, false, false, null);
            try {
                while (true) {
                    DataFrame df = watcher.getDataFrame();
                    if (df.getTags().containsKey("task_id")) {
                        System.out.println(String.format("task_id = %s", df.getTags().get("task_id")));
                    }
                    System.out.println(String.format("index = %d, data = %s, requestId = %s", df.getIndex(), new String(df.getData()), df.getTags().get("requestId")));
                    sinkQueue.commit(df.getIndex());
                }
            } catch (Exception e) {
                System.out.println("watch error:" + e.getMessage());
                e.printStackTrace();
                watcher.close();
            }
    
            // 关闭客户端。
            sinkQueue.shutdown();
        }
    }

    其中:

    • queueEndpoint:配置为步骤1中获取的服务访问地址。请参考示例代码进行相应的配置。

    • queueToken:配置为步骤1中获取的服务Token信息。

    • <service_name>:替换为已部署的异步服务名称。

    说明
    • 需要主动进行commit操作,也可以设置auto_commit=True来自动进行commit操作。

    • 如果consumer不再消费数据,需要及时关闭以释放资源。

    • 您也可以使用curl命令或者调用同步接口来获取订阅接口,详情请参见部署异步推理服务

    代码执行成功后,系统输出如下结果。您的结果以实际为准。您可以前往OSS控制台对应的路径下查看已生成的图片。

    2023-08-04 16:17:31,497 INFO [com.aliyun.openservices.eas.predict.queue_client.WebSocketWatcher] - WebSocketClient Successfully Connects to Server: 1396993924585947.cn-hangzhou.pai-eas.aliyuncs.com/116.62.4.210:80
    task_id = txt2img_0
    index = 21, data = {"images":[],"parameters":{"id_task":null,"status":0,"image_url":"/code/stable-diffusion-webui/data-oss/outputs/txt2img/txt2img-images/2023-08-04/54363a9d-24a5-41b5-b038-2257d43b8e79-412510031.png","seed":"412510031","error_msg":"","total_time":2.5351321697235107},"info":""}, requestId = 05ca7786-c24e-4645-8538-83d235e791fe
    task_id = txt2img_1
    index = 22, data = {"images":[],"parameters":{"id_task":null,"status":0,"image_url":"/code/stable-diffusion-webui/data-oss/outputs/txt2img/txt2img-images/2023-08-04/0c646dda-4a53-43f4-97fd-1f507599f6ae-2287341785.png","seed":"2287341785","error_msg":"","total_time":2.6269655227661133},"info":""}, requestId = 639b257a-7902-448d-afd5-f2641ab77025
    task_id = txt2img_2
    index = 23, data = {"images":[],"parameters":{"id_task":null,"status":0,"image_url":"/code/stable-diffusion-webui/data-oss/outputs/txt2img/txt2img-images/2023-08-04/4d542f25-b9cc-4548-9db2-5addd0366d32-1158414078.png","seed":"1158414078","error_msg":"","total_time":2.6604185104370117},"info":""}, requestId = d6b2e127-eba3-4414-8e6c-c3690e0a487c
    task_id = txt2img_3

发送同步接口请求

部署异步服务后,仍然支持使用指定服务名称的方式同步请求WebUI接口。您可以使用curl命令或Python客户端请求WebUI服务来验证模型效果和服务可用性。具体操作步骤如下:

  1. 查询调用信息。

    服务部署成功后,单击服务方式列下的调用信息,在调用信息对话框中的同步调用页签,在公网地址调用页签查询服务访问地址和Token。image.png

  2. 使用curl命令发送服务请求。示例如下:

    curl -v --location '<service_url>/sdapi/v1/sd-models' \
    --header 'Authorization: <service_token>' 

    其中:

    • <service_url>:替换为步骤1中查询到的服务访问地址。

    • <token>:替换为步骤1中查询到的服务Token。

    命令执行成功后,返回当前服务支持的模型列表。

EAS基于原生SDWebUI接口支持了一些新特性,您可以在请求数据中添加一些可选参数用于实现更加丰富的功能或定制化需求。具体操作,请参见API额外支持的参数

API额外支持的参数

EAS基于原生SDWebUI接口支持了一些新特性,在API接口中除了必填参数以外,还可以添加一些可选参数用于实现更加丰富的功能或定制化需求:

  • 可以指定SD模型、VAE模型以及保存目录。

  • 支持通过URL输入参数,并返回相应的状态码。

  • 生成的图片和ControlNet所对应的图片可以通过URL进行访问。

具体使用示例如下:

txt2img请求和返回示例

请求数据格式示例如下:

{
      "alwayson_scripts": {
          "sd_model_checkpoint": "deliberate_v2.safetensors",  
          "save_dir": "/code/stable-diffusion-webui/data-oss/outputs",
          "sd_vae": "Automatic"
      },
      "steps": 20,
      "prompt": "girls",          
      "batch_size": 1,                                            
      "n_iter": 2,                                                 
      "width": 576, 
      "height": 576,
      "negative_prompt": "ugly, out of frame"
  }

其中关键参数说明如下:

  • sd_model_checkpoint:指定SD模型参数,并且可以自动切换到大模型。

  • sd_vae:指定VAE模型。

  • save_dir:指定生成图片的保存路径。

发送同步接口请求示例如下:

#验证同步接口,获取服务调用入口。

curl --location --request POST '<service_url>/sdapi/v1/txt2img' \
--header 'Authorization: <token>' \
--header 'Content-Type: application/json' \
--data-raw '{
      "alwayson_scripts": {
          "sd_model_checkpoint": "deliberate_v2.safetensors",
          "save_dir": "/code/stable-diffusion-webui/data-oss/outputs",
          "sd_vae": "Automatic"
      },
      "prompt": "girls",          
      "batch_size": 1,                                            
      "n_iter": 2,                                                 
      "width": 576, 
      "height": 576,
      "negative_prompt": "ugly, out of frame"
  }'

返回数据格式示例如下:

{
  "images": [],
  "parameters": {
    "id_task": "14837",
    "status": 0,
    "image_url": "/code/stable-diffusion-webui/data-oss/outputs/txt2img-grids/2023-07-24/grid-29a67c1c-099a-4d00-8ff3-1ebe6e64931a.png,/code/stable-diffusion-webui/data-oss/outputs/txt2img-images/2023-07-24/74626268-6c81-45ff-90b7-faba579dc309-1146644551.png,/code/stable-diffusion-webui/data-oss/outputs/txt2img-images/2023-07-24/6a233060-e197-4169-86ab-1c18adf04e3f-1146644552.png",
    "seed": "1146644551,1146644552",
    "error_msg": "",
    "total_time": 32.22393465042114
  },
  "info": ""
}

发送异步接口请求示例如下:

# 将数据直接送入异步队列。
curl --location --request POST '<service_url>/sdapi/v1/txt2img' \
--header 'Authorization: <token>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "alwayson_scripts": {
        "sd_model_checkpoint": "deliberate_v2.safetensors",
        "id_task": "14837",
        "uid": "123",
        "save_dir": "tmp/outputs"
    },
    "prompt": "girls",
    "batch_size": 1,
    "n_iter": 2,
    "width": 576,
    "height": 576,
    "negative_prompt": "ugly, out of frame"
}'

img2img请求数据格式示例

请求数据格式示例如下:

{
    "alwayson_scripts": {
        "image_link":"https://eas-cache-cn-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/stable-diffusion-cache/tests/boy.png",
        "sd_model_checkpoint": "deliberate_v2.safetensors",
        "sd_vae": "Automatic",
        "save_dir": "/code/stable-diffusion-webui/data-oss/outputs"
    },
    "prompt": "girl",
    "batch_size": 1,                                            
    "n_iter": 2,                                                 
    "width": 576, 
    "height": 576,
    "negative_prompt": "ugly, out of frame",
    "steps": 20, # Sampling steps
    "seed": 111,   
    "subseed": 111, # Variation seed
    "subseed_strength": 0, # Variation strength
    "seed_resize_from_h": 0, # Resize seed from height
    "seed_resize_from_w": 0, # Resize seed from width
    "seed_enable_extras": false, # Extra
    "sampler_name": "DDIM", # Sampling method
    "cfg_scale": 7.5, # CFG Scale
    "restore_faces": true, # Restore faces
    "tiling": false, # Tiling
    "init_images": [], # image base64 str, default None
    "mask_blur": 4, # Mask blur
    "resize_mode": 1, # 0 just resize, 1 crop and resize, 2 resize and fill, 3 just resize
    "denoising_strength": 0.75, # Denoising strength
    "inpainting_mask_invert": 0, #int, index of ['Inpaint masked', 'Inpaint not masked'], Mask mode
    "inpainting_fill": 0, #index of ['fill', 'original', 'latent noise', 'latent nothing'], Masked content
    "inpaint_full_res": 0, # index of ["Whole picture", "Only masked"], Inpaint area
    "inpaint_full_res_padding": 32, #minimum=0, maximum=256, step=4, value=32, Only masked padding, pixels
    #"image_cfg_scale": 1, # resized by scale
    #"script_name": "Outpainting mk2", # 使用的script名字,不使用的话不要加这个字段
    #"script_args": ["Outpainting", 128, 8, ["left", "right", "up", "down"], 1, 0.05]  # 对应script脚本的参数,此处依次对应: 固定字段, pixels, mask_blur, direction, noise_q, color_variation
}

返回数据格式示例如下:

{
    "images":[],
    "parameters":{
        "id_task":"14837",
        "status":0,
        "image_url":"/data/api_test/img2img-grids/2023-06-05/grid-0000.png,/data/api_test/img2img-images/2023-06-05/00000-1003.png,/data/api_test/img2img-images/2023-06-05/00001-1004.png",
        "seed":"1003,1004",
        "error_msg":""
    },
    "info":""
}

txt2img使用controlnet的数据格式

请求数据格式如下:

{
    "alwayson_scripts": {
        "sd_model_checkpoint": "deliberate_v2.safetensors", #模型名称,需要带着 
        "save_dir": "/code/stable-diffusion-webui/data-oss/outputs",
        "controlnet":{
            "args":[
                {
                    "image_link": "https://pai-aigc-dataset.oss-cn-hangzhou.aliyuncs.com/pixabay_images/00008b87bf3ff6742b8cf81c358b9dbc.jpg",
                    "enabled": true, 
                    "module": "canny", 
                    "model": "control_v11p_sd15_canny", 
                    "weight": 1, 
                    "resize_mode": "Crop and Resize", 
                    "low_vram": false, 
                    "processor_res": 512, 
                    "threshold_a": 100, 
                    "threshold_b": 200, 
                    "guidance_start": 0, 
                    "guidance_end": 1, 
                    "pixel_perfect": true, 
                    "control_mode": "Balanced", 
                    "input_mode": "simple", 
                    "batch_images": "", 
                    "output_dir": "", 
                    "loopback": false
                }
            ]
        }
    },
    # 主要参数
    "prompt": "girls",          
    "batch_size": 1,                                            
    "n_iter": 2,                                                 
    "width": 576, 
    "height": 576,
    "negative_prompt": "ugly, out of frame"
}

返回数据格式示例如下:

{
    "images":[],
    "parameters":{
        "id_task":"14837",
        "status":0,
        "image_url":"/data/api_test/txt2img-grids/2023-06-05/grid-0007.png,/data/api_test/txt2img-images/2023-06-05/00014-1003.png,/data/api_test/txt2img-images/2023-06-05/00015-1004.png",
        "seed":"1003,1004",
        "error_msg":"",
        "image_mask_url":"/data/api_test/controlnet_mask/2023-06-05/00000.png,/data/api_test/controlnet_mask/2023-06-05/00001.png"
    },
    "info":""
}

相关文档