All Products
Search
Document Center

Platform For AI:Use ComfyUI to deploy an AI video generation model service

Last Updated:Jul 18, 2024

Elastic Algorithm Service (EAS) of Platform for AI (PAI) allows you to quickly deploy an AI video generation service based on ComfyUI and Stable Video Diffusion models. You can use the service to complete tasks such as generating short videos or animations on social media platforms. This topic describes how to deploy a service based on a ComfyUI image and general methods for calling the service.

Background information

As generative AI gains more attention, AI-powered video generation has become a popular application industry. Many open source foundation models for video generation are available in the market. You can select a foundation model based on the model performance and the specific scenario. ComfyUI, a node-based web UI tool for generative AI, divides the AI-powered content generation process into worker nodes to achieve precise workflow customization and reproducibility. You can quickly deploy a ComfyUI-based AI video generation service in one of the following editions:

  • Standard Edition: suitable for scenarios in which a single user calls the service by using the web UI or by using API operations when the service is deployed on a single instance. The following call methods are supported:

    • Web UI: When you send a request, the frontend forwards the request to the backend server. All requests are processed by the same backend instance. We recommend that you deploy the service on only one instance. If your service is deployed on multiple instances and you want to call the service by using the web UI, select Cluster Edition.

    • API: When you send a request, the request is sent by using the EAS interface. We recommend that you deploy the service on only one instance. If your service is deployed on multiple instances and you want to call the service by using API operations, select API Edition.

  • API Edition: suitable for high-concurrency scenarios. The system automatically deploys the service as an asynchronous service. This edition supports service calls only by using API operations. The system creates a queue service instance in addition to the asynchronous inference service instances.

  • Cluster Edition: suitable when multiple users call the service by using the web UI at the same time. This edition supports service calls only by using the web UI. You can use this edition in group work scenarios. The system allows resource reuse at different times to improve the utilization of inference clusters and reduce costs. The system creates an instance to allow the proxy to process requests from the web UI in addition to the inference service instances. For information about how a Cluster Edition service works, see Principles of the Cluster Edition service. Cluster Edition has the following benefits:

    • The system provides a separate backend environment for each user. If you configure multiple instances for the service, tasks of a single user are run in sequence, and tasks of multiple users are distributed among instances to achieve efficient GPU sharing.

    • The system assigns a separate working directory for each user to facilitate storage and management of files such as models and generated images or videos.

Procedure:

  1. Deploy a model service in EAS

    Select an edition based on your business requirements.

  2. Call an EAS service

    Select one of the following methods based on the edition you use:

    • Call EAS services by using the web UI

      Use the web UI to send a service request. This method is supported for Standard Edition and Cluster Edition.

    • Debug an EAS service online

      Send a synchronous service request on the online debugging page of EAS. This method is supported only for Standard Edition.

    • Call EAS services by using API operations

      Send a service request by using API operations. This method is supported only for Standard Edition and API Edition. Standard Edition supports synchronous service calls, whereas API Edition supports asynchronous service calls.

Prerequisites

Before you deploy a fine-tuned model, install the ComfyUI plug-in, or use an API operation to call a service, you must mount an Apsara File Storage NAS (NAS) file system or Object Storage Service (OSS) bucket. This makes it easier to upload the fine-tuned model and plug-in and obtain inference results. Make sure that the following operations are completed:

  • An OSS bucket and an empty file directory are created. Example: oss://bucket-test/data-oss/. bucket-test is the name of the OSS bucket and data-oss is the empty directory in the bucket. For more information about how to create a bucket, see Create a bucket. For more information about how to create an empty directory, see Manage directories.

  • A NAS file system and an empty directory are created. For more information, see Create a NAS file system.

Deploy a model service in EAS

The following deployment methods are supported:

Method 1: Scenario-based model deployment (recommend)

  1. Go to the EAS-Online Model Services page.

    1. Log on to the PAI console.

    2. In the left-side navigation pane, click Workspaces. On the Workspaces page, click the name of the workspace to which you want to deploy the model.

    3. In the left-side navigation pane, choose Model Deployment>Elastic Algorithm Service (EAS) to go to the Elastic Algorithm Service (EAS) page. image

  2. On the Elastic Algorithm Service (EAS) page, click Deploy Service. In the Scenario-based Model Deployment section, click AI Video Generation: ComfyUI-based Deployment.

  3. On the AI Video Generation: ComfyUI-based Deployment page, configure the following parameters.

    Parameter

    Description

    Basic Information

    Service Name

    The name of the model service.

    Edition

    The edition of the service. Valid values:

    • Standard Edition: suitable for scenarios in which a single user calls the service by using the web UI or by using API operations when the service is deployed on a single instance.

    • API Edition: suitable for high-concurrency scenarios. The system automatically deploys the service as an asynchronous service. This edition supports service calls only by using API operations.

    • Cluster Edition WebUI: suitable when multiple users call the service by using the web UI at the same time. This edition supports service calls only by using the web UI. For information about how a Cluster Edition service works, see Principles of the Cluster Edition service.

    For information about the scenarios of each edition, see the Background information section of this topic.

    Model Settings

    If you deploy a fine-tuned model, install the ComfyUI plug-in, or call the API Edition or Standard Edition service by using API operations, click Add to configure the model. This makes it easier to upload the model and plug-in and obtain the inference result. Valid values:

    • Mount OSS: Click the image icon to select an existing OSS directory.

    • Mount NAS: Configure a NAS mount target and NAS source path.

    You can upload the custom model and ComfyUI plug-in to the specific OSS or NAS path in subsequent steps. For more information, see the "How do I mount a custom model and the ComfyUI plug-in?" section of this topic.

    Resource Configuration

    Instance Count

    If you select Standard Edition, we recommend that you set the number of instances to 1.

    Resource Configuration

    We recommend that you use the GU30, A10 or T4 GPU types. By default, the system uses the GPU-accelerated > ml.gu7i.c16m60.1-gu30 instance type to ensure cost-effectiveness.

    Note

    ComfyUI supports only single-GPU mode, which means tasks can run on a single-GPU instance or multiple single-GPU instances. ComfyUI does not support multi-GPU concurrent operation.

  4. Click Deploy.

