All Products
Search
Document Center

Platform For AI:Wan video generation best practices

Last Updated:Dec 04, 2025

Wan is an open-source video generation model that supports T2V (text-to-video) and I2V (image-to-video) generations. PAI provides customized JSON workflows and API calling methods to help you use the Wan model in ComfyUI to generate high-quality videos. This topic uses I2V as an example to show how to deploy the ComfyUI service and use Wan to generate videos.

Deploy ComfyUI standard service (for single user)

Deploy the service

Use the custom deployment method to deploy the ComfyUI standard service. Perform the following steps:

  1. Log on to the PAI console. Select a region on the top of the page. Then, select the desired workspace and click Elastic Algorithm Service (EAS).

  2. Click Deploy Service. In the Custom Model Deployment section, click Custom Deployment.

  3. On the Custom Deployment page, configure the following parameters.

    1. In the Environment Information section:

      Parameter

      Description

      Image Configuration

      Select comfyui > comfyui:1.9 from the Alibaba Cloud Images list.

      Note

      1.9 is the image version. Due to rapid version iterations, you can just select the latest version when deploying.

      Mount storage

      Mount an external storage (such as OSS or NAS) for the service. The generated videos will be automatically saved to the corresponding data source. Take OSS as an example, set the following parameters:

      • Uri: Select an OSS bucket directory. For more information about how to create a bucket and directory, see Get started with the OSS console. Make sure that your bucket is in the same region as the EAS service.

      • Mount Path: The destination path in the service instance. For example, /code/data-oss.

      Command

      After you select an image, the system automatically sets this parameter.

      After you complete the model settings, set the --data-dir mount directory in Command and make sure that the mount directory is the same as the mount path in model settings.

      For the image version 1.9, --data-dir is preconfigured. You only need to update it to the mount path in model settings. For example, python main.py --listen --port 8000 --data-dir /code/data-oss.

    2. In the Resource Information section, set the resource specifications.

      Parameter

      Description

      Resource Type

      Select Public Resources.

      Deployment Resources

      Choose a Resource Type. Because video generation requires more GPU video memory than image generation, we recommend a type with GPU memory of no less than 48 GB per card, such as the GU60 types (for example, ml.gu8is.c16m128.1-gu60).

    3. In the Network information section, set a virtual private cloud (VPC) with Internet access. For more information, see Configure Internet access for VPC.

      Note

      The EAS service does not have Internet access by default. However, because the I2V function needs to download images from the internet, a VPC with Internet access is required.

  4. After you configure the parameters, click Deploy.

Use WebUI

After the service is deployed, you can build a workflow on the WebUI page. Perform the following steps:

  1. Click View Web App in the Service Type column.

  2. In the upper-left corner, select Workflow > Open, select a JSON workflow file, and Open it.

    PAI has integrated various acceleration algorithms in ComfyUI. Here are some workflows with good speed and performance:

    • I2V (upload image directly): wanvideo_720P_I2V.json

      After the workflow is loaded, you can click upload in the Load Image section to upload or update image files.image

    • I2V (load image URL): wanvideo_720P_I2V_URL.json

      After the workflow is loaded, set the image URL in the Load Image By URL section to update images.image

  3. Click the Run button at the bottom of the page to generate a video.

    After about 20 minutes of execution, the result will be displayed in the Video Combine section on the right.image

Synchronous API call

