# 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": "LoadImage",
"inputs": {
"image": "live_portrait_character.png"
},
"_meta": {
"title": "Load Image"
}
},
"10": {
"class_type": "VHS_VideoCombine",
"inputs": {
"crf": 19,
"filename_prefix": "LivePortrait",
"format": "video/h264-mp4",
"frame_rate": 15,
"images": [
"49",
0
],
"loop_count": 0,
"pingpong": False,
"pix_fmt": "yuv420p",
"save_metadata": True,
"save_output": True,
"trim_to_audio": False
},
"_meta": {
"title": "Video Combine 🎥🅥🅗🅢"
}
},
"44": {
"class_type": "VHS_LoadVideo",
"inputs": {
"custom_height": 0,
"custom_width": 0,
"force_rate": 0,
"format": "AnimateDiff",
"frame_load_cap": 0,
"select_every_nth": 2,
"skip_first_frames": 0,
"video": "live_portrait_expression.mp4"
},
"_meta": {
"title": "Load Video (Upload) 🎥🅥🅗🅢"
}
},
"47": {
"class_type": "LivePortraitProcess",
"inputs": {
"crop_info": [
"51",
1
],
"delta_multiplier": 1.5,
"driving_images": [
"44",
0
],
"driving_smooth_observation_variance": 0.000003,
"expression_friendly": False,
"expression_friendly_multiplier": 1,
"lip_zero": False,
"lip_zero_threshold": 0.03,
"mismatch_method": "constant",
"pipeline": [
"60",
0
],
"relative_motion_mode": "relative",
"source_image": [
"3",
0
],
"stitching": True
},
"_meta": {
"title": "LivePortrait Process"
}
},
"49": {
"class_type": "LivePortraitComposite",
"inputs": {
"cropped_image": [
"47",
0
],
"liveportrait_out": [
"47",
1
],
"source_image": [
"3",
0
]
},
"_meta": {
"title": "LivePortrait Composite"
}
},
"51": {
"class_type": "LivePortraitCropper",
"inputs": {
"cropper": [
"59",
0
],
"dsize": 512,
"face_index": 0,
"face_index_order": "large-small",
"pipeline": [
"60",
0
],
"rotate": True,
"scale": 2,
"source_image": [
"3",
0
],
"vx_ratio": 0,
"vy_ratio": -0.125
},
"_meta": {
"title": "LivePortrait Cropper"
}
},
"59": {
"class_type": "LivePortraitLoadMediaPipeCropper",
"inputs": {
"keep_model_loaded": True,
"landmarkrunner_onnx_device": "CPU"
},
"_meta": {
"title": "LivePortrait Load MediaPipeCropper"
}
},
"60": {
"class_type": "DownloadAndLoadLivePortraitModels",
"inputs": {
"mode": "human",
"precision": "auto"
},
"_meta": {
"title": "(Down)Load LivePortraitModels"
}
}
})
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)