# 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({
"483": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_FILENAME"
},
"_meta": {
"title": "Load Image"
}
},
"1185": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_2_FILENAME"
},
"_meta": {
"title": "Load Image"
}
},
"1235": {
"class_type": "GeminiNanoBanana2",
"inputs": {
"aspect_ratio": "9:16",
"images": [
"1236",
0
],
"model": "Nano Banana 2 (Gemini 3.1 Flash Image)",
"prompt": "Character with product",
"resolution": "2K",
"response_modalities": "IMAGE",
"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.",
"thinking_level": "MINIMAL"
},
"_meta": {
"title": "Nano Banana 2"
}
},
"1236": {
"class_type": "BatchImagesNode",
"inputs": {
"images.image0": [
"483",
0
],
"images.image1": [
"1185",
0
]
},
"_meta": {
"title": "Batch Images"
}
},
"1237": {
"class_type": "SaveVideo",
"inputs": {
"filename_prefix": "video/gsc_advanced_1",
"format": "auto",
"format.codec": "auto",
"video": [
"1239",
0
]
},
"_meta": {
"title": "Save Video"
}
},
"1239": {
"class_type": "KlingOmniProImageToVideoNode",
"inputs": {
"aspect_ratio": "9:16",
"duration": 9,
"generate_audio": True,
"model_name": "kling-v3-omni",
"prompt": "addictive hook ad",
"reference_images": [
"1244",
0
],
"resolution": "1080p",
"seed": 85124566,
"storyboards": "3 storyboards",
"storyboards.storyboard_1_duration": 3,
"storyboards.storyboard_1_prompt": "\"My skin hits different\"",
"storyboards.storyboard_2_duration": 3,
"storyboards.storyboard_2_prompt": "\"I love this shit\", ambient sounds",
"storyboards.storyboard_3_duration": 3,
"storyboards.storyboard_3_prompt": "product packshot, ambient sounds"
},
"_meta": {
"title": "Kling 3.0 Omni Image to Video"
}
},
"1242": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "gsc_advanced_1",
"images": [
"1235",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"1244": {
"class_type": "BatchImagesNode",
"inputs": {
"images.image0": [
"1235",
0
],
"images.image1": [
"1185",
0
]
},
"_meta": {
"title": "Batch Images"
}
}
})
# Replace each example.com URL with a public URL of your file.
workflow.set_input("483", "image", client.assets.from_url("https://example.com/replace-with-a-url/image"))
workflow.set_input("1185", "image", client.assets.from_url("https://example.com/replace-with-a-url/image_2"))
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)