The standard service only supports synchronous calling, which means directly requesting the inference instance without using the EAS queue service. Perform the following steps:

  1. Export the workflow JSON file.

    The API request body depends on the workflow configuration. You need to first set up the workflow on the WebUI page of the service. Then, select Workflow > Export (API) in the upper-left corner to get the JSON file corresponding to the workflow.

    image

  2. View the endpoint information.

    1. In the service list, click the service name, and then click View Endpoint Information in the Basic Information section.

    2. In the Invocation Method panel, obtain the endpoint and token.

      Note
      • To use the Internet endpoint: the client must support access to the Internet.

      • To use the VPC endpoint: the client must be in the same VPC as the service.

      image

  3. Call the service.

    The following is a complete code sample for calling and obtaining results. You can obtain the full path of the output image from data[prompt_id]["outputs"]["fullpath"] in the final result.

    The sample code gets the endpoint and token from environment variables. Run the following commands in the terminal to add temporary environment variables (only effective in the current session):

    # Set your endpoint and token. 
    
    export SERVICE_URL="http://test****.115770327099****.cn-beijing.pai-eas.aliyuncs.com/"
    export TOKEN="MzJlMDNjMmU3YzQ0ZDJ*****************TMxZA=="

    Complete I2V calling code

    from time import sleep
    
    import os
    import json
    import requests
    
    service_url     = os.getenv("SERVICE_URL")
    token           = os.getenv("TOKEN")
    image_url       = "https://pai-aigc-photog.oss-cn-hangzhou.aliyuncs.com/wan_fun/asset/3.png"
    prompt          = "A blonde woman with her head tilted back and eyes closed, her expression serene and dreamy. Her hair is very long and fluffy, showing natural waves as if blown by the wind. In the background, some blurred flowers are falling, creating a romantic and dreamy atmosphere. She is wearing a top with lace decorations, and the color of her clothes coordinates with the background, with an overall soft tone. Light shines down from above, illuminating her face and hair, making the entire image appear very soft and warm."
    negative_prompt = "Vibrant color tones, overexposure, static, blurry details, captions, style, artwork, painting, image, still, overall grayness, worst quality, low quality, JPEG compression artifacts, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn face, deformed, disfigured, deformed limbs, finger fusion, static image, messy background, three legs, many people in the background, walking backwards"
    height          = 720
    width           = 1280
    steps           = 40
    num_frames      = 81
    
    if service_url[-1] == "/":
        service_url = service_url[:-1]
    
    prompt_url = f"{service_url}/prompt"
    
    # Please configure the value of prompt in the payload as the content of the JSON file corresponding to the workflow.
    payload = """
    {
        "prompt":
        {
            "11": {
                "inputs": {
                "model_name": "umt5-xxl-enc-bf16.safetensors",
                "precision": "bf16",
                "load_device": "offload_device",
                "quantization": "disabled"
                },
                "class_type": "LoadWanVideoT5TextEncoder",
                "_meta": {
                "title": "Load WanVideo T5 TextEncoder"
                }
            },
            "16": {
                "inputs": {
                "positive_prompt": "A blonde woman with her head tilted back and eyes closed, her expression serene and dreamy. Her hair is very long and fluffy, showing natural waves as if blown by the wind. In the background, some blurred flowers are falling, creating a romantic and dreamy atmosphere. She is wearing a top with lace decorations, and the color of her clothes coordinates with the background, with an overall soft tone. Light shines down from above, illuminating her face and hair, making the entire image appear very soft and warm.",
                "negative_prompt": "Vibrant color tones, overexposure, static, blurry details, captions, style, artwork, painting, image, still, overall grayness, worst quality, low quality, JPEG compression artifacts, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn face, deformed, disfigured, deformed limbs, finger fusion, static image, messy background, three legs, many people in the background, walking backwards",
                "force_offload": true,
                "speak_and_recognation": {
                    "__value__": [
                    false,
                    true
                    ]
                },
                "t5": [
                    "11",
                    0
                ],
                "model_to_offload": [
                    "22",
                    0
                ]
                },
                "class_type": "WanVideoTextEncode",
                "_meta": {
                "title": "WanVideo TextEncode"
                }
            },
            "22": {
                "inputs": {
                "model": "WanVideo/wan2.1_i2v_720p_14B_bf16.safetensors",
                "base_precision": "fp16",
                "quantization": "fp8_e4m3fn",
                "load_device": "offload_device",
                "attention_mode": "sageattn",
                "compile_args": [
                    "35",
                    0
                ]
                },
                "class_type": "WanVideoModelLoader",
                "_meta": {
                "title": "WanVideo Model Loader"
                }
            },
            "27": {
                "inputs": {
                "steps": 40,
                "cfg": 6,
                "shift": 5,
                "seed": 1057359483639287,
                "force_offload": true,
                "scheduler": "unipc",
                "riflex_freq_index": 0,
                "denoise_strength": 1,
                "batched_cfg": "",
                "rope_function": "comfy",
                "nocfg_begin": 0.7500000000000001,
                "nocfg_end": 1,
                "model": [
                    "22",
                    0
                ],
                "text_embeds": [
                    "16",
                    0
                ],
                "image_embeds": [
                    "63",
                    0
                ],
                "teacache_args": [
                    "52",
                    0
                ]
                },
                "class_type": "WanVideoSampler",
                "_meta": {
                "title": "WanVideo Sampler"
                }
            },
            "28": {
                "inputs": {
                "enable_vae_tiling": false,
                "tile_x": 272,
                "tile_y": 272,
                "tile_stride_x": 144,
                "tile_stride_y": 128,
                "vae": [
                    "38",
                    0
                ],
                "samples": [
                    "27",
                    0
                ]
                },
                "class_type": "WanVideoDecode",
                "_meta": {
                "title": "WanVideo Decode"
                }
            },
            "30": {
                "inputs": {
                "frame_rate": 16,
                "loop_count": 0,
                "filename_prefix": "WanVideoWrapper_I2V",
                "format": "video/h264-mp4",
                "pix_fmt": "yuv420p",
                "crf": 19,
                "save_metadata": true,
                "trim_to_audio": false,
                "pingpong": false,
                "save_output": true,
                "images": [
                    "28",
                    0
                ]
                },
                "class_type": "VHS_VideoCombine",
                "_meta": {
                "title": "Merge to video"
                }
            },
            "35": {
                "inputs": {
                "backend": "inductor",
                "fullgraph": false,
                "mode": "default",
                "dynamic": false,
                "dynamo_cache_size_limit": 64,
                "compile_transformer_blocks_only": true
                },
                "class_type": "WanVideoTorchCompileSettings",
                "_meta": {
                "title": "WanVideo Torch Compile Settings"
                }
            },
            "38": {
                "inputs": {
                "model_name": "WanVideo/Wan2_1_VAE_bf16.safetensors",
                "precision": "bf16"
                },
                "class_type": "WanVideoVAELoader",
                "_meta": {
                "title": "WanVideo VAE Loader"
                }
            },
            "52": {
                "inputs": {
                "rel_l1_thresh": 0.25,
                "start_step": 1,
                "end_step": -1,
                "cache_device": "offload_device",
                "use_coefficients": "true"
                },
                "class_type": "WanVideoTeaCache",
                "_meta": {
                "title": "WanVideo TeaCache"
                }
            },
            "59": {
                "inputs": {
                "clip_name": "wanx_clip_vision_h.safetensors"
                },
                "class_type": "CLIPVisionLoader",
                "_meta": {
                "title": "CLIP Vision Loader"
                }
            },
            "63": {
                "inputs": {
                "width": [
                    "66",
                    1
                ],
                "height": [
                    "66",
                    2
                ],
                "num_frames": 81,
                "noise_aug_strength": 0.030000000000000006,
                "start_latent_strength": 1,
                "end_latent_strength": 1,
                "force_offload": true,
                "start_image": [
                    "66",
                    0
                ],
                "vae": [
                    "38",
                    0
                ],
                "clip_embeds": [
                    "65",
                    0
                ]
                },
                "class_type": "WanVideoImageToVideoEncode",
                "_meta": {
                "title": "WanVideo ImageToVideo Encode"
                }
            },
            "65": {
                "inputs": {
                "strength_1": 1,
                "strength_2": 1,
                "crop": "center",
                "combine_embeds": "average",
                "force_offload": true,
                "tiles": 4,
                "ratio": 0.20000000000000004,
                "clip_vision": [
                    "59",
                    0
                ],
                "image_1": [
                    "66",
                    0
                ]
                },
                "class_type": "WanVideoClipVisionEncode",
                "_meta": {
                "title": "WanVideo ClipVision Encode"
                }
            },
            "66": {
                "inputs": {
                "width": 832,
                "height": 480,
                "upscale_method": "lanczos",
                "keep_proportion": false,
                "divisible_by": 16,
                "crop": "disabled",
                "image": [
                    "68",
                    0
                ]
                },
                "class_type": "ImageResizeKJ",
                "_meta": {
                "title": "Image Resize (KJ)"
                }
            },
            "68": {
                "inputs": {
                "url": "https://pai-aigc-photog.oss-cn-hangzhou.aliyuncs.com/wan_fun/asset/3.png",
                "cache": true
                },
                "class_type": "LoadImageByUrl //Browser",
                "_meta": {
                "title": "Load Image By URL"
                }
            }
        }
    }
    """
    
    session = requests.session()
    session.headers.update({"Authorization":token})
    
    payload = json.loads(payload)
    payload["prompt"]["16"]["inputs"]["positive_prompt"] = prompt
    payload["prompt"]["16"]["inputs"]["negative_prompt"] = negative_prompt
    payload["prompt"]["27"]["inputs"]["steps"] = steps
    payload["prompt"]["66"]["inputs"]["height"] = height
    payload["prompt"]["66"]["inputs"]["width"] = width
    payload["prompt"]["63"]["inputs"]["num_frames"] = num_frames
    payload["prompt"]["68"]["inputs"]["url"] = image_url
    
    response = session.post(url=f'{prompt_url}', json=payload)
    if response.status_code != 200:
        raise Exception(response.content)
    
    data = response.json()
    prompt_id = data["prompt_id"]
    print(data)
    
    while 1:
        url = f"{service_url}/history/{prompt_id}"
    
        response = session.get(url=f'{url}')
    
        if response.status_code != 200:
            raise Exception(response.content)
       
        data = response.json()
        if len(data) != 0:
            print(data[prompt_id]["outputs"])
            if len(data[prompt_id]["outputs"]) == 0:
                print("Find no outputs key in output json, the process may be failed, please check the log")
            break
        else:
            sleep(1)
    

    Step-by-step explanation of the above code

    • Send a POST request and get the Prompt ID from the returned result.

      import requests
      import os
      
      service_url = os.getenv("SERVICE_URL")
      token = os.getenv("TOKEN")
      url = f"{service_url}/prompt"
      
      payload = {
          "prompt":
          Request body... 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)

      Where, payload is the request body, the value of prompt is the request JSON obtained from the above Export (API). In Python requests, Boolean values (True and False) in the request body need to have their first letter capitalized.

      The response of the first request is:

      {
          "prompt_id": "021ebc5b-e245-4e37-8bd3-00f7b949****",
          "number": 5,
          "node_errors": {}
      }
    • Get the final result based on the Prompt ID.

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

      Replace <prompt_id> with the prompt_id in the previous step.

      The following response is returned:

      {
          "130bcd6b-5bb5-496c-9c8c-3a1359a0****": {
              "prompt": ... omitted,
              "outputs": {
                  "30": {
                    'gifs': [
                      {
                        'filename': 'WanVideo2_1_T2V_00002.mp4', 
                        'subfolder': '', 
                        'type': 'output', 
                        'format': 'video/h264-mp4', 
                        'frame_rate': 16.0, 'workflow': 
                        'WanVideo2_1_T2V_00002.png', 'fullpath': 
                        '/code/data-oss/output/WanVideo2_1_T2V_00002.mp4'
                      }
                    ]
                  }
              },
              "status": {
                  "status_str": "success",
                  "completed": true,
                  "messages": ... omitted,
              }
          }
      }

