# Python 3.10+: pip install comfy-sdk==0.4.0
import os
from comfy_sdk import Comfy
api_key = os.environ.get("COMFY_API_KEY", "").strip()
if not api_key: raise RuntimeError("Set COMFY_API_KEY")
os.environ.setdefault("COMFY_BASE_URL", "https://cloud.comfy.org")
client = Comfy(api_key=api_key)
workflow = client.workflows.from_json({
"3": {
"class_type": "KSampler",
"inputs": {
"cfg": 1,
"denoise": 1,
"latent_image": [
"49",
2
],
"model": [
"48",
0
],
"negative": [
"49",
1
],
"positive": [
"49",
0
],
"sampler_name": "uni_pc",
"scheduler": "simple",
"seed": 776767434080331,
"steps": 3
},
"_meta": {
"title": "KSampler"
}
},
"6": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"165",
1
],
"text": "A portrait of a woman with her eyes closed, her head surrounded by white transparent glass flowers, with only her face exposed. The camera slowly moves in, and the girl smiles. There are other transparent glass flowers in the style of Nicoletta Ceccoli around her. The detailed painting features natural light and soft lighting, creating a beautiful, surreal, and emotionally expressive movie scene.\n"
},
"_meta": {
"title": "CLIP Text Encode (Positive Prompt)"
}
},
"7": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"165",
1
],
"text": "bad quality, blurry, messy, chaotic"
},
"_meta": {
"title": "CLIP Text Encode (Negative Prompt)"
}
},
"8": {
"class_type": "VAEDecode",
"inputs": {
"samples": [
"58",
0
],
"vae": [
"152",
0
]
},
"_meta": {
"title": "VAE Decode"
}
},
"48": {
"class_type": "ModelSamplingSD3",
"inputs": {
"model": [
"165",
0
],
"shift": 8.000000000000002
},
"_meta": {
"title": "ModelSamplingSD3"
}
},
"49": {
"class_type": "WanVaceToVideo",
"inputs": {
"batch_size": 1,
"control_masks": [
"130",
0
],
"control_video": [
"110",
0
],
"height": [
"139",
0
],
"length": [
"131",
0
],
"negative": [
"7",
0
],
"positive": [
"6",
0
],
"strength": 1,
"vae": [
"152",
0
],
"width": [
"137",
0
]
},
"_meta": {
"title": "WanVaceToVideo"
}
},
"58": {
"class_type": "TrimVideoLatent",
"inputs": {
"samples": [
"3",
0
],
"trim_amount": [
"49",
3
]
},
"_meta": {
"title": "Trim Video Latent"
}
},
"68": {
"class_type": "CreateVideo",
"inputs": {
"bit_depth": "auto",
"codec": "none",
"color_space": "sRGB",
"fps": 16,
"images": [
"8",
0
]
},
"_meta": {
"title": "Create Video"
}
},
"69": {
"class_type": "SaveVideo",
"inputs": {
"filename_prefix": "video/ComfyUI",
"format": "auto",
"format.codec": "auto",
"video": [
"68",
0
]
},
"_meta": {
"title": "Save Video"
}
},
"71": {
"class_type": "LoadVideo",
"inputs": {
"file": "video_wan_vace_outpainting_input_video.mp4"
},
"_meta": {
"title": "Load Video"
}
},
"72": {
"class_type": "GetVideoComponents",
"inputs": {
"video": [
"71",
0
]
},
"_meta": {
"title": "Get Video Components"
}
},
"110": {
"class_type": "ImagePadForOutpaint",
"inputs": {
"bottom": 200,
"feathering": 0,
"image": [
"72",
0
],
"left": 120,
"right": 120,
"top": 120
},
"_meta": {
"title": "Pad Image for Outpainting"
}
},
"111": {
"class_type": "MaskToImage",
"inputs": {
"mask": [
"110",
1
]
},
"_meta": {
"title": "Convert Mask to Image"
}
},
"129": {
"class_type": "RepeatImageBatch",
"inputs": {
"amount": [
"131",
0
],
"image": [
"111",
0
]
},
"_meta": {
"title": "Repeat Image Batch"
}
},
"130": {
"class_type": "ImageToMask",
"inputs": {
"channel": "red",
"image": [
"129",
0
]
},
"_meta": {
"title": "Convert Image to Mask"
}
},
"131": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 81
},
"_meta": {
"title": "Length"
}
},
"135": {
"class_type": "PreviewImage",
"inputs": {
"images": [
"110",
0
]
},
"_meta": {
"title": "Preview Image - Outpaint"
}
},
"137": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 960
},
"_meta": {
"title": "Width"
}
},
"139": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 960
},
"_meta": {
"title": "Height"
}
},
"143": {
"class_type": "PreviewImage",
"inputs": {
"images": [
"72",
0
]
},
"_meta": {
"title": "Preview Image - original"
}
},
"151": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "wan2.1_vace_14B_fp16.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"152": {
"class_type": "VAELoader",
"inputs": {
"vae_name": "wan_2.1_vae.safetensors"
},
"_meta": {
"title": "Load VAE"
}
},
"161": {
"class_type": "CLIPLoader",
"inputs": {
"clip_name": "umt5_xxl_fp16.safetensors",
"device": "default",
"type": "wan"
},
"_meta": {
"title": "Load CLIP"
}
},
"165": {
"class_type": "LoraLoader",
"inputs": {
"clip": [
"161",
0
],
"lora_name": "Wan21_CausVid_14B_T2V_lora_rank32.safetensors",
"model": [
"151",
0
],
"strength_clip": 1,
"strength_model": 0.4000000000000001
},
"_meta": {
"title": "Load LoRA (Model and CLIP)"
}
}
})
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)