# 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({
"4": {
"class_type": "LoadImage",
"inputs": {
"button": {
"clicked": False,
"computedDisabled": False,
"computedHeight": 24,
"label": "choose file to upload",
"last_y": 70,
"name": "upload",
"options": {
"canvasOnly": True,
"serialize": False
},
"type": "button",
"y": 70
},
"image": "de8196b2e4887c7e987d9940dbd4c886bbdab2a04bea3187590426e237408fac.png"
},
"_meta": {
"title": "Load Logo Image"
}
},
"5": {
"class_type": "ImageBatch",
"inputs": {
"image1": [
"4",
0
],
"image2": [
"15",
0
]
},
"_meta": {
"title": "Batch Images (DEPRECATED)"
}
},
"6": {
"class_type": "GeminiImageNode",
"inputs": {
"aspect_ratio": "auto",
"images": [
"7",
0
],
"model": "gemini-2.5-flash-image",
"prompt": "Display the back view of the input image 1, maintain the lighting angle and shadows",
"response_modalities": "IMAGE+TEXT",
"seed": 222,
"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 (Google Gemini Image)"
}
},
"7": {
"class_type": "GeminiImage2Node",
"inputs": {
"aspect_ratio": "1:1",
"images": [
"5",
0
],
"model": "gemini-3-pro-image-preview",
"prompt": "Apply the texture from the matcap in image 2 into the logo from image 1. The logotype is in a 3d studio setting, match the lighting from the matcap",
"resolution": "1K",
"response_modalities": "IMAGE+TEXT",
"seed": 111,
"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)"
}
},
"10": {
"class_type": "ByteDanceFirstLastFrameNode",
"inputs": {
"aspect_ratio": "adaptive",
"camera_fixed": True,
"duration": 5,
"first_frame": [
"7",
0
],
"generate_audio": False,
"last_frame": [
"6",
0
],
"model": "seedance-1-0-pro-250528",
"prompt": "A logo rotates 180 degrees against a white studio background. The logo has a sleek, modern design. The camera remains static, focusing on the logo as it completes a half rotation. The logo's material remains constant throughout the rotation.",
"resolution": "1080p",
"seed": 1014447163,
"watermark": False
},
"_meta": {
"title": "ByteDance First-Last-Frame to Video"
}
},
"11": {
"class_type": "SaveVideo",
"inputs": {
"filename_prefix": "video/ComfyUI",
"format": "auto",
"format.codec": "auto",
"video": [
"10",
0
]
},
"_meta": {
"title": "Save Video"
}
},
"13": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "ComfyUI",
"images": [
"7",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"14": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "ComfyUI",
"images": [
"6",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"15": {
"class_type": "ResizeAndPadImage",
"inputs": {
"image": [
"17",
0
],
"interpolation": "area",
"padding_color": "white",
"target_height": [
"16",
1
],
"target_width": [
"16",
0
]
},
"_meta": {
"title": "Resize And Pad Image"
}
},
"16": {
"class_type": "GetImageSize",
"inputs": {
"image": [
"4",
0
]
},
"_meta": {
"title": "Get Image Size"
}
},
"17": {
"class_type": "LoadImage",
"inputs": {
"button": {
"clicked": False,
"computedDisabled": False,
"computedHeight": 24,
"label": "choose file to upload",
"last_y": 70,
"name": "upload",
"options": {
"canvasOnly": True,
"serialize": False
},
"type": "button",
"y": 70
},
"image": "de8196b2e4887c7e987d9940dbd4c886bbdab2a04bea3187590426e237408fac.png"
},
"_meta": {
"title": "Load Texture Image"
}
}
})
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)