Deploy ComfyUI API service (high concurrency scenarios)

Deploy the service

Note

If you have already created a standard service and want to change it to the API version, we recommend that you delete the original service and create a new API version instead.

Use the custom deployment method to deploy the ComfyUI API service. Perform the following steps:

  1. Log on to the PAI console. Select a region on the top of the page. Then, select the desired workspace and click Elastic Algorithm Service (EAS).

  2. Click Deploy Service. In the Custom Model Deployment section, click Custom Deployment.

  3. On the Custom Deployment page, configure the following parameters.

    1. In the Environment Information section:

      Parameter

      Description

      Image Configuration

      Select comfyui > comfyui:1.9-api from the Aibaba Cloud Images list.

      Note

      1.9 is the image version. Due to rapid version iterations, you can just select the latest version when deploying.

      Model Settings

      Mount an external storage (such as OSS or NAS) for the service. The generated videos will be automatically saved to the corresponding data source. Take OSS as an example, set the following parameters:

      • Uri: Select an OSS bucket directory. For more information about how to create a bucket and directory, see Get started with the OSS console. Make sure that your bucket is in the same region as the EAS service.

      • Mount Path: The destination path in the service instance. For example, /code/data-oss.

      Command

      After you select an image, the system automatically sets this parameter.

      After you complete the model settings, set the --data-dir mount directory in Command and make sure that the mount directory is the same as the mount path in model settings.

      For the image version 1.9, --data-dir is preconfigured. You only need to update it to the mount path in model settings. For example, python main.py --listen --port 8000 --api --data-dir /code/data-oss.

    2. In the Resource Information section, select the resource specifications.

      Parameter

      Description

      Resource Type

      Select Public Resources.

      Deployment Resources

      Select Resource Type. Because video generation requires more GPU video memory than image generation, we recommend a type with GPU memory of no less than 48 GB per card, such as the GU60 types (for example, ml.gu8is.c16m128.1-gu60).

    3. In the Asynchronous Queue section, set Maximum Data for A Single Input Request and Maximum Data for A Single Output. The standard value is 1024 KB.

      Note

      Set the data size appropriately to avoid request rejection, sample loss, response failure, or queue blocking due to exceeding the limit.

    4. In the Network information section, set a VPC with Internet access, including the VPC, vSwitch, and Security Group parameters. For more information, see Configure Internet access for VPC.

      Note

      The EAS service does not have Internet access by default. However, because the I2V function needs to download images from the internet, a VPC with Internet access is required.

  4. After you configure the parameters, click Deploy.

Asynchronous API call

