# 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({
"97": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_FILENAME"
},
"_meta": {
"title": "Load Image"
}
},
"108": {
"class_type": "SaveVideo",
"inputs": {
"filename_prefix": "video/Wan2.2_i2v",
"format": "auto",
"format.codec": "auto",
"video": [
"129:94",
0
]
},
"_meta": {
"title": "Save Video"
}
},
"129:101": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "wan2.2_i2v_lightx2v_4steps_lora_v1_high_noise.safetensors",
"model": [
"129:95",
0
],
"strength_model": 1.0000000000000002
},
"_meta": {
"title": "Load LoRA"
}
},
"129:102": {
"class_type": "LoraLoaderModelOnly",
"inputs": {
"lora_name": "wan2.2_i2v_lightx2v_4steps_lora_v1_low_noise.safetensors",
"model": [
"129:96",
0
],
"strength_model": 1.0000000000000002
},
"_meta": {
"title": "Load LoRA"
}
},
"129:103": {
"class_type": "ModelSamplingSD3",
"inputs": {
"model": [
"129:117",
0
],
"shift": 5.000000000000001
},
"_meta": {
"title": "ModelSamplingSD3"
}
},
"129:104": {
"class_type": "ModelSamplingSD3",
"inputs": {
"model": [
"129:116",
0
],
"shift": 5.000000000000001
},
"_meta": {
"title": "ModelSamplingSD3"
}
},
"129:116": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"129:95",
0
],
"on_true": [
"129:101",
0
],
"switch": [
"129:131",
0
]
},
"_meta": {
"title": "Switch (Model)"
}
},
"129:117": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"129:96",
0
],
"on_true": [
"129:102",
0
],
"switch": [
"129:131",
0
]
},
"_meta": {
"title": "Switch (Model)"
}
},
"129:118": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 4
},
"_meta": {
"title": "Steps"
}
},
"129:119": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"129:128",
0
],
"on_true": [
"129:118",
0
],
"switch": [
"129:131",
0
]
},
"_meta": {
"title": "Switch (Steps)"
}
},
"129:120": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"129:126",
0
],
"on_true": [
"129:122",
0
],
"switch": [
"129:131",
0
]
},
"_meta": {
"title": "Switch (CFG)"
}
},
"129:122": {
"class_type": "PrimitiveFloat",
"inputs": {
"value": 1
},
"_meta": {
"title": "CFG"
}
},
"129:124": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 2
},
"_meta": {
"title": "split_step"
}
},
"129:125": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"129:127",
0
],
"on_true": [
"129:124",
0
],
"switch": [
"129:131",
0
]
},
"_meta": {
"title": "Switch (Split Step)"
}
},
"129:126": {
"class_type": "PrimitiveFloat",
"inputs": {
"value": 3.5
},
"_meta": {
"title": "CFG"
}
},
"129:127": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 10
},
"_meta": {
"title": "split_step"
}
},
"129:128": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 20
},
"_meta": {
"title": "Steps"
}
},
"129:131": {
"class_type": "PrimitiveBoolean",
"inputs": {
"value": True
},
"_meta": {
"title": "Enable 4steps LoRA?"
}
},
"129:84": {
"class_type": "CLIPLoader",
"inputs": {
"clip_name": "umt5_xxl_fp8_e4m3fn_scaled.safetensors",
"device": "default",
"type": "wan"
},
"_meta": {
"title": "Load CLIP"
}
},
"129:85": {
"class_type": "KSamplerAdvanced",
"inputs": {
"add_noise": "disable",
"cfg": [
"129:120",
0
],
"end_at_step": [
"129:119",
0
],
"latent_image": [
"129:86",
0
],
"model": [
"129:103",
0
],
"negative": [
"129:98",
1
],
"noise_seed": 0,
"positive": [
"129:98",
0
],
"return_with_leftover_noise": "disable",
"sampler_name": "euler",
"scheduler": "simple",
"start_at_step": [
"129:125",
0
],
"steps": [
"129:119",
0
]
},
"_meta": {
"title": "KSampler (Advanced)"
}
},
"129:86": {
"class_type": "KSamplerAdvanced",
"inputs": {
"add_noise": "enable",
"cfg": [
"129:120",
0
],
"end_at_step": [
"129:125",
0
],
"latent_image": [
"129:98",
2
],
"model": [
"129:104",
0
],
"negative": [
"129:98",
1
],
"noise_seed": 264244520398999,
"positive": [
"129:98",
0
],
"return_with_leftover_noise": "enable",
"sampler_name": "euler",
"scheduler": "simple",
"start_at_step": 0,
"steps": [
"129:119",
0
]
},
"_meta": {
"title": "KSampler (Advanced)"
}
},
"129:87": {
"class_type": "VAEDecode",
"inputs": {
"samples": [
"129:85",
0
],
"vae": [
"129:90",
0
]
},
"_meta": {
"title": "VAE Decode"
}
},
"129:89": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"129:84",
0
],
"text": "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走"
},
"_meta": {
"title": "CLIP Text Encode (Negative Prompt)"
}
},
"129:90": {
"class_type": "VAELoader",
"inputs": {
"vae_name": "wan_2.1_vae.safetensors"
},
"_meta": {
"title": "Load VAE"
}
},
"129:93": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"129:84",
0
],
"text": "A high aerial drone shot over the cracked, parched desert lake bed as the herd of wild horses gallops forward, the black stallion leading in the foreground with its mane whipping in the wind. Hooves pound the dry clay and throw up long plumes of pale dust that drift and glow in the hazy sunlight. White, chestnut and bay horses surge behind him, their manes and tails streaming as the herd fans out and tightens again. Camera: the drone swoops low and fast alongside the black stallion, banks into a sweeping arc ahead of the herd, then rises and tilts down to reveal the whole herd racing toward the distant ranch fence. Dynamic, energetic motion, realistic gallop cycles, natural motion blur, warm dusty light, documentary realism."
},
"_meta": {
"title": "CLIP Text Encode (Positive Prompt)"
}
},
"129:94": {
"class_type": "CreateVideo",
"inputs": {
"bit_depth": "auto",
"codec": "none",
"color_space": "sRGB",
"fps": 16,
"images": [
"129:87",
0
]
},
"_meta": {
"title": "Create Video"
}
},
"129:95": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "wan2.2_i2v_high_noise_14B_fp8_scaled.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"129:96": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"129:98": {
"class_type": "WanImageToVideo",
"inputs": {
"batch_size": 1,
"height": 720,
"length": 81,
"negative": [
"129:89",
0
],
"positive": [
"129:93",
0
],
"start_image": [
"97",
0
],
"vae": [
"129:90",
0
],
"width": 1280
},
"_meta": {
"title": "WanImageToVideo"
}
}
})
workflow.set_input("97", "image", client.assets.from_url("https://comfy.org/catalog-media/151a692a-e9b7-4ce2-ab96-e63dad23740b/69375d1b-55df-452b-8814-f5b659a6d8de"))
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)
for output in job.get_outputs("108"):
output.to_file(output.name)