Method 2: Custom deployment

  1. Go to the EAS-Online Model Services page.

    1. Log on to the PAI console.

    2. In the left-side navigation pane, click Workspaces. On the Workspaces page, click the name of the workspace to which you want to deploy the model.

    3. In the left-side navigation pane, choose Model Deployment>Elastic Algorithm Service (EAS) to go to the Elastic Algorithm Service (EAS) page. image

  2. On the Elastic Algorithm Service (EAS) page, click Deploy Service. In the dialog box that appears, select Custom Deployment and click OK.

  3. On the Deploy Service page, configure the parameters. The following table describes the parameters.

    Parameter

    Description

    Model Service Information

    Service Name

    The name of the service. In this example, the name comfyui_svd_demo is used.

    Deployment Method

    Select Deploy Web App by Using Image.

    Select Image

    Select PAI Image and select comfyui and 1.3 from the drop-down lists. Take note of the following parameters:

    • x.x: specifies Standard Edition.

    • x.x.x-api: specifies API version.

    • x.x.x-cluster: specifies Cluster Edition.

    Note
    • The image version is updated frequently. We recommend that you select the latest version.

    • For information about the scenarios of each edition, see the Background information section of this topic.

    Specify Model Settings

    If you deploy a fine-tuned model, install the ComfyUI plug-in, or call the API Edition or Standard Edition service by using API operations, click Specify Model Settings to configure the model to upload the model and plug-in and obtain the inference result. Valid values:

    • Mount OSS Path

      • Click the image icon to select an existing OSS directory. Example: oss://bucket-test/data-oss/.

      • Mount Path: Set the value to /code/data-oss. The OSS file directory is mounted to the /code/data-oss path of the image.

    • Mount NAS File System

      • NAS Mount Target: the mount target of the NAS file system. The EAS service uses the mount target to access the NAS file system.

      • NAS Source Path: the NAS path where the files are stored. Example: /data-oss.

      • Mount Path: Set the value to /code/data-oss. The path of the NAS file system is mounted to the /code/data-oss path of the image.

    You can upload the custom model and ComfyUI plug-in to the specific OSS or NAS path in subsequent steps. For more information, see the "How do I mount a custom model and the ComfyUI plug-in?" section of this topic.

    Command to Run

    • After you configure the image version, the system automatically sets the parameter to python main.py --listen --port 8000.

    • Port number: 8000.

    After you configure the model settings, you must append the --data-dir mount directory to the command that you specify. The mount directory must be the same as the Mount Path that you specify in the Model Settings section. Example: python main.py --listen --port 8000 --data-dir /code/data-oss.

    Resource Deployment Information

    Resource Group Type

    Select Public Resource Group from the drop-down list.

    Instance Count

    If you use Standard Edition, we recommend that you set the number of instances to 1.

    Resource Configuration Mode

    Select General.

    Resource Configuration

    You must select a GPU-accelerated instance type. We recommend that you use ml.gu7i.c16m60.1-gu30 to ensure cost-effectiveness. If this instance type is unavailable, you can use the ecs.gn6i-c16g1.4xlarge instance type.

    Note

    ComfyUI supports only single-GPU mode, which means tasks can run on a single-GPU instance or multiple single-GPU instances. ComfyUI does not support multi-GPU concurrent operation.

  4. Click Deploy.

    If Service Status is Running, the service is deployed.

Call an EAS service

Call EAS services by using the web UI

You can use the web UI to call EAS services of Standard Edition or Cluster Edition. In a Standard Edition service, all requests are processed by the same backend instance. The Cluster Edition service distributes requests among multiple instances and is suitable for group work scenarios. Perform the following steps:

  1. Find the service that you want to manage and click View Web App in the Service Type column.

    Note

    When you access the web UI, the web UI page takes approximately 1 minute to load before you can see the interface.

  2. Perform model inference on the web application interface.

    Select a model for text-to-image generation and a model for image-to-video generation based on your business requirements. In this example, the default settings are used. Enter text prompts in the CLIP Text Encode (Prompt) section, such as Rocket takes off from the ground, fire, sky, airplane and click Queue Prompt. The system starts to run the workflow and generate the video. 85453c9fcadd222fbb087c5acddb6e90.png

  3. Right-click the generated video and select Save Image to save the generated video to your on-premises device. image.png

    The following section provides an example of the generated video:

Debug an EAS service online

Only Standard Edition services support online debugging. Procedure:

  1. Generate a request body. For more information, see the Generate a request body section in this topic.

  2. On the Elastic Algorithm Service (EAS) page, find the service that you want to debug and click Online Debugging in the Actions column.

  3. Send a POST request to obtain the prompt ID.

    1. On the Body tab of the Request Parameter Online Tuning section, enter the request body. Enter /prompt in the request URL input box. image

    2. Click Send Request and view the prediction results in the Debugging Information section. Example: image

  4. Send a GET request to obtain the inference result based on the prompt ID.

    1. In the Request Parameter Online Tuning section, select GET from the drop-down list and enter /history/<prompt id> in the input box. Example: image

      Replace <prompt id> with the prompt ID that you obtained in Step 3.

    2. Click Send Request to obtain the inference result.

      You can view the inference result in the output directory of the mounted storage.

Call EAS services by using API operations