The API service only supports asynchronous calling and the api_prompt path. Asynchronous calling means using the EAS queue service to send requests to the input queue and obtain results through subscription. Perform the following steps:

  1. View the endpoint information.

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

    Note
    • To use the Internet endpoint: the client must support access to the Internet.

    • To use the VPC endpoint: the client must be in the same VPC as the service.

    image

  2. Run the following command in the terminal to install the eas_prediction SDK.

    pip install eas_prediction  --user
  3. Call the service.

    The following is a complete code sample. You can obtain the full path of the output image from json.loads(x.data.decode('utf-8'))[1]["data"]["output"]["gifs"][0]["fullpath"] in the final result.

    The sample code gets the endpoint and token from environment variables. Run the following commands in the terminal to add temporary environment variables (only effective in the current session):

    # Set your endpoint and token. 
    
    export SERVICE_URL="http://test****.115770327099****.cn-beijing.pai-eas.aliyuncs.com/"
    export TOKEN="MzJlMDNjMmU3YzQ0ZDJ*****************TMxZA=="

    Complete I2V calling code

    import json
    import os
    import requests
    from urllib.parse import urlparse, urlunparse
    from eas_prediction import QueueClient
    
    service_url     = os.getenv("SERVICE_URL")
    token           = os.getenv("TOKEN")
    
    image_url       = "https://pai-aigc-photog.oss-cn-hangzhou.aliyuncs.com/wan_fun/asset/3.png"
    prompt          = "A blonde woman with her head tilted back and eyes closed, her expression serene and dreamy. Her hair is very long and fluffy, showing natural waves as if blown by the wind. In the background, some blurred flowers are falling, creating a romantic and dreamy atmosphere. She is wearing a top with lace decorations, and the color of her clothes coordinates with the background, with an overall soft tone. Light shines down from above, illuminating her face and hair, making the entire image appear very soft and warm."
    negative_prompt = "Vibrant color tones, overexposure, static, blurry details, captions, style, artwork, painting, image, still, overall grayness, worst quality, low quality, JPEG compression artifacts, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn face, deformed, disfigured, deformed limbs, finger fusion, static image, messy background, three legs, many people in the background, walking backwards"
    height          = 720
    width           = 1280
    steps           = 40
    num_frames      = 81
    
    if service_url[-1] == "/":
        service_url = service_url[:-1]
    
    
    def parse_service_url(service_url):
        parsed = urlparse(service_url)
        service_domain = f"{parsed.scheme}://{parsed.netloc}"
        path_parts = [p for p in parsed.path.strip('/').split('/') if p]
        service_name = path_parts[-1]
        return service_domain, service_name
    
    
    service_domain, service_name = parse_service_url(service_url)
    print(f"service_domain: {service_domain}, service_name: {service_name}.")
    
    # Please configure the payload as the content of the JSON file corresponding to the workflow.
    payload = """
    {
        "11": {
            "inputs": {
            "model_name": "umt5-xxl-enc-bf16.safetensors",
            "precision": "bf16",
            "load_device": "offload_device",
            "quantization": "disabled"
            },
            "class_type": "LoadWanVideoT5TextEncoder",
            "_meta": {
            "title": "Load WanVideo T5 TextEncoder"
            }
        },
        "16": {
            "inputs": {
            "positive_prompt": "A blonde woman with her head tilted back and eyes closed, her expression serene and dreamy. Her hair is very long and fluffy, showing natural waves as if blown by the wind. In the background, some blurred flowers are falling, creating a romantic and dreamy atmosphere. She is wearing a top with lace decorations, and the color of her clothes coordinates with the background, with an overall soft tone. Light shines down from above, illuminating her face and hair, making the entire image appear very soft and warm.",
            "negative_prompt": "Vibrant color tones, overexposure, static, blurry details, captions, style, artwork, painting, image, still, overall grayness, worst quality, low quality, JPEG compression artifacts, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn face, deformed, disfigured, deformed limbs, finger fusion, static image, messy background, three legs, many people in the background, walking backwards",
            "force_offload": true,
            "speak_and_recognation": {
                "__value__": [
                false,
                true
                ]
            },
            "t5": [
                "11",
                0
            ],
            "model_to_offload": [
                "22",
                0
            ]
            },
            "class_type": "WanVideoTextEncode",
            "_meta": {
            "title": "WanVideo TextEncode"
            }
        },
        "22": {
            "inputs": {
            "model": "WanVideo/wan2.1_i2v_720p_14B_bf16.safetensors",
            "base_precision": "fp16",
            "quantization": "fp8_e4m3fn",
            "load_device": "offload_device",
            "attention_mode": "sageattn",
            "compile_args": [
                "35",
                0
            ]
            },
            "class_type": "WanVideoModelLoader",
            "_meta": {
            "title": "WanVideo Model Loader"
            }
        },
        "27": {
            "inputs": {
            "steps": 40,
            "cfg": 6,
            "shift": 5,
            "seed": 1057359483639287,
            "force_offload": true,
            "scheduler": "unipc",
            "riflex_freq_index": 0,
            "denoise_strength": 1,
            "batched_cfg": "",
            "rope_function": "comfy",
            "nocfg_begin": 0.7500000000000001,
            "nocfg_end": 1,
            "model": [
                "22",
                0
            ],
            "text_embeds": [
                "16",
                0
            ],
            "image_embeds": [
                "63",
                0
            ],
            "teacache_args": [
                "52",
                0
            ]
            },
            "class_type": "WanVideoSampler",
            "_meta": {
            "title": "WanVideo Sampler"
            }
        },
        "28": {
            "inputs": {
            "enable_vae_tiling": false,
            "tile_x": 272,
            "tile_y": 272,
            "tile_stride_x": 144,
            "tile_stride_y": 128,
            "vae": [
                "38",
                0
            ],
            "samples": [
                "27",
                0
            ]
            },
            "class_type": "WanVideoDecode",
            "_meta": {
            "title": "WanVideo Decode"
            }
        },
        "30": {
            "inputs": {
            "frame_rate": 16,
            "loop_count": 0,
            "filename_prefix": "WanVideoWrapper_I2V",
            "format": "video/h264-mp4",
            "pix_fmt": "yuv420p",
            "crf": 19,
            "save_metadata": true,
            "trim_to_audio": false,
            "pingpong": false,
            "save_output": true,
            "images": [
                "28",
                0
            ]
            },
            "class_type": "VHS_VideoCombine",
            "_meta": {
            "title": "Merge to video"
            }
        },
        "35": {
            "inputs": {
            "backend": "inductor",
            "fullgraph": false,
            "mode": "default",
            "dynamic": false,
            "dynamo_cache_size_limit": 64,
            "compile_transformer_blocks_only": true
            },
            "class_type": "WanVideoTorchCompileSettings",
            "_meta": {
            "title": "WanVideo Torch Compile Settings"
            }
        },
        "38": {
            "inputs": {
            "model_name": "WanVideo/Wan2_1_VAE_bf16.safetensors",
            "precision": "bf16"
            },
            "class_type": "WanVideoVAELoader",
            "_meta": {
            "title": "WanVideo VAE Loader"
            }
        },
        "52": {
            "inputs": {
            "rel_l1_thresh": 0.25,
            "start_step": 1,
            "end_step": -1,
            "cache_device": "offload_device",
            "use_coefficients": "true"
            },
            "class_type": "WanVideoTeaCache",
            "_meta": {
            "title": "WanVideo TeaCache"
            }
        },
        "59": {
            "inputs": {
            "clip_name": "wanx_clip_vision_h.safetensors"
            },
            "class_type": "CLIPVisionLoader",
            "_meta": {
            "title": "CLIP Vision Loader"
            }
        },
        "63": {
            "inputs": {
            "width": [
                "66",
                1
            ],
            "height": [
                "66",
                2
            ],
            "num_frames": 81,
            "noise_aug_strength": 0.030000000000000006,
            "start_latent_strength": 1,
            "end_latent_strength": 1,
            "force_offload": true,
            "start_image": [
                "66",
                0
            ],
            "vae": [
                "38",
                0
            ],
            "clip_embeds": [
                "65",
                0
            ]
            },
            "class_type": "WanVideoImageToVideoEncode",
            "_meta": {
            "title": "WanVideo ImageToVideo Encode"
            }
        },
        "65": {
            "inputs": {
            "strength_1": 1,
            "strength_2": 1,
            "crop": "center",
            "combine_embeds": "average",
            "force_offload": true,
            "tiles": 4,
            "ratio": 0.20000000000000004,
            "clip_vision": [
                "59",
                0
            ],
            "image_1": [
                "66",
                0
            ]
            },
            "class_type": "WanVideoClipVisionEncode",
            "_meta": {
            "title": "WanVideo ClipVision Encode"
            }
        },
        "66": {
            "inputs": {
            "width": 832,
            "height": 480,
            "upscale_method": "lanczos",
            "keep_proportion": false,
            "divisible_by": 16,
            "crop": "disabled",
            "image": [
                "68",
                0
            ]
            },
            "class_type": "ImageResizeKJ",
            "_meta": {
            "title": "Image Resize (KJ)"
            }
        },
        "68": {
            "inputs": {
            "url": "https://pai-aigc-photog.oss-cn-hangzhou.aliyuncs.com/wan_fun/asset/3.png",
            "cache": true
            },
            "class_type": "LoadImageByUrl //Browser",
            "_meta": {
            "title": "Load Image By URL"
            }
        }
    }
    """
    
    
    session = requests.session()
    session.headers.update({"Authorization":token})
    
    payload = json.loads(payload)
    payload["16"]["inputs"]["positive_prompt"] = prompt
    payload["16"]["inputs"]["negative_prompt"] = negative_prompt
    payload["27"]["inputs"]["steps"] = steps
    payload["66"]["inputs"]["height"] = height
    payload["66"]["inputs"]["width"] = width
    payload["63"]["inputs"]["num_frames"] = num_frames
    payload["68"]["inputs"]["url"] = image_url
    
    response = session.post(url=f'{service_url}/api_prompt?task_id=txt2img', json=payload)
    if response.status_code != 200:
        raise Exception(response.content)
    
    data = response.json()
    sink_queue = QueueClient(service_domain, f'{service_name}/sink')
    sink_queue.set_token(token)
    sink_queue.init()
    
    watcher = sink_queue.watch(0, 1, 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}')
        print(json.loads(x.data.decode('utf-8'))[1]["data"]["output"]["gifs"][0]["fullpath"])
        sink_queue.commit(x.index)

    Step-by-step explanation of the above code

    • Send a request:

      import requests, io, base64, os
      from PIL import Image, PngImagePlugin
      
      url = os.getenv("SERVICE_URL")
      token = os.getenv("TOKEN")
      session = requests.session()
      session.headers.update({"Authorization": token})
      
      work_flow = {
          '3':
          ... omitted
      }  # Different from the Standard Edition, there is no prompt key
      
      for i in range(1):
          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}")
      

      Where, work_flow is the request body, which is the request JSON obtained from the above Export (API). In Python requests, Boolean values (True and False) in the request body need to have their first letter capitalized.

    • Subscribe to results:

      from eas_prediction import QueueClient
      import os
      
      token = os.getenv("TOKEN")
      sink_queue = QueueClient('<service_domain>', '<service_name>/sink')
      sink_queue.set_token(token)
      sink_queue.init()
      
      watcher = sink_queue.watch(0, 1, 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)
      

      Key configuration items:

      Item

      Description

      <service_domain>

      Replace with the obtained endpoint. For example, 139699392458****.cn-hangzhou.pai-eas.aliyuncs.com.

      <service_name>

      Replace with the name of the service.

      A command output similar to the following one is returned:

      index 2 task_id is txt2img
      index 2 data is b'[{"status_code": 200}, {"type": "executed", "data": {"node": "30", "display_node": "30", "output": {"gifs": [{"filename": "WanVideoWrapper_I2V_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4", "frame_rate": 16.0, "workflow": "WanVideoWrapper_I2V_00001.png", "fullpath": "/code/data-oss/output/WanVideoWrapper_I2V_00001.mp4"}]}, "prompt_id": "e20b1cb0-fb48-4ddd-92e5-3c783b064a2c"}}, {"e20b1cb0-fb48-4ddd-92e5-3c783b064a2c": {"prompt": [1, "e20b1cb0-fb48-4ddd-92e5-3c783b064a2c", {"11": {"inputs": {"model_name": "umt5-xxl-enc-bf16.safetensors", "precision": "bf16", "load_device": "offload_device", "quantization": "disabled"}, "class_type": "LoadWanVideoT5TextEncoder", "_meta": {"title": "Load WanVideo T5 TextEncoder"}}, "16": {"inputs": {"positive_prompt": "\\u4e00\\u4f4d\\u91d1\\u53d1\\u5973\\u5b50\\uff0c\\u5979\\u4ef0\\u5934\\u95ed\\u773c\\uff0c\\u8868\\u60c5\\u5b81\\u9759\\u800c\\u68a6\\u5e7b\\u3002\\u5979\\u7684\\u5934\\u53d1\\u975e\\u5e38\\u957f\\u4e14\\u84ec\\u677e\\uff0c\\u5448\\u73b0\\u51fa\\u81ea\\u7136\\u7684\\u6ce2\\u6d6a\\u72b6\\uff0c\\u4eff\\u4f5b\\u88ab\\u98ce\\u5439\\u62c2\\u3002\\u80cc\\u666f\\u4e2d\\u6709\\u4e00\\u4e9b\\u6a21\\u7cca\\u7684\\u82b1\\u6735\\u98d8\\u843d\\uff0c\\u8425\\u9020\\u51fa\\u4e00\\u79cd\\u6d6a\\u6f2b\\u548c\\u68a6\\u5e7b\\u7684\\u6c1b\\u56f4\\u3002\\u5979\\u7a7f\\u7740\\u4e00\\u4ef6\\u5e26\\u6709\\u857e\\u4e1d\\u88c5\\u9970\\u7684\\u4e0a\\u8863\\uff0c\\u8863\\u670d\\u7684\\u989c\\u8272\\u4e0e\\u80cc\\u666f\\u76f8\\u534f\\u8c03\\uff0c\\u6574\\u4f53\\u8272\\u8c03\\u67d4\\u548c\\u3002\\u5149\\u7ebf\\u4ece\\u4e0a\\u65b9\\u7167\\u5c04\\u4e0b\\u6765\\uff0c\\u7167\\u4eae\\u4e86\\u5979\\u7684\\u8138\\u5e9e\\u548c\\u5934\\u53d1\\uff0c\\u4f7f\\u6574\\u4e2a\\u753b\\u9762\\u663e\\u5f97\\u975e\\u5e38\\u67d4\\u548c\\u548c\\u6e29\\u6696\\u3002", "negative_prompt": "\\u8272\\u8c03\\u8273\\u4e3d\\uff0c\\u8fc7\\u66dd\\uff0c\\u9759\\u6001\\uff0c\\u7ec6\\u8282\\u6a21\\u7cca\\u4e0d\\u6e05\\uff0c\\u5b57\\u5e55\\uff0c\\u98ce\\u683c\\uff0c\\u4f5c\\u54c1\\uff0c\\u753b\\u4f5c\\uff0c\\u753b\\u9762\\uff0c\\u9759\\u6b62\\uff0c\\u6574\\u4f53\\u53d1\\u7070\\uff0c\\u6700\\u5dee\\u8d28\\u91cf\\uff0c\\u4f4e\\u8d28\\u91cf\\uff0cJPEG\\u538b\\u7f29\\u6b8b\\u7559\\uff0c\\u4e11\\u964b\\u7684\\uff0c\\u6b8b\\u7f3a\\u7684\\uff0c\\u591a\\u4f59\\u7684\\u624b\\u6307\\uff0c\\u753b\\u5f97\\u4e0d\\u597d\\u7684\\u624b\\u90e8\\uff0c\\u753b\\u5f97\\u4e0d\\u597d\\u7684\\u8138\\u90e8\\uff0c\\u7578\\u5f62\\u7684\\uff0c\\u6bc1\\u5bb9\\u7684\\uff0c\\u5f62\\u6001\\u7578\\u5f62\\u7684\\u80a2\\u4f53\\uff0c\\u624b\\u6307\\u878d\\u5408\\uff0c\\u9759\\u6b62\\u4e0d\\u52a8\\u7684\\u753b\\u9762\\uff0c\\u6742\\u4e71\\u7684\\u80cc\\u666f\\uff0c\\u4e09\\u6761\\u817f\\uff0c\\u80cc\\u666f\\u4eba\\u5f88\\u591a\\uff0c\\u5012\\u7740\\u8d70", "force_offload": true, "speak_and_recognation": {"__value__": [false, true]}, "t5": ["11", 0], "model_to_offload": ["22", 0]}, "class_type": "WanVideoTextEncode", "_meta": {"title": "WanVideo TextEncode"}}, "22": {"inputs": {"model": "WanVideo/wan2.1_i2v_720p_14B_bf16.safetensors", "base_precision": "fp16", "quantization": "fp8_e4m3fn", "load_device": "offload_device", "attention_mode": "sageattn", "compile_args": ["35", 0]}, "class_type": "WanVideoModelLoader", "_meta": {"title": "WanVideo Model Loader"}}, "27": {"inputs": {"steps": 40, "cfg": 6.0, "shift": 5.0, "seed": 1057359483639287, "force_offload": true, "scheduler": "unipc", "riflex_freq_index": 0, "denoise_strength": 1.0, "batched_cfg": false, "rope_function": "comfy", "nocfg_begin": 0.7500000000000001, "nocfg_end": 1.0, "model": ["22", 0], "text_embeds": ["16", 0], "image_embeds": ["63", 0], "teacache_args": ["52", 0]}, "class_type": "WanVideoSampler", "_meta": {"title": "WanVideo Sampler"}}, "28": {"inputs": {"enable_vae_tiling": false, "tile_x": 272, "tile_y": 272, "tile_stride_x": 144, "tile_stride_y": 128, "vae": ["38", 0], "samples": ["27", 0]}, "class_type": "WanVideoDecode", "_meta": {"title": "WanVideo Decode"}}, "30": {"inputs": {"frame_rate": 16.0, "loop_count": 0, "filename_prefix": "WanVideoWrapper_I2V", "format": "video/h264-mp4", "pix_fmt": "yuv420p", "crf": 19, "save_metadata": true, "trim_to_audio": false, "pingpong": false, "save_output": true, "images": ["28", 0]}, "class_type": "VHS_VideoCombine", "_meta": {"title": "\\u5408\\u5e76\\u4e3a\\u89c6\\u9891"}}, "35": {"inputs": {"backend": "inductor", "fullgraph": false, "mode": "default", "dynamic": false, "dynamo_cache_size_limit": 64, "compile_transformer_blocks_only": true}, "class_type": "WanVideoTorchCompileSettings", "_meta": {"title": "WanVideo Torch Compile Settings"}}, "38": {"inputs": {"model_name": "WanVideo/Wan2_1_VAE_bf16.safetensors", "precision": "bf16"}, "class_type": "WanVideoVAELoader", "_meta": {"title": "WanVideo VAE Loader"}}, "52": {"inputs": {"rel_l1_thresh": 0.25, "start_step": 1, "end_step": -1, "cache_device": "offload_device", "use_coefficients": true}, "class_type": "WanVideoTeaCache", "_meta": {"title": "WanVideo TeaCache"}}, "59": {"inputs": {"clip_name": "wanx_clip_vision_h.safetensors"}, "class_type": "CLIPVisionLoader", "_meta": {"title": "CLIP\\u89c6\\u89c9\\u52a0\\u8f7d\\u5668"}}, "63": {"inputs": {"width": ["66", 1], "height": ["66", 2], "num_frames": 81, "noise_aug_strength": 0.030000000000000006, "start_latent_strength": 1.0, "end_latent_strength": 1.0, "force_offload": true, "start_image": ["66", 0], "vae": ["38", 0], "clip_embeds": ["65", 0]}, "class_type": "WanVideoImageToVideoEncode", "_meta": {"title": "WanVideo ImageToVideo Encode"}}, "65": {"inputs": {"strength_1": 1.0, "strength_2": 1.0, "crop": "center", "combine_embeds": "average", "force_offload": true, "tiles": 4, "ratio": 0.20000000000000004, "clip_vision": ["59", 0], "image_1": ["66", 0]}, "class_type": "WanVideoClipVisionEncode", "_meta": {"title": "WanVideo ClipVision Encode"}}, "66": {"inputs": {"width": 1280, "height": 720, "upscale_method": "lanczos", "keep_proportion": false, "divisible_by": 16, "crop": "disabled", "image": ["68", 0]}, "class_type": "ImageResizeKJ", "_meta": {"title": "\\u56fe\\u50cf\\u7f29\\u653e\\uff08KJ\\uff09"}}, "68": {"inputs": {"url": "https://pai-aigc-photog.oss-cn-hangzhou.aliyuncs.com/wan_fun/asset/3.png", "cache": true}, "class_type": "LoadImageByUrl //Browser", "_meta": {"title": "Load Image By URL"}}}, {"client_id": "unknown"}, ["30"]], "outputs": {"30": {"gifs": [{"filename": "WanVideoWrapper_I2V_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4", "frame_rate": 16.0, "workflow": "WanVideoWrapper_I2V_00001.png", "fullpath": "/code/data-oss/output/WanVideoWrapper_I2V_00001.mp4"}]}}, "status": {"status_str": "success", "completed": true, "messages": [["execution_start", {"prompt_id": "e20b1cb0-fb48-4ddd-92e5-3c783b064a2c", "timestamp": 1746512702895}], ["execution_cached", {"nodes": ["11", "16", "22", "27", "28", "30", "35", "38", "52", "59", "63", "65", "66", "68"], "prompt_id": "e20b1cb0-fb48-4ddd-92e5-3c783b064a2c", "timestamp": 1746512702899}], ["execution_success", {"prompt_id": "e20b1cb0-fb48-4ddd-92e5-3c783b064a2c", "timestamp": 1746512702900}]]}, "meta": {"30": {"node_id": "30", "display_node": "30", "parent_node": null, "real_node_id": "30"}}}}, {"30": {"gifs": [{"filename": "WanVideoWrapper_I2V_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4", "frame_rate": 16.0, "workflow": "WanVideoWrapper_I2V_00001.png", "fullpath": "/code/data-oss/output/WanVideoWrapper_I2V_00001.mp4"}]}}]'

