Wan是一個開源的AI視頻產生大模型,支援T2V(文本產生視頻)和I2V(映像產生視頻)功能。在ComfyUI中,PAI提供了定製化的JSON工作流程和API調用方式,協助您使用Wan模型產生高品質的視頻內容。本文將以I2V(映像產生視頻)為例,介紹如何部署ComfyUI服務,並使用Wan產生視頻。
部署標準版ComfyUI(單使用者使用)
部署配置
使用自訂部署方式部署標準版ComfyUI鏡像服務,具體操作步驟如下:
登入PAI控制台,在頁面上方選擇目標地區,並在右側選擇目標工作空間,然後單擊進入EAS。
單擊部署服務,然後在自訂模型部署地區,單擊自訂部署。
在自訂部署頁面,配置以下參數。
在環境資訊地區,配置以下參數。
參數
描述
鏡像配置
在官方鏡像列表中選擇鏡像comfyui > comfyui:1.9。
說明其中1.9為鏡像版本,由於版本迭代迅速,部署時鏡像版本選擇最高版本即可。
儲存掛載
為EAS服務掛載外部儲存資料來源(如OSS、NAS等),後續調用服務產生的視頻,將自動儲存到相應的資料來源中。以Object Storage Service為例,單擊OSS,並配置以下參數:
Uri:選擇OSS Bucket源地址目錄。關於如何建立儲存空間和目錄,請參見控制台快速入門。請確保建立的儲存空間與EAS服務位於同一地區。
掛載路徑:即掛載到服務執行個體中的目標路徑。例如
/code/data-oss。
運行命令
選擇鏡像後,系統會自動設定運行命令。
當您進行模型配置後,您需要在運行命令中設定
--data-dir掛載目錄,並確保掛載目錄與模型配置中的掛載路徑一致。對於1.9版本的鏡像,
--data-dir已預先配置,您只需將其更新為模型配置中的掛載路徑即可。例如python main.py --listen --port 8000 --data-dir /code/data-oss。在資源資訊地區,選擇資源規格。
參數
描述
資源類型
選擇公用資源。
部署資源
選擇資源規格。因視頻產生相比圖片產生需要更大的GPU顯存,建議您選擇單卡顯存不低於48 GB的資源規格。推薦使用GU60機型(例如
ml.gu8is.c16m128.1-gu60)。在網路資訊地區,配置具有公網訪問能力的專用網路,詳情請參見EAS訪問公網或內網資源。
說明EAS服務預設不通公網,因I2V(映像產生視頻)功能需要串連公網下載圖片,所以需為EAS配置具有公網訪問能力的專用網路。
參數配置完成後,單擊部署。
WebUI使用
服務部署成功後,您可以在WebUI頁面構建工作流程,完成服務調用。具體操作步驟如下:
單擊目標服務名稱進入概覽頁面,在右上方單擊Web應用。
在WebUI頁面左上方,選擇工作流程 > 開啟,選擇JSON工作流程檔案,然後單擊開啟。
PAI已在ComfyUI中整合了各類加速演算法,速度與效果較好的ComfyUI JSON工作流程樣本如下:
Image to Video(直接上傳圖片):wanvideo_720P_I2V.json
工作流程載入成功後,您可以在WebUI頁面的載入映像地區,通過單擊選擇檔案上傳,手動上傳並更新圖片檔案。

Image to Video(通過圖片URL載入圖片):wanvideo_720P_I2V_URL.json
工作流程載入成功後,您可以在WebUI頁面的Load Image By URL地區,配置圖片URL地址,以更新載入的圖片。

單擊頁面下方的運行按鈕,產生視頻。
大約執行20分鐘左右,結果會顯示在右方的合并為視頻地區中。

API同步調用
標準版服務僅支援同步調用,即直接請求推理執行個體,不使用EAS的佇列服務。具體操作步驟如下:
匯出工作流程JSON檔案。
ComfyUI的API請求體取決於工作流程配置。您需要先在已部署的標準版服務的WebUI版面設定工作流程,然後在WebUI頁面左上方,選擇工作流程 > 匯出(API),通過儲存API格式擷取工作流程對應的JSON檔案。