You can use API operations to call Standard Edition or API Edition services. API calls support synchronous and asynchronous service calls.

  • Synchronous calls

    The Standard Edition service supports only synchronous calls. If you send a synchronous request, the client pauses execution and awaits the return of the result.

  • Asynchronous calls

    The API Edition service supports only asynchronous calls. The client uses the queue service of EAS to send requests to the input queue and subscribes to the inference result in the output queue.

ComfyUI has an asynchronous queue system. Synchronous calls are also processed in an asynchronous manner. After you submit a request, the system returns a prompt ID. You need to use the prompt ID to poll the inference results.

Synchronous calls

  1. View the information about API calls.

    1. In the service list, click the name of the Standard Edition service to go to the Service Details page.

    2. In the Basic Information section, click View Endpoint Information.

    3. On the Public Endpoint tab of the Invocation Method dialog box, obtain the service endpoint and token. image

  2. Obtain the prompt ID.

    1. Generate a request body. For more information, see the Generate a request body section in this topic.

    2. Send a request to obtain the prompt ID.

      The following methods are supported:

      Curl

      • HTTP request method: POST

      • Request URL: <service_url>/prompt

      • Request header:

        Request header

        Value

        Description

        Authorization

        <token>

        The authorization key.

        Content-Type

        application/json

        The format of the request body.

      • Sample code

        curl --location --request POST '<service_url>/prompt' \
        --header 'Authorization: <token>' \
        --header 'Content-Type: application/json' \
        --data-raw '{
            "prompt":
            Omitted
        }'

        The following table describes the parameters.

        Parameter

        Description

        <service_url>

        Replace the value with the endpoint that you obtained in Step 1. Delete the forward slash ( /) at the end of the endpoint. Example: http://comfyui****.175805416243****.cn-beijing.pai-eas.aliyuncs.com.

        <token>

        Replace the value with the token that you obtained in Step 1. Example: ZGJmNzcwYjczODE1MmVlNWY1NTNiNGYxNDkzODI****NzU2NTFiOA==.

        data-raw

        Set the value to the request body. Example:

        Important

        The first letter of the Boolean value (true and false) in the request body must be lowercase.

        Click to view a sample request body

        {
            "prompt": {
                "3": {
                    "inputs": {
                        "seed": 367490676387803,
                        "steps": 40,
                        "cfg": 7,
                        "sampler_name": "dpmpp_sde_gpu",
                        "scheduler": "karras",
                        "denoise": 1,
                        "model": [
                            "4",
                            0
                        ],
                        "positive": [
                            "6",
                            0
                        ],
                        "negative": [
                            "7",
                            0
                        ],
                        "latent_image": [
                            "5",
                            0
                        ]
                    },
                    "class_type": "KSampler",
                    "_meta": {
                        "title": "K sampler"
                    }
                },
                "4": {
                    "inputs": {
                        "ckpt_name": "LandscapeBING_v10.safetensors"
                    },
                    "class_type": "CheckpointLoaderSimple",
                    "_meta": {
                        "title": "Checkpoint loader (simple)"
                    }
                },
                "5": {
                    "inputs": {
                        "width": 720,
                        "height": 1280,
                        "batch_size": 1
                    },
                    "class_type": "EmptyLatentImage",
                    "_meta": {
                        "title": "Empty Latent"
                    }
                },
                "6": {
                    "inputs": {
                        "text": "Rocket takes off from the ground, fire,sky, airplane",
                        "clip": [
                            "4",
                            1
                        ]
                    },
                    "class_type": "CLIPTextEncode",
                    "_meta": {
                        "title": "CLIP text encoder"
                    }
                },
                "7": {
                    "inputs": {
                        "text": "",
                        "clip": [
                            "4",
                            1
                        ]
                    },
                    "class_type": "CLIPTextEncode",
                    "_meta": {
                        "title": "CLIP text encoder"
                    }
                },
                "8": {
                    "inputs": {
                        "samples": [
                            "3",
                            0
                        ],
                        "vae": [
                            "4",
                            2
                        ]
                    },
                    "class_type": "VAEDecode",
                    "_meta": {
                        "title": "VAE decoding"
                    }
                },
                "9": {
                    "inputs": {
                        "filename_prefix": "ComfyUI",
                        "images": [
                            "8",
                            0
                        ]
                    },
                    "class_type": "SaveImage",
                    "_meta": {
                        "title": "Save the image"
                    }
                },
                "13": {
                    "inputs": {
                        "seed": 510424455529432,
                        "steps": 40,
                        "cfg": 2.5,
                        "sampler_name": "euler_ancestral",
                        "scheduler": "karras",
                        "denoise": 1,
                        "model": [
                            "17",
                            0
                        ],
                        "positive": [
                            "16",
                            0
                        ],
                        "negative": [
                            "16",
                            1
                        ],
                        "latent_image": [
                            "16",
                            2
                        ]
                    },
                    "class_type": "KSampler",
                    "_meta": {
                        "title": "K sampler"
                    }
                },
                "14": {
                    "inputs": {
                        "samples": [
                            "13",
                            0
                        ],
                        "vae": [
                            "18",
                            2
                        ]
                    },
                    "class_type": "VAEDecode",
                    "_meta": {
                        "title": "VAE decoding"
                    }
                },
                "15": {
                    "inputs": {
                        "filename_prefix": "ComfyUI",
                        "fps": 10,
                        "lossless": false,
                        "quality": 85,
                        "method": "default",
                        "images": [
                            "14",
                            0
                        ]
                    },
                    "class_type": "SaveAnimatedWEBP",
                    "_meta": {
                        "title": "Save WEBP"
                    }
                },
                "16": {
                    "inputs": {
                        "width": 512,
                        "height": 768,
                        "video_frames": 35,
                        "motion_bucket_id": 140,
                        "fps": 15,
                        "augmentation_level": 0.15,
                        "clip_vision": [
                            "18",
                            1
                        ],
                        "init_image": [
                            "8",
                            0
                        ],
                        "vae": [
                            "18",
                            2
                        ]
                    },
                    "class_type": "SVD_img2vid_Conditioning",
                    "_meta": {
                        "title": "SVD_Image to Video_Condition"
                    }
                },
                "17": {
                    "inputs": {
                        "min_cfg": 1,
                        "model": [
                            "18",
                            0
                        ]
                    },
                    "class_type": "VideoLinearCFGGuidance",
                    "_meta": {
                        "title": "Linear CFG Bootstrap"
                    }
                },
                "18": {
                    "inputs": {
                        "ckpt_name": "svd_xt_image_decoder.safetensors"
                    },
                    "class_type": "ImageOnlyCheckpointLoader",
                    "_meta": {
                        "title": "Checkpoint loader (image only)"
                    }
                },
                "19": {
                    "inputs": {
                        "frame_rate": 10,
                        "loop_count": 0,
                        "filename_prefix": "comfyUI",
                        "format": "video/h264-mp4",
                        "pix_fmt": "yuv420p",
                        "crf": 20,
                        "save_metadata": true,
                        "pingpong": false,
                        "save_output": true,
                        "images": [
                            "14",
                            0
                        ]
                    },
                    "class_type": "VHS_VideoCombine",
                    "_meta": {
                        "title": "Merge to video"
                    }
                }
            }
        }

      Python

      The following code provides an example:

      import requests
      
      url = "<service_url>/prompt"
      
      payload = {
          "prompt":
          Omitted
      }
      
      session = requests.session()
      session.headers.update({"Authorization":"<token>"})
      
      
      response = session.post(url=f'{url}', json=payload)
      if response.status_code != 200:
          raise Exception(response.content)
      
      data = response.json()
      print(data)

      The following table describes the parameters.

      Value

      Cluster Description

      <service_url>

      Replace the value with the endpoint that you obtained in Step 1. Delete the forward slash (/) at the end of the endpoint. Example: http://comfyui****.175805416243****.cn-beijing.pai-eas.aliyuncs.com.

      <token>

      Replace the value with the token that you obtained in Step 1. ZGJmNzcwYjczODE1MmVlNWY1NTNiNGYxNDkzODI****NzU2NTFiOA==

      payload

      Set the value to the request body. Example:

      Important

      The first letter of the Boolean value (True and False) in the request body must be uppercase.

      Click to view a sample request body

      {
          "prompt": {
              "3": {
                  "inputs": {
                      "seed": 367490676387803,
                      "steps": 40,
                      "cfg": 7,
                      "sampler_name": "dpmpp_sde_gpu",
                      "scheduler": "karras",
                      "denoise": 1,
                      "model": [
                          "4",
                          0
                      ],
                      "positive": [
                          "6",
                          0
                      ],
                      "negative": [
                          "7",
                          0
                      ],
                      "latent_image": [
                          "5",
                          0
                      ]
                  },
                  "class_type": "KSampler",
                  "_meta": {
                      "title": "K sampler"
                  }
              },
              "4": {
                  "inputs": {
                      "ckpt_name": "LandscapeBING_v10.safetensors"
                  },
                  "class_type": "CheckpointLoaderSimple",
                  "_meta": {
                      "title": "Checkpoint loader (simple)"
                  }
              },
              "5": {
                  "inputs": {
                      "width": 720,
                      "height": 1280,
                      "batch_size": 1
                  },
                  "class_type": "EmptyLatentImage",
                  "_meta": {
                      "title": "Empty Latent"
                  }
              },
              "6": {
                  "inputs": {
                      "text": "Rocket takes off from the ground, fire,sky, airplane",
                      "clip": [
                          "4",
                          1
                      ]
                  },
                  "class_type": "CLIPTextEncode",
                  "_meta": {
                      "title": "CLIP text encoder"
                  }
              },
              "7": {
                  "inputs": {
                      "text": "",
                      "clip": [
                          "4",
                          1
                      ]
                  },
                  "class_type": "CLIPTextEncode",
                  "_meta": {
                      "title": "CLIP text encoder"
                  }
              },
              "8": {
                  "inputs": {
                      "samples": [
                          "3",
                          0
                      ],
                      "vae": [
                          "4",
                          2
                      ]
                  },
                  "class_type": "VAEDecode",
                  "_meta": {
                      "title": "VAE decoding"
                  }
              },
              "9": {
                  "inputs": {
                      "filename_prefix": "ComfyUI",
                      "images": [
                          "8",
                          0
                      ]
                  },
                  "class_type": "SaveImage",
                  "_meta": {
                      "title": "Save the image"
                  }
              },
              "13": {
                  "inputs": {
                      "seed": 510424455529432,
                      "steps": 40,
                      "cfg": 2.5,
                      "sampler_name": "euler_ancestral",
                      "scheduler": "karras",
                      "denoise": 1,
                      "model": [
                          "17",
                          0
                      ],
                      "positive": [
                          "16",
                          0
                      ],
                      "negative": [
                          "16",
                          1
                      ],
                      "latent_image": [
                          "16",
                          2
                      ]
                  },
                  "class_type": "KSampler",
                  "_meta": {
                      "title": "K sampler"
                  }
              },
              "14": {
                  "inputs": {
                      "samples": [
                          "13",
                          0
                      ],
                      "vae": [
                          "18",
                          2
                      ]
                  },
                  "class_type": "VAEDecode",
                  "_meta": {
                      "title": "VAE decoding"
                  }
              },
              "15": {
                  "inputs": {
                      "filename_prefix": "ComfyUI",
                      "fps": 10,
                      "lossless": False,
                      "quality": 85,
                      "method": "default",
                      "images": [
                          "14",
                          0
                      ]
                  },
                  "class_type": "SaveAnimatedWEBP",
                  "_meta": {
                      "title": "Save WEBP"
                  }
              },
              "16": {
                  "inputs": {
                      "width": 512,
                      "height": 768,
                      "video_frames": 35,
                      "motion_bucket_id": 140,
                      "fps": 15,
                      "augmentation_level": 0.15,
                      "clip_vision": [
                          "18",
                          1
                      ],
                      "init_image": [
                          "8",
                          0
                      ],
                      "vae": [
                          "18",
                          2
                      ]
                  },
                  "class_type": "SVD_img2vid_Conditioning",
                  "_meta": {
                      "title": "SVD_Image to Video_Condition"
                  }
              },
              "17": {
                  "inputs": {
                      "min_cfg": 1,
                      "model": [
                          "18",
                          0
                      ]
                  },
                  "class_type": "VideoLinearCFGGuidance",
                  "_meta": {
                      "title": "Linear CFG Bootstrap"
                  }
              },
              "18": {
                  "inputs": {
                      "ckpt_name": "svd_xt_image_decoder.safetensors"
                  },
                  "class_type": "ImageOnlyCheckpointLoader",
                  "_meta": {
                      "title": "Checkpoint loader (image only)"
                  }
              },
              "19": {
                  "inputs": {
                      "frame_rate": 10,
                      "loop_count": 0,
                      "filename_prefix": "comfyUI",
                      "format": "video/h264-mp4",
                      "pix_fmt": "yuv420p",
                      "crf": 20,
                      "save_metadata": True,
                      "pingpong": False,
                      "save_output": True,
                      "images": [
                          "14",
                          0
                      ]
                  },
                  "class_type": "VHS_VideoCombine",
                  "_meta": {
                      "title": "Merge to video"
                  }
              }
          }
      }

      Sample response:

      {'prompt_id': '021ebc5b-e245-4e37-8bd3-00f7b949****',
       'number': 5,
       'node_errors': {}}

      You can obtain the prompt ID from the response.

  3. Send a request to obtain the inference result.

    The following methods are supported:

    Curl

    • HTTP request method: GET

    • Request URL: <service_url>/history/<prompt_id>

    • Request header:

    • Request header

      Value

      Description

      Authorization

      <token>

      The authorization key.

    • Sample code:

      curl --location --request GET '<service_url>/history/<prompt_id>' \
           --header 'Authorization: <token>'

      The following table describes the parameters.

      Value

      Cluster Description

      <service_url>

      Replace the value with the endpoint that you obtained in Step 1. Delete the forward slash ( /) at the end of the endpoint. Example: http://comfyui****.175805416243****.cn-beijing.pai-eas.aliyuncs.com.

      <token>

      Replace the value with the token that you obtained in Step 1. Example: ZGJmNzcwYjczODE1MmVlNWY1NTNiNGYxNDkzODI****NzU2NTFiOA==.

      <prompt_id>

      Replace the value with the prompt ID that you obtained in Step 2.

    Python

    The following code provides an example:

    import requests
    
    # Create the request URL. 
    url = "<service_url>/history/<prompt_id>"
    
    session = requests.session()
    session.headers.update({"Authorization":"<token>"})
    
    response = session.get(url=f'{url}')
    
    if response.status_code != 200:
        raise Exception(response.content)
    
    data = response.json()
    print(data)

    The following table describes the parameters.

    Parameter

    Description

    <service_url>

    Replace the value with the endpoint that you obtained in Step 1. Delete the forward slash (/) at the end of the endpoint. Example: http://comfyui****.175805416243****.cn-beijing.pai-eas.aliyuncs.com.

    <token>

    Replace the value with the token that you obtained in Step 1. Example: ZGJmNzcwYjczODE1MmVlNWY1NTNiNGYxNDkzODI****NzU2NTFiOA==.

    <prompt_id>

    Replace the value with the prompt ID that you obtained in Step 2.

    Sample response:

    {
        "130bcd6b-5bb5-496c-9c8c-3a1359a0****": {
            "prompt": ... omitted,
            "outputs": {
                "9": {
                    "images": [
                        {
                            "filename": "ComfyUI_1712645398_18dba34d-df87-4735-a577-c63d5506a6a1_.png",
                            "subfolder": "",
                            "type": "output"
                        }
                    ]
                },
                "15": {
                    "images": [
                        {
                            "filename": "ComfyUI_1712645867_.webp",
                            "subfolder": "",
                            "type": "output"
                        }
                    ],
                    "animated": [
                        true
                    ]
                },
                "19": {
                    "gifs": [
                        {
                            "filename": "comfyUI_00002.mp4",
                            "subfolder": "",
                            "type": "output",
                            "format": "video/h264-mp4"
                        }
                    ]
                }
            },
            "status": {
                "status_str": "success",
                "completed": true,
                "messages": ... omitted,
            }
        }
    }
    

    In the preceding response, the generated images, WEBP files, and MP4 videos are returned in the outputs section. You can find the files by file name in the output directory of the mounted storage.