Appendix: More examples

The usage process for T2V is the same as that of I2V. You can refer to the steps above to deploy and call the service. However, T2V does not require Internet access, so you do not need to configure a VPC when deploying the EAS service.

You can experience the WebUI calling process through the sample workflow file (wanvideo_720P_T2V.json). Load the workflow on the WebUI page, then enter the prompt in the WanVideo TextEncode input box. Click Run to start.imageTo call through the API, Here are code samples:

The sample code gets the endpoint and token from environment variables. Run the following commands in the terminal to add temporary environment variables (only effective in the current session):

# Set your endpoint and token. 

export SERVICE_URL="http://test****.115770327099****.cn-beijing.pai-eas.aliyuncs.com/"
export TOKEN="MzJlMDNjMmU3YzQ0ZDJ*****************TMxZA=="

Synchronous API call

Complete T2V calling code

from time import sleep

import os
import json
import requests

service_url     = os.getenv("SERVICE_URL")
token           = os.getenv("TOKEN")
prompt          = "A blonde woman with her head tilted back and eyes closed, her expression serene and dreamy. Her hair is very long and fluffy, showing natural waves as if blown by the wind. In the background, some blurred flowers are falling, creating a romantic and dreamy atmosphere. She is wearing a top with lace decorations, and the color of her clothes coordinates with the background, with an overall soft tone. Light shines down from above, illuminating her face and hair, making the entire image appear very soft and warm."
negative_prompt = "Vibrant color tones, overexposure, static, blurry details, captions, style, artwork, painting, image, still, overall grayness, worst quality, low quality, JPEG compression artifacts, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn face, deformed, disfigured, deformed limbs, finger fusion, static image, messy background, three legs, many people in the background, walking backwards"
height          = 720
width           = 1280
steps           = 40
num_frames      = 81

