# 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({
"1": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "Casting_Previs",
"images": [
"19",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"11": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_FILENAME"
},
"_meta": {
"title": "TALENT HEADSHOT"
}
},
"13": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_2_FILENAME"
},
"_meta": {
"title": "ENVIRONMENT IMAGE (OPTIONAL)"
}
},
"15": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_3_FILENAME"
},
"_meta": {
"title": "PRODUCT IMAGE (OPTIONAL)"
}
},
"17": {
"class_type": "StringConcatenate",
"inputs": {
"delimiter": "",
"string_a": "Generate a still frame from a high-end video production with professional color grading, using the input person, product (optional), and environment (optional) as references.",
"string_b": "a medium wide shot of the talent, wearing tennis attire, is enjoying a sip of the soda with eyes closed and a joyful expression while standing in the tennis court"
},
"_meta": {
"title": "Concatenate Text"
}
},
"18": {
"class_type": "ImageBatchMulti",
"inputs": {
"image_1": [
"11",
0
],
"image_2": [
"15",
0
],
"image_3": [
"13",
0
],
"inputcount": 3
},
"_meta": {
"title": "Image Batch Multi"
}
},
"19": {
"class_type": "GeminiImage2Node",
"inputs": {
"aspect_ratio": "16:9",
"images": [
"18",
0
],
"model": "gemini-3-pro-image-preview",
"prompt": [
"17",
0
],
"resolution": "1K",
"response_modalities": "IMAGE+TEXT",
"seed": 0,
"system_prompt": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input—regardless of format, intent, or abstraction—as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests."
},
"_meta": {
"title": "Nano Banana Pro (Google Gemini Image)"
}
},
"20": {
"class_type": "KlingOmniProImageToVideoNode",
"inputs": {
"aspect_ratio": "16:9",
"duration": 5,
"generate_audio": False,
"model_name": "kling-v3-omni",
"prompt": [
"24",
0
],
"reference_images": [
"23",
0
],
"resolution": "720p",
"seed": 1766898599,
"storyboards": "disabled"
},
"_meta": {
"title": "Kling 3.0 Omni Image to Video"
}
},
"22": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_4_FILENAME"
},
"_meta": {
"title": "FIRST FRAME"
}
},
"23": {
"class_type": "ImageBatchMulti",
"inputs": {
"image_1": [
"22",
0
],
"image_2": [
"11",
0
],
"inputcount": 3
},
"_meta": {
"title": "Image Batch Multi"
}
},
"24": {
"class_type": "StringConcatenate",
"inputs": {
"delimiter": "",
"string_a": "use the first image as first frame, and the second image as the character reference. Generate: ",
"string_b": "A woman takes a sip of the drink with joy, and then looks at the can. Camera slowly dollies in."
},
"_meta": {
"title": "Concatenate Text"
}
},
"26": {
"class_type": "SaveVideo",
"inputs": {
"filename_prefix": "video/Casting_Previs",
"format": "auto",
"format.codec": "auto",
"video": [
"20",
0
]
},
"_meta": {
"title": "Save Video"
}
}
})
# Replace each example.com URL with a public URL of your file.
workflow.set_input("11", "image", client.assets.from_url("https://example.com/replace-with-a-url/image"))
workflow.set_input("13", "image", client.assets.from_url("https://example.com/replace-with-a-url/image_2"))
workflow.set_input("15", "image", client.assets.from_url("https://example.com/replace-with-a-url/image_3"))
workflow.set_input("22", "image", client.assets.from_url("https://example.com/replace-with-a-url/image_4"))
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)