Asynchronous calls

Only API Edition services support asynchronous calls, and the calls are sent by using api_prompt.

  1. View the information about API calls.

    Click Invocation Method in the Service Type column of the service. In the Invocation Method dialog box, view the service endpoint and token on the Asynchronous Invocation tab. image

  2. Send request.

    The following code provides an example:

    import requests,io,base64
    from PIL import Image, PngImagePlugin
    
    url = "<service_url>"
    session = requests.session()
    session.headers.update({"Authorization":"<token>"})
    
    work_flow = {
        '3': 
        Omitted
      }
    
    for i in range(5):
      payload = work_flow
      response = session.post(url=f'{url}/api_prompt?task_id=txt2img_{i}', json=payload)
      if response.status_code != 200:
        exit(f"send request error:{response.content}")
      else:
        print(f"send {i} success, index is {response.content}")

    The following table describes the parameters.

    Parameter

    Description

    <service_url>

    Replace the value with the endpoint that you obtained in Step 1. Delete the forward slash (/) at the end of the endpoint. Example: http://175805416243****.cn-beijing.pai-eas.aliyuncs.com/api/predict/comfyui_api.

    <token>

    Replace the value with the token that you obtained in Step 1. Example: ZTJhM****TBhMmJkYjM3M2U0NjM1NGE3OGNlZGEyZTdjYjlm****Nw==.

    work_flow

    Set the value to the content of the JSON file of the workflow. For information about how to obtain a workflow JSON file, see the Generate a request body section of this topic.

    Important

    The first letter of the Boolean values (True and False) in the file must be uppercase.

    Click to view a sample JSON file

    {
      "3": {
        "inputs": {
          "seed": 1021224598837526,
          "steps": 40,
          "cfg": 7,
          "sampler_name": "dpmpp_sde_gpu",
          "scheduler": "karras",
          "denoise": 1,
          "model": [
            "4",
            0
          ],
          "positive": [
            "6",
            0
          ],
          "negative": [
            "7",
            0
          ],
          "latent_image": [
            "5",
            0
          ]
        },
        "class_type": "KSampler",
        "_meta": {
          "title": "K sampler"
        }
      },
      "4": {
        "inputs": {
          "ckpt_name": "LandscapeBING_v10.safetensors"
        },
        "class_type": "CheckpointLoaderSimple",
        "_meta": {
          "title": "Checkpoint loader (simple)"
        }
      },
      "5": {
        "inputs": {
          "width": 720,
          "height": 1280,
          "batch_size": 1
        },
        "class_type": "EmptyLatentImage",
        "_meta": {
          "title": "Empty Latent"
        }
      },
      "6": {
        "inputs": {
          "text": "Rocket takes off from the ground, fire, sky, airplane",
          "clip": [
            "4",
            1
          ]
        },
        "class_type": "CLIPTextEncode",
        "_meta": {
          "title": "CLIP text encoder"
        }
      },
      "7": {
        "inputs": {
          "text": "",
          "clip": [
            "4",
            1
          ]
        },
        "class_type": "CLIPTextEncode",
        "_meta": {
          "title": "CLIP text encoder"
        }
      },
      "8": {
        "inputs": {
          "samples": [
            "3",
            0
          ],
          "vae": [
            "4",
            2
          ]
        },
        "class_type": "VAEDecode",
        "_meta": {
          "title": "VAE decoding"
        }
      },
      "9": {
        "inputs": {
          "filename_prefix": "ComfyUI",
          "images": [
            "8",
            0
          ]
        },
        "class_type": "SaveImage",
        "_meta": {
          "title": "Save the image"
        }
      },
      "13": {
        "inputs": {
          "seed": 1072245043382649,
          "steps": 40,
          "cfg": 2.5,
          "sampler_name": "euler_ancestral",
          "scheduler": "karras",
          "denoise": 1,
          "model": [
            "17",
            0
          ],
          "positive": [
            "16",
            0
          ],
          "negative": [
            "16",
            1
          ],
          "latent_image": [
            "16",
            2
          ]
        },
        "class_type": "KSampler",
        "_meta": {
          "title": "K sampler"
        }
      },
      "14": {
        "inputs": {
          "samples": [
            "13",
            0
          ],
          "vae": [
            "18",
            2
          ]
        },
        "class_type": "VAEDecode",
        "_meta": {
          "title": "VAE decoding"
        }
      },
      "15": {
        "inputs": {
          "filename_prefix": "ComfyUI",
          "fps": 10,
          "lossless": False,
          "quality": 85,
          "method": "default",
          "images": [
            "14",
            0
          ]
        },
        "class_type": "SaveAnimatedWEBP",
        "_meta": {
          "title": "Save WEBP"
        }
      },
      "16": {
        "inputs": {
          "width": 512,
          "height": 768,
          "video_frames": 35,
          "motion_bucket_id": 140,
          "fps": 15,
          "augmentation_level": 0.15,
          "clip_vision": [
            "18",
            1
          ],
          "init_image": [
            "8",
            0
          ],
          "vae": [
            "18",
            2
          ]
        },
        "class_type": "SVD_img2vid_Conditioning",
        "_meta": {
          "title": "SVD_Image to Video_Condition"
        }
      },
      "17": {
        "inputs": {
          "min_cfg": 1,
          "model": [
            "18",
            0
          ]
        },
        "class_type": "VideoLinearCFGGuidance",
        "_meta": {
          "title": "Linear CFG Bootstrap"
        }
      },
      "18": {
        "inputs": {
          "ckpt_name": "svd_xt_image_decoder.safetensors"
        },
        "class_type": "ImageOnlyCheckpointLoader",
        "_meta": {
          "title": "Checkpoint loader (image only)"
        }
      },
      "19": {
        "inputs": {
          "frame_rate": 10,
          "loop_count": 0,
          "filename_prefix": "comfyUI",
          "format": "video/h264-mp4",
          "pix_fmt": "yuv420p",
          "crf": 20,
          "save_metadata": True,
          "pingpong": False,
          "save_output": True,
          "images": [
            "14",
            0
          ]
        },
        "class_type": "VHS_VideoCombine",
        "_meta": {
          "title": "Merge to video"
        }
      }
    }
  3. Subscribe to results.

    1. Run the following command to install the eas_prediction SDK:

      pip install eas_prediction  --user
    2. Run the following code to obtain the response:

      from eas_prediction import QueueClient
      
      sink_queue = QueueClient('<service_domain>', '<service_name>/sink')
      sink_queue.set_token('<token>')
      sink_queue.init()
      
      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)
      

      The following table describes the key parameters.

      Parameter

      Description

      <service_domain>

      Replace the value with the service endpoint that you obtained in Step 1. Example: 139699392458****.cn-hangzhou.pai-eas.aliyuncs.com.

      <service_name>

      Replace the value with the name of the EAS service.

      <token>

      Replace the value with the token that you obtained in Step 1.

      Sample response:

      index 42 task_id is txt2img_0
      index 42 data is b'[{"type": "executed", "data": {"node": "9", "output": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "prompt_id": "c3c983b6-f92b-4dd5-b4dc-442db4d1736f"}}, {"type": "executed", "data": {"node": "15", "output": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "prompt_id": "c3c983b6-f92b-4dd5-b4dc-442db4d1736f"}}, {"type": "executed", "data": {"node": "19", "output": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}, "prompt_id": "c3c983b6-f92b-4dd5-b4dc-442db4d1736f"}}, {"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 43 task_id is txt2img_1
      index 43 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 44 task_id is txt2img_2
      index 44 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 45 task_id is txt2img_3
      index 45 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 46 task_id is txt2img_4
      index 46 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'

      You can view the inference result files in the output directory of the mounted storage.