if service_url[-1] == "/":
    service_url = service_url[:-1]

prompt_url = f"{service_url}/prompt"

# Please configure the value of prompt in the payload as the content of the JSON file corresponding to the workflow.
payload = """
{
    "prompt":
    {
        "11": {
            "inputs": {
            "model_name": "umt5-xxl-enc-bf16.safetensors",
            "precision": "bf16",
            "load_device": "offload_device",
            "quantization": "disabled"
            },
            "class_type": "LoadWanVideoT5TextEncoder",
            "_meta": {
            "title": "Load WanVideo T5 TextEncoder"
            }
        },
        "16": {
            "inputs": {
            "positive_prompt": "A blonde woman with her head tilted back and eyes closed, her expression serene and dreamy. Her hair is very long and fluffy, showing natural waves as if blown by the wind. In the background, some blurred flowers are falling, creating a romantic and dreamy atmosphere. She is wearing a top with lace decorations, and the color of her clothes coordinates with the background, with an overall soft tone. Light shines down from above, illuminating her face and hair, making the entire image appear very soft and warm.",
            "negative_prompt": "Vibrant color tones, overexposure, static, blurry details, captions, style, artwork, painting, image, still, overall grayness, worst quality, low quality, JPEG compression artifacts, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn face, deformed, disfigured, deformed limbs, finger fusion, static image, messy background, three legs, many people in the background, walking backwards",
            "force_offload": true,
            "speak_and_recognation": {
                "__value__": [
                false,
                true
                ]
            },
            "t5": [
                "11",
                0
            ]
            },
            "class_type": "WanVideoTextEncode",
            "_meta": {
            "title": "WanVideo TextEncode"
            }
        },
        "22": {
            "inputs": {
            "model": "WanVideo/wan2.1_t2v_14B_bf16.safetensors",
            "base_precision": "fp16",
            "quantization": "fp8_e4m3fn",
            "load_device": "offload_device",
            "attention_mode": "sageattn",
            "compile_args": [
                "35",
                0
            ]
            },
            "class_type": "WanVideoModelLoader",
            "_meta": {
            "title": "WanVideo Model Loader"
            }
        },
        "27": {
            "inputs": {
            "steps": 40,
            "cfg": 6.000000000000002,
            "shift": 5.000000000000001,
            "seed": 1057359483639287,
            "force_offload": true,
            "scheduler": "unipc",
            "riflex_freq_index": 0,
            "denoise_strength": 1,
            "batched_cfg": false,
            "rope_function": "default",
            "nocfg_begin": 0.7500000000000001,
            "nocfg_end": 1,
            "model": [
                "22",
                0
            ],
            "text_embeds": [
                "16",
                0
            ],
            "image_embeds": [
                "37",
                0
            ],
            "teacache_args": [
                "52",
                0
            ]
            },
            "class_type": "WanVideoSampler",
            "_meta": {
            "title": "WanVideo Sampler"
            }
        },
        "28": {
            "inputs": {
            "enable_vae_tiling": true,
            "tile_x": 272,
            "tile_y": 272,
            "tile_stride_x": 144,
            "tile_stride_y": 128,
            "vae": [
                "38",
                0
            ],
            "samples": [
                "27",
                0
            ]
            },
            "class_type": "WanVideoDecode",
            "_meta": {
            "title": "WanVideo Decode"
            }
        },
        "30": {
            "inputs": {
            "frame_rate": 16,
            "loop_count": 0,
            "filename_prefix": "WanVideo2_1_T2V",
            "format": "video/h264-mp4",
            "pix_fmt": "yuv420p",
            "crf": 19,
            "save_metadata": true,
            "trim_to_audio": false,
            "pingpong": false,
            "save_output": true,
            "images": [
                "28",
                0
            ]
            },
            "class_type": "VHS_VideoCombine",
            "_meta": {
            "title": "Merge to video"
            }
        },
        "35": {
            "inputs": {
            "backend": "inductor",
            "fullgraph": false,
            "mode": "default",
            "dynamic": false,
            "dynamo_cache_size_limit": 64,
            "compile_transformer_blocks_only": true
            },
            "class_type": "WanVideoTorchCompileSettings",
            "_meta": {
            "title": "WanVideo Torch Compile Settings"
            }
        },
        "37": {
            "inputs": {
            "width": 832,
            "height": 480,
            "num_frames": 81
            },
            "class_type": "WanVideoEmptyEmbeds",
            "_meta": {
            "title": "WanVideo Empty Embeds"
            }
        },
        "38": {
            "inputs": {
            "model_name": "WanVideo/Wan2_1_VAE_bf16.safetensors",
            "precision": "bf16"
            },
            "class_type": "WanVideoVAELoader",
            "_meta": {
            "title": "WanVideo VAE Loader"
            }
        },
        "52": {
            "inputs": {
            "rel_l1_thresh": 0.25000000000000006,
            "start_step": 1,
            "end_step": -1,
            "cache_device": "offload_device",
            "use_coefficients": "true"
            },
            "class_type": "WanVideoTeaCache",
            "_meta": {
            "title": "WanVideo TeaCache"
            }
        }
    }
}
"""