查看調用資訊。
在服務列表中,單擊服務名稱,然後在基本資料地區,單擊查看調用資訊。
在調用資訊對話方塊,擷取訪問地址和Token。
說明使用公網調用地址:調用用戶端需支援訪問公網。
使用VPC調用地址:調用用戶端必須與服務位於同一個專用網路內。

調用服務。
完整調用和擷取結果的程式碼範例如下,您可以在最終結果中通過
data[prompt_id]["outputs"]["fullpath"],擷取輸出映像的OSS完整路徑。範例程式碼通過環境變數擷取EAS服務訪問地址和Token,您可以在終端中執行以下命令添加臨時性環境變數(僅在當前會話中生效):
# 分別配置為服務訪問地址和Token。 export SERVICE_URL="http://test****.115770327099****.cn-beijing.pai-eas.aliyuncs.com/" export TOKEN="MzJlMDNjMmU3YzQ0ZDJ*****************TMxZA=="完整I2V調用代碼
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 = "一位金髮女子,她仰頭閉眼,表情寧靜而夢幻。她的頭髮非常長且蓬鬆,呈現出自然的波浪狀,彷彿被風吹拂。背景中有一些模糊的花朵飄落,營造出一種浪漫和夢幻的氛圍。她穿著一件帶有蕾絲裝飾的上衣,衣服的顏色與背景相協調,整體色調柔和。光線從上方照射下來,照亮了她的臉龐和頭髮,使整個畫面顯得非常柔和和溫暖。" negative_prompt = "色調豔麗,過曝,靜態,細節模糊不清,字幕,風格,作品,畫作,畫面,靜止,整體發灰,最差品質,低品質,JPEG壓縮殘留,醜陋的,殘缺的,多餘的手指,畫得不好的手部,畫得不好的臉部,畸形的,毀容的,形態畸形的肢體,手指融合,靜止不動的畫面,雜亂的背景,三條腿,背景人很多,倒著走" height = 720 width = 1280 steps = 40 num_frames = 81 if service_url[-1] == "/": service_url = service_url[:-1] prompt_url = f"{service_url}/prompt" # 請將payload中的prompt的值配置為工作流程對應的JSON檔案內容。 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": "一位金髮女子,她仰頭閉眼,表情寧靜而夢幻。她的頭髮非常長且蓬鬆,呈現出自然的波浪狀,彷彿被風吹拂。背景中有一些模糊的花朵飄落,營造出一種浪漫和夢幻的氛圍。她穿著一件帶有蕾絲裝飾的上衣,衣服的顏色與背景相協調,整體色調柔和。光線從上方照射下來,照亮了她的臉龐和頭髮,使整個畫面顯得非常柔和和溫暖。", "negative_prompt": "色調豔麗,過曝,靜態,細節模糊不清,字幕,風格,作品,畫作,畫面,靜止,整體發灰,最差品質,低品質,JPEG壓縮殘留,醜陋的,殘缺的,多餘的手指,畫得不好的手部,畫得不好的臉部,畸形的,毀容的,形態畸形的肢體,手指融合,靜止不動的畫面,雜亂的背景,三條腿,背景人很多,倒著走", "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": "合并為視頻" } }, "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視覺載入器" } }, "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": "映像縮放(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)分步解析上述代碼
發送POST請求,從返回結果中擷取Prompt ID。
import requests import os service_url = os.getenv("SERVICE_URL") token = os.getenv("TOKEN") url = f"{service_url}/prompt" payload = { "prompt": 請求體...省略 } 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)其中payload需配置為請求體,prompt索引值是上述匯出(API)獲得的請求JSON,在Python請求中,請求體中的布爾值(True和False)首字母需要大寫。
首次請求的返回結果樣本如下:
{ "prompt_id": "021ebc5b-e245-4e37-8bd3-00f7b949****", "number": 5, "node_errors": {} }根據請求的Prompt ID擷取最終預測結果。
import requests import os # 構造請求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)其中<prompt_id>需替換為上一步中擷取的prompt_id。
返回結果樣本如下:
{ "130bcd6b-5bb5-496c-9c8c-3a1359a0****": { "prompt": ...省略, "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": ...省略, } } }
部署API版ComfyUI(高並發情境)
部署配置
如果您已建立標準版ComfyUI服務,希望將其改成API版本,建議刪除原有服務後重新建立API版本。
使用自訂部署方式部署API版ComfyUI鏡像服務,具體操作步驟如下:
登入PAI控制台,在頁面上方選擇目標地區,並在右側選擇目標工作空間,然後單擊進入EAS。
單擊部署服務,然後在自訂模型部署地區,單擊自訂部署。
在自訂部署頁面,配置以下參數。
在環境資訊地區,配置以下參數。
參數
描述
鏡像配置
在官方鏡像列表中選擇鏡像comfyui > comfyui:1.9-api。
說明其中1.9為鏡像版本,由於版本迭代迅速,部署時鏡像版本選擇最高版本即可。
儲存掛載
為EAS服務掛載外部儲存資料來源(如OSS、NAS等),後續調用服務產生的視頻,將自動儲存到相應的資料來源中。以Object Storage Service為例,單擊OSS,並配置以下參數:
Uri:選擇OSS Bucket源地址目錄。關於如何建立儲存空間和目錄,請參見控制台快速入門。請確保建立的儲存空間與EAS服務位於同一地區。
掛載路徑:即掛載到服務執行個體中的目標路徑。例如
/code/data-oss。
運行命令
選擇鏡像後,系統會自動設定運行命令。
當您進行模型配置後,您需要在運行命令中設定
--data-dir掛載目錄,並確保掛載目錄與模型配置中的掛載路徑一致。對於1.9版本的鏡像,
--data-dir已預先配置,您只需將其更新為模型配置中的掛載路徑即可。例如python main.py --listen --port 8000 --api --data-dir /code/data-oss。在資源資訊地區,選擇資源規格。
參數
描述
資源類型
選擇公用資源。
部署資源
選擇資源規格。因視頻產生相比圖片產生需要更大的GPU顯存,建議您選擇單卡顯存不低於48 GB的資源規格。推薦使用GU60機型(例如
ml.gu8is.c16m128.1-gu60)。在非同步隊列地區,配置單一輸入請求最巨量資料和單一輸出返回最巨量資料,標準值為1024 KB。
說明建議合理設定隊列資料大小,以避免因超出限制而導致請求被拒絕、樣本丟失、響應失敗或隊列阻塞等問題。
在網路資訊地區,配置具有公網訪問能力的專用網路,詳情請參見EAS訪問公網或內網資源。
說明EAS服務預設不通公網,因I2V(映像產生視頻)功能需要串連公網下載圖片,所以需為EAS配置具有公網訪問能力的專用網路。
參數配置完成後,單擊部署。
API非同步呼叫
API版僅支援非同步呼叫,且僅支援api_prompt路徑。非同步呼叫是指使用EAS的佇列服務,向輸入隊列發送請求,以訂閱的方式獲得結果推送。具體操作步驟如下:
在推理服務頁簽,單擊目標服務名稱進入概覽頁面,在基本資料地區單擊查看調用資訊。在調用資訊對話方塊的非同步呼叫頁簽,查看服務訪問地址和Token。
說明使用公網調用地址:調用用戶端需支援訪問公網。
使用VPC調用地址:調用用戶端必須與服務位於同一個專用網路內。
在終端中執行安裝eas_prediction SDK命令。
pip install eas_prediction --user調用服務。
完整調用的程式碼範例如下,您可以在最終結果中通過
json.loads(x.data.decode('utf-8'))[1]["data"]["output"]["gifs"][0]["fullpath"],擷取輸出映像的OSS完整路徑。範例程式碼通過環境變數擷取EAS服務訪問地址和Token,您可以在終端中執行以下命令添加臨時性環境變數(僅在當前會話中生效):
# 分別配置為服務訪問地址和Token。 export SERVICE_URL="http://test****.115770327099****.cn-beijing.pai-eas.aliyuncs.com/" export TOKEN="MzJlMDNjMmU3YzQ0ZDJ*****************TMxZA=="完整I2V調用代碼
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 = "一位金髮女子,她仰頭閉眼,表情寧靜而夢幻。她的頭髮非常長且蓬鬆,呈現出自然的波浪狀,彷彿被風吹拂。背景中有一些模糊的花朵飄落,營造出一種浪漫和夢幻的氛圍。她穿著一件帶有蕾絲裝飾的上衣,衣服的顏色與背景相協調,整體色調柔和。光線從上方照射下來,照亮了她的臉龐和頭髮,使整個畫面顯得非常柔和和溫暖。" negative_prompt = "色調豔麗,過曝,靜態,細節模糊不清,字幕,風格,作品,畫作,畫面,靜止,整體發灰,最差品質,低品質,JPEG壓縮殘留,醜陋的,殘缺的,多餘的手指,畫得不好的手部,畫得不好的臉部,畸形的,毀容的,形態畸形的肢體,手指融合,靜止不動的畫面,雜亂的背景,三條腿,背景人很多,倒著走" 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}.") # 請將payload配置為工作流程對應的JSON檔案內容。 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": "一位金髮女子,她仰頭閉眼,表情寧靜而夢幻。她的頭髮非常長且蓬鬆,呈現出自然的波浪狀,彷彿被風吹拂。背景中有一些模糊的花朵飄落,營造出一種浪漫和夢幻的氛圍。她穿著一件帶有蕾絲裝飾的上衣,衣服的顏色與背景相協調,整體色調柔和。光線從上方照射下來,照亮了她的臉龐和頭髮,使整個畫面顯得非常柔和和溫暖。", "negative_prompt": "色調豔麗,過曝,靜態,細節模糊不清,字幕,風格,作品,畫作,畫面,靜止,整體發灰,最差品質,低品質,JPEG壓縮殘留,醜陋的,殘缺的,多餘的手指,畫得不好的手部,畫得不好的臉部,畸形的,毀容的,形態畸形的肢體,手指融合,靜止不動的畫面,雜亂的背景,三條腿,背景人很多,倒著走", "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": "合并為視頻" } }, "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視覺載入器" } }, "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": "映像縮放(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)分步解析上述代碼
發送請求,程式碼範例如下:
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': ...省略 } # 與標準版不同的是沒有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}")其中work_flow需配置為請求體,即上述匯出(API)獲得的請求JSON,在Python請求中,請求體中的布爾值(True和False)首字母需要大寫。
訂閱結果,程式碼範例如下:
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)其中關鍵配置項說明如下:
配置項
描述
<service_domain>
請替換為已查詢的服務訪問地址中的調用資訊。例如
139699392458****.cn-hangzhou.pai-eas.aliyuncs.com。<service_name>
請替換為EAS服務名稱。
返回結果樣本如下:
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"}]}}]'
附錄:更多樣本
T2V(文本產生視頻)和I2V(映像產生視頻)的使用流程一致,參考上述步驟部署和調用服務即可。但T2V不依賴公網串連功能,因此在部署EAS服務時,無需配置專用網路。
您可以通過樣本工作流程檔案(wanvideo_720P_T2V.json)體驗WebUI調用流程。參考WebUI使用,在WebUI頁面載入工作流程,然後在WanVideo TextEncode輸入框中輸入文本提示詞,並單擊運行,則會開始執行流程。
如果需要通過API調用,完整的程式碼範例如下:
範例程式碼通過環境變數擷取EAS服務訪問地址和Token,您可以在終端中執行以下命令添加臨時性環境變數(僅在當前會話中生效):
# 分別配置為服務訪問地址和Token。
export SERVICE_URL="http://test****.115770327099****.cn-beijing.pai-eas.aliyuncs.com/"
export TOKEN="MzJlMDNjMmU3YzQ0ZDJ*****************TMxZA=="API同步調用
完整T2V調用代碼
from time import sleep
import os
import json
import requests
service_url = os.getenv("SERVICE_URL")
token = os.getenv("TOKEN")
prompt = "一位金髮女子,她仰頭閉眼,表情寧靜而夢幻。她的頭髮非常長且蓬鬆,呈現出自然的波浪狀,彷彿被風吹拂。背景中有一些模糊的花朵飄落,營造出一種浪漫和夢幻的氛圍。她穿著一件帶有蕾絲裝飾的上衣,衣服的顏色與背景相協調,整體色調柔和。光線從上方照射下來,照亮了她的臉龐和頭髮,使整個畫面顯得非常柔和和溫暖。"
negative_prompt = "色調豔麗,過曝,靜態,細節模糊不清,字幕,風格,作品,畫作,畫面,靜止,整體發灰,最差品質,低品質,JPEG壓縮殘留,醜陋的,殘缺的,多餘的手指,畫得不好的手部,畫得不好的臉部,畸形的,毀容的,形態畸形的肢體,手指融合,靜止不動的畫面,雜亂的背景,三條腿,背景人很多,倒著走"
height = 720
width = 1280
steps = 40
num_frames = 81
if service_url[-1] == "/":
service_url = service_url[:-1]
prompt_url = f"{service_url}/prompt"
# 請將payload中的prompt的值配置為工作流程對應的JSON檔案內容。
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": "一位金髮女子,她仰頭閉眼,表情寧靜而夢幻。她的頭髮非常長且蓬鬆,呈現出自然的波浪狀,彷彿被風吹拂。背景中有一些模糊的花朵飄落,營造出一種浪漫和夢幻的氛圍。她穿著一件帶有蕾絲裝飾的上衣,衣服的顏色與背景相協調,整體色調柔和。光線從上方照射下來,照亮了她的臉龐和頭髮,使整個畫面顯得非常柔和和溫暖。",
"negative_prompt": "色調豔麗,過曝,靜態,細節模糊不清,字幕,風格,作品,畫作,畫面,靜止,整體發灰,最差品質,低品質,JPEG壓縮殘留,醜陋的,殘缺的,多餘的手指,畫得不好的手部,畫得不好的臉部,畸形的,毀容的,形態畸形的肢體,手指融合,靜止不動的畫面,雜亂的背景,三條腿,背景人很多,倒著走",
"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": "合并為視頻"
}
},
"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)API非同步呼叫
完整T2V調用代碼
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 = "一位金髮女子,她仰頭閉眼,表情寧靜而夢幻。她的頭髮非常長且蓬鬆,呈現出自然的波浪狀,彷彿被風吹拂。背景中有一些模糊的花朵飄落,營造出一種浪漫和夢幻的氛圍。她穿著一件帶有蕾絲裝飾的上衣,衣服的顏色與背景相協調,整體色調柔和。光線從上方照射下來,照亮了她的臉龐和頭髮,使整個畫面顯得非常柔和和溫暖。"
negative_prompt = "色調豔麗,過曝,靜態,細節模糊不清,字幕,風格,作品,畫作,畫面,靜止,整體發灰,最差品質,低品質,JPEG壓縮殘留,醜陋的,殘缺的,多餘的手指,畫得不好的手部,畫得不好的臉部,畸形的,毀容的,形態畸形的肢體,手指融合,靜止不動的畫面,雜亂的背景,三條腿,背景人很多,倒著走"
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}.")
# 請將payload配置為工作流程對應的JSON檔案內容。
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": "一位金髮女子,她仰頭閉眼,表情寧靜而夢幻。她的頭髮非常長且蓬鬆,呈現出自然的波浪狀,彷彿被風吹拂。背景中有一些模糊的花朵飄落,營造出一種浪漫和夢幻的氛圍。她穿著一件帶有蕾絲裝飾的上衣,衣服的顏色與背景相協調,整體色調柔和。光線從上方照射下來,照亮了她的臉龐和頭髮,使整個畫面顯得非常柔和和溫暖。",
"negative_prompt": "色調豔麗,過曝,靜態,細節模糊不清,字幕,風格,作品,畫作,畫面,靜止,整體發灰,最差品質,低品質,JPEG壓縮殘留,醜陋的,殘缺的,多餘的手指,畫得不好的手部,畫得不好的臉部,畸形的,毀容的,形態畸形的肢體,手指融合,靜止不動的畫面,雜亂的背景,三條腿,背景人很多,倒著走",
"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": "合并為視頻"
}
},
"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)相關文檔
如需更全面的瞭解ComfyUI的部署與功能使用,包括載入自訂模型、整合ComfyUI外掛程式,以及常見問題等內容,請參閱AI視頻產生-ComfyUI部署。