References

  • ComfyUI-based API Edition services use asynchronous queues. For more information about the asynchronous calls, see Deploy an asynchronous inference service.

  • EAS also supports the following scenario-based deployment:

    • You can use EAS to deploy an LLM with a few clicks and then call the model by using the web UI or API operations. After you deploy an LLM, you can use the LangChain framework to build a Q&A chatbot that is connected to a custom knowledge base. For more information, see Quickly deploy open source LLMs in EAS.

    • You can configure parameters to deploy a Retrieval-Augmented Generation (RAG)-based LLM chatbot. The chatbot is suitable for Q&A, summarization, and other natural language processing (NLP) tasks that rely on specific knowledge bases. For more information, see RAG-based LLM chatbot.

Appendixes

Generate a request body

You need to configure a workflow based on your business requirements on the web UI page, and then generate the request body. Perform the following steps:

  1. On the Elastic Algorithm Service (EAS) page, find the service that you want to view and click View Web App in the Service Type column to go to the ComfyUI-based web UI page.

    Note

    The web UI page takes approximately 1 minute to load before you can see the interface.

  2. On the web UI page, click the image icon. In the Settings dialog box, select Enable Dev mode Options. image

  3. On the web UI page, configure a workflow based on your business requirements.

    You can select a model in the Load Checkpoint section, enter prompts in the CLIP Text Encode (Prompt) section, or adjust sampler configurations. After you complete the configuration, click Queue Prompt to obtain the AI-generated video.

  4. If the workflow works as expected, click Save (API Format) to download the JSON file of the workflow. image

    Take note of the following items:

    • For the request body of a synchronous call or online debugging, you must package the content of the downloaded JSON file in the prompt field. The following section provides an example of the request body of the preceding workflow:

      {
          "prompt": {
              "3": {
                  "inputs": {
                      "seed": 367490676387803,
                      "steps": 40,
                      "cfg": 7,
                      "sampler_name": "dpmpp_sde_gpu",
                      "scheduler": "karras",
                      "denoise": 1,
                      "model": [
                          "4",
                          0
                      ],
                      "positive": [
                          "6",
                          0
                      ],
                      "negative": [
                          "7",
                          0
                      ],
                      "latent_image": [
                          "5",
                          0
                      ]
                  },
                  "class_type": "KSampler",
                  "_meta": {
                      "title": "K sampler"
                  }
              },
              "4": {
                  "inputs": {
                      "ckpt_name": "LandscapeBING_v10.safetensors"
                  },
                  "class_type": "CheckpointLoaderSimple",
                  "_meta": {
                      "title": "Checkpoint loader (simple)"
                  }
              },
              "5": {
                  "inputs": {
                      "width": 720,
                      "height": 1280,
                      "batch_size": 1
                  },
                  "class_type": "EmptyLatentImage",
                  "_meta": {
                      "title": "Empty Latent"
                  }
              },
              "6": {
                  "inputs": {
                      "text": "Rocket takes off from the ground, fire,sky, airplane",
                      "clip": [
                          "4",
                          1
                      ]
                  },
                  "class_type": "CLIPTextEncode",
                  "_meta": {
                      "title": "CLIP text encoder"
                  }
              },
              "7": {
                  "inputs": {
                      "text": "",
                      "clip": [
                          "4",
                          1
                      ]
                  },
                  "class_type": "CLIPTextEncode",
                  "_meta": {
                      "title": "CLIP text encoder"
                  }
              },
              "8": {
                  "inputs": {
                      "samples": [
                          "3",
                          0
                      ],
                      "vae": [
                          "4",
                          2
                      ]
                  },
                  "class_type": "VAEDecode",
                  "_meta": {
                      "title": "VAE decoding"
                  }
              },
              "9": {
                  "inputs": {
                      "filename_prefix": "ComfyUI",
                      "images": [
                          "8",
                          0
                      ]
                  },
                  "class_type": "SaveImage",
                  "_meta": {
                      "title": "Save the image"
                  }
              },
              "13": {
                  "inputs": {
                      "seed": 510424455529432,
                      "steps": 40,
                      "cfg": 2.5,
                      "sampler_name": "euler_ancestral",
                      "scheduler": "karras",
                      "denoise": 1,
                      "model": [
                          "17",
                          0
                      ],
                      "positive": [
                          "16",
                          0
                      ],
                      "negative": [
                          "16",
                          1
                      ],
                      "latent_image": [
                          "16",
                          2
                      ]
                  },
                  "class_type": "KSampler",
                  "_meta": {
                      "title": "K sampler"
                  }
              },
              "14": {
                  "inputs": {
                      "samples": [
                          "13",
                          0
                      ],
                      "vae": [
                          "18",
                          2
                      ]
                  },
                  "class_type": "VAEDecode",
                  "_meta": {
                      "title": "VAE decoding"
                  }
              },
              "15": {
                  "inputs": {
                      "filename_prefix": "ComfyUI",
                      "fps": 10,
                      "lossless": false,
                      "quality": 85,
                      "method": "default",
                      "images": [
                          "14",
                          0
                      ]
                  },
                  "class_type": "SaveAnimatedWEBP",
                  "_meta": {
                      "title": "Save WEBP"
                  }
              },
              "16": {
                  "inputs": {
                      "width": 512,
                      "height": 768,
                      "video_frames": 35,
                      "motion_bucket_id": 140,
                      "fps": 15,
                      "augmentation_level": 0.15,
                      "clip_vision": [
                          "18",
                          1
                      ],
                      "init_image": [
                          "8",
                          0
                      ],
                      "vae": [
                          "18",
                          2
                      ]
                  },
                  "class_type": "SVD_img2vid_Conditioning",
                  "_meta": {
                      "title": "SVD_Image to Video_Condition"
                  }
              },
              "17": {
                  "inputs": {
                      "min_cfg": 1,
                      "model": [
                          "18",
                          0
                      ]
                  },
                  "class_type": "VideoLinearCFGGuidance",
                  "_meta": {
                      "title": "Linear CFG Bootstrap"
                  }
              },
              "18": {
                  "inputs": {
                      "ckpt_name": "svd_xt_image_decoder.safetensors"
                  },
                  "class_type": "ImageOnlyCheckpointLoader",
                  "_meta": {
                      "title": "Checkpoint loader (image only)"
                  }
              },
              "19": {
                  "inputs": {
                      "frame_rate": 10,
                      "loop_count": 0,
                      "filename_prefix": "comfyUI",
                      "format": "video/h264-mp4",
                      "pix_fmt": "yuv420p",
                      "crf": 20,
                      "save_metadata": true,
                      "pingpong": false,
                      "save_output": true,
                      "images": [
                          "14",
                          0
                      ]
                  },
                  "class_type": "VHS_VideoCombine",
                  "_meta": {
                      "title": "Merge to video"
                  }
              }
          }
      }
    • For the request body of an asynchronous call, you do not need to specify the prompt field. In the preceding sample request body, the content of the downloaded JSON file is used.

Principles of the Cluster Edition service

The following figure shows how a Cluster Edition service works.

image
  • The Cluster Edition service is suitable for multi-user scenarios. The service decouples the client and backend inference instances to allow multiple users to reuse backend inference instances at different times. This improves instance utilization and reduces costs.

  • The proxy is used to manage client processes and inference instances. Your operations are processed in your user process. You can manage only files in public directories and personal directories. This isolates the working directories of team members. When you want to use an inference instance to process a request, the proxy identifies an available instance from the backend inference instances to process the inference request.

Accelerate image generation

xFormers is an open source acceleration tool based on Transformer. It can effectively accelerate image and video generation and improve GPU utilization. By default, xFormers acceleration is enabled for ComfyUI-based service deployment.

How do I mount a custom model and the ComfyUI plug-in?

After you deploy the service, the system automatically creates the following directory structure in the mounted OSS bucket or NAS file system: image

Take note of the following parameters:

  • custom_nodes: This directory is used to store the ComfyUI plug-in.

  • models: This directory is used to store model files.

If you obtain third-party ComfyUI plug-ins from the open source community or generate a custom model, you must store these plug-ins or model files in the specified directory to allow the system to load and use new models and plug-ins. Perform the following steps:

  1. After you deploy the service, find the service that you want to view and click View Web App in the Service Type column.

  2. On the web UI page, view the list of available model files and ComfyUI plug-ins.

    • If you use the default ComfyUI workflow, you need to view the available model files on the corresponding node. For example, you can view the available model files in the drop-down list of the Checkpoint Loader.

    • Right-click the web UI page and select Create Node from the shortcut menu to view all installed ComfyUI plug-ins. image

  3. Load the model file.

    1. Upload the model file to the subdirectory of the models directory of the mounted storage. For more information, see the "Upload a file" section in the Get started by using the OSS console topic. Refer to the instructions for the open source project library of the corresponding node to determine the subdirectory to which to upload the model. For example, for a Checkpoint loader node, the model must be uploaded to the models/checkpoints path.

    2. On the web UI page, click Refresh and check whether the model file is loaded from the drop-down list of Checkpoint Loader. image

    3. If the model file is not loaded, click Process Restart to reload the model file. image

      This process requires approximately 5 minutes, during which the service automatically restarts and provides services. After the service is restarted, you can access the web UI page to check whether the model file is loaded.

  4. You can use one of the following methods to load the ComfyUI plug-in:

    • (Recommended.) Upload and load the ComfyUI plug-in.

      1. Upload the third-party ComfyUI plug-in to the custom_nodes directory of the mounted storage.

      2. On the web UI page, click Process Restart.

        This process requires approximately 5 minutes, during which the service automatically restarts and provides services. After the service is restarted, you can access the web UI page to check whether the plug-in is loaded.

    • Install the plug-in directly in the Manager. The network connection may fail when pulling code from the GitHub platform.

      On the web UI page, click Manager. In the ComfyUI Manager dialog box, install the node. image