session = requests.session()
session.headers.update({"Authorization":token})

payload = json.loads(payload)
payload["prompt"]["16"]["inputs"]["positive_prompt"] = prompt
payload["prompt"]["16"]["inputs"]["negative_prompt"] = negative_prompt
payload["prompt"]["27"]["inputs"]["steps"] = steps
payload["prompt"]["37"]["inputs"]["height"] = height
payload["prompt"]["37"]["inputs"]["width"] = width
payload["prompt"]["37"]["inputs"]["num_frames"] = num_frames

response = session.post(url=f'{prompt_url}', json=payload)
if response.status_code != 200:
    raise Exception(response.content)

data = response.json()
prompt_id = data["prompt_id"]
print(data)

while 1:
    url = f"{service_url}/history/{prompt_id}"

    response = session.get(url=f'{url}')

    if response.status_code != 200:
        raise Exception(response.content)
    
    data = response.json()
    if len(data) != 0:
        print(data[prompt_id]["outputs"])
        if len(data[prompt_id]["outputs"]) == 0:
            print("Find no outputs key in output json, the process may be failed, please check the log")
        break
    else:
        sleep(1)

Asynchronous API call

Complete T2V calling code

import json
import os
import requests
from urllib.parse import urlparse, urlunparse
from eas_prediction import QueueClient

service_url     = os.getenv("SERVICE_URL")
token           = os.getenv("TOKEN")

prompt          = "A blonde woman with her head tilted back and eyes closed, her expression serene and dreamy. Her hair is very long and fluffy, showing natural waves as if blown by the wind. In the background, some blurred flowers are falling, creating a romantic and dreamy atmosphere. She is wearing a top with lace decorations, and the color of her clothes coordinates with the background, with an overall soft tone. Light shines down from above, illuminating her face and hair, making the entire image appear very soft and warm."
negative_prompt = "Vibrant color tones, overexposure, static, blurry details, captions, style, artwork, painting, image, still, overall grayness, worst quality, low quality, JPEG compression artifacts, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn face, deformed, disfigured, deformed limbs, finger fusion, static image, messy background, three legs, many people in the background, walking backwards"
height          = 720
width           = 1280
steps           = 40
num_frames      = 81

if service_url[-1] == "/":
    service_url = service_url[:-1]


def parse_service_url(service_url):
    parsed = urlparse(service_url)
    service_domain = f"{parsed.scheme}://{parsed.netloc}"
    path_parts = [p for p in parsed.path.strip('/').split('/') if p]
    service_name = path_parts[-1]
    return service_domain, service_name


service_domain, service_name = parse_service_url(service_url)
print(f"service_domain: {service_domain}, service_name: {service_name}.")

# Please configure the payload as the content of the JSON file corresponding to the workflow.
payload = """
{
    "11": {
        "inputs": {
        "model_name": "umt5-xxl-enc-bf16.safetensors",
        "precision": "bf16",
        "load_device": "offload_device",
        "quantization": "disabled"
        },
        "class_type": "LoadWanVideoT5TextEncoder",
        "_meta": {
        "title": "Load WanVideo T5 TextEncoder"
        }
    },
    "16": {
        "inputs": {
        "positive_prompt": "A blonde woman with her head tilted back and eyes closed, her expression serene and dreamy. Her hair is very long and fluffy, showing natural waves as if blown by the wind. In the background, some blurred flowers are falling, creating a romantic and dreamy atmosphere. She is wearing a top with lace decorations, and the color of her clothes coordinates with the background, with an overall soft tone. Light shines down from above, illuminating her face and hair, making the entire image appear very soft and warm.",
        "negative_prompt": "Vibrant color tones, overexposure, static, blurry details, captions, style, artwork, painting, image, still, overall grayness, worst quality, low quality, JPEG compression artifacts, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn face, deformed, disfigured, deformed limbs, finger fusion, static image, messy background, three legs, many people in the background, walking backwards",
        "force_offload": true,
        "speak_and_recognation": {
            "__value__": [
            false,
            true
            ]
        },
        "t5": [
            "11",
            0
        ]
        },
        "class_type": "WanVideoTextEncode",
        "_meta": {
        "title": "WanVideo TextEncode"
        }
    },
    "22": {
        "inputs": {
        "model": "WanVideo/wan2.1_t2v_14B_bf16.safetensors",
        "base_precision": "fp16",
        "quantization": "fp8_e4m3fn",
        "load_device": "offload_device",
        "attention_mode": "sageattn",
        "compile_args": [
            "35",
            0
        ]
        },
        "class_type": "WanVideoModelLoader",
        "_meta": {
        "title": "WanVideo Model Loader"
        }
    },
    "27": {
        "inputs": {
        "steps": 40,
        "cfg": 6.000000000000002,
        "shift": 5.000000000000001,
        "seed": 1057359483639287,
        "force_offload": true,
        "scheduler": "unipc",
        "riflex_freq_index": 0,
        "denoise_strength": 1,
        "batched_cfg": false,
        "rope_function": "default",
        "nocfg_begin": 0.7500000000000001,
        "nocfg_end": 1,
        "model": [
            "22",
            0
        ],
        "text_embeds": [
            "16",
            0
        ],
        "image_embeds": [
            "37",
            0
        ],
        "teacache_args": [
            "52",
            0
        ]
        },
        "class_type": "WanVideoSampler",
        "_meta": {
        "title": "WanVideo Sampler"
        }
    },
    "28": {
        "inputs": {
        "enable_vae_tiling": true,
        "tile_x": 272,
        "tile_y": 272,
        "tile_stride_x": 144,
        "tile_stride_y": 128,
        "vae": [
            "38",
            0
        ],
        "samples": [
            "27",
            0
        ]
        },
        "class_type": "WanVideoDecode",
        "_meta": {
        "title": "WanVideo Decode"
        }
    },
    "30": {
        "inputs": {
        "frame_rate": 16,
        "loop_count": 0,
        "filename_prefix": "WanVideo2_1_T2V",
        "format": "video/h264-mp4",
        "pix_fmt": "yuv420p",
        "crf": 19,
        "save_metadata": true,
        "trim_to_audio": false,
        "pingpong": false,
        "save_output": true,
        "images": [
            "28",
            0
        ]
        },
        "class_type": "VHS_VideoCombine",
        "_meta": {
        "title": "Merge to video"
        }
    },
    "35": {
        "inputs": {
        "backend": "inductor",
        "fullgraph": false,
        "mode": "default",
        "dynamic": false,
        "dynamo_cache_size_limit": 64,
        "compile_transformer_blocks_only": true
        },
        "class_type": "WanVideoTorchCompileSettings",
        "_meta": {
        "title": "WanVideo Torch Compile Settings"
        }
    },
    "37": {
        "inputs": {
        "width": 832,
        "height": 480,
        "num_frames": 81
        },
        "class_type": "WanVideoEmptyEmbeds",
        "_meta": {
        "title": "WanVideo Empty Embeds"
        }
    },
    "38": {
        "inputs": {
        "model_name": "WanVideo/Wan2_1_VAE_bf16.safetensors",
        "precision": "bf16"
        },
        "class_type": "WanVideoVAELoader",
        "_meta": {
        "title": "WanVideo VAE Loader"
        }
    },
    "52": {
        "inputs": {
        "rel_l1_thresh": 0.25000000000000006,
        "start_step": 1,
        "end_step": -1,
        "cache_device": "offload_device",
        "use_coefficients": "true"
        },
        "class_type": "WanVideoTeaCache",
        "_meta": {
        "title": "WanVideo TeaCache"
        }
    }
}
"""

session = requests.session()
session.headers.update({"Authorization":token})

payload = json.loads(payload)
payload["16"]["inputs"]["positive_prompt"] = prompt
payload["16"]["inputs"]["negative_prompt"] = negative_prompt
payload["27"]["inputs"]["steps"] = steps
payload["37"]["inputs"]["height"] = height
payload["37"]["inputs"]["width"] = width
payload["37"]["inputs"]["num_frames"] = num_frames

response = session.post(url=f'{service_url}/api_prompt?task_id=txt2img', json=payload)
if response.status_code != 200:
    raise Exception(response.content)

data = response.json()
sink_queue = QueueClient(service_domain, f'{service_name}/sink')
sink_queue.set_token(token)
sink_queue.init()

watcher = sink_queue.watch(0, 1, 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}')
    print(json.loads(x.data.decode('utf-8'))[1]["data"]["output"]["gifs"][0]["fullpath"])
    sink_queue.commit(x.index)

References

To learn more about the deployment and functionality ComfyUI, such as loading custom models, integrating plugins, and FAQs, see AI video generation - ComfyUI deployment.