# 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({
"76": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_FILENAME"
},
"_meta": {
"title": "Load Image"
}
},
"81": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_reference_image_FILENAME"
},
"_meta": {
"title": "Load Image"
}
},
"94": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "Flux2-Klein-4b-base",
"images": [
"92:104",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"92:102": {
"class_type": "KSamplerSelect",
"inputs": {
"sampler_name": "euler"
},
"_meta": {
"title": "KSamplerSelect"
}
},
"92:103": {
"class_type": "SamplerCustomAdvanced",
"inputs": {
"guider": [
"92:114",
0
],
"latent_image": [
"92:109",
0
],
"noise": [
"92:105",
0
],
"sampler": [
"92:102",
0
],
"sigmas": [
"92:115",
0
]
},
"_meta": {
"title": "SamplerCustomAdvanced"
}
},
"92:104": {
"class_type": "VAEDecode",
"inputs": {
"samples": [
"92:103",
0
],
"vae": [
"92:107",
0
]
},
"_meta": {
"title": "VAE Decode"
}
},
"92:105": {
"class_type": "RandomNoise",
"inputs": {
"noise_seed": 0
},
"_meta": {
"title": "RandomNoise"
}
},
"92:106": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "flux-2-klein-base-9b-fp8.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"92:107": {
"class_type": "VAELoader",
"inputs": {
"vae_name": "flux2-vae.safetensors"
},
"_meta": {
"title": "Load VAE"
}
},
"92:108": {
"class_type": "GetImageSize",
"inputs": {
"image": [
"92:110",
0
]
},
"_meta": {
"title": "Get Image Size"
}
},
"92:109": {
"class_type": "EmptyFlux2LatentImage",
"inputs": {
"batch_size": 1,
"height": [
"92:108",
1
],
"width": [
"92:108",
0
]
},
"_meta": {
"title": "Empty Flux 2 Latent"
}
},
"92:110": {
"class_type": "ImageScaleToTotalPixels",
"inputs": {
"image": [
"76",
0
],
"megapixels": 1,
"resolution_steps": 1,
"upscale_method": "nearest-exact"
},
"_meta": {
"title": "Scale Image to Total Pixels"
}
},
"92:111": {
"class_type": "CLIPLoader",
"inputs": {
"clip_name": "qwen_3_8b_fp8mixed.safetensors",
"device": "default",
"type": "flux2"
},
"_meta": {
"title": "Load CLIP"
}
},
"92:112:116": {
"class_type": "ReferenceLatent",
"inputs": {
"conditioning": [
"92:87",
0
],
"latent": [
"92:112:117",
0
]
},
"_meta": {
"title": "Set Reference Latent"
}
},
"92:112:117": {
"class_type": "VAEEncode",
"inputs": {
"pixels": [
"92:110",
0
],
"vae": [
"92:107",
0
]
},
"_meta": {
"title": "VAE Encode"
}
},
"92:112:118": {
"class_type": "ReferenceLatent",
"inputs": {
"conditioning": [
"92:113",
0
],
"latent": [
"92:112:117",
0
]
},
"_meta": {
"title": "Set Reference Latent"
}
},
"92:113": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"92:111",
0
],
"text": "Replace the woven corded lounge chair on the right side of the room with the chair from the reference image: the mid-century upholstered chair with plush emerald green velvet seat and backrest, smooth cream fabric along the sides and a dark walnut frame with tapered legs. Place it on the woven rug at the same spot, angled toward the sofa at a natural three-quarter view, scaled correctly to the room and the olive sectional. Match the soft daylight from the tall windows, with gentle shadows falling onto the rug and a subtle sheen on the velvet. Keep the double-height living room, the paper pendant lamp, the oak paneling, the staircase, the oak armchairs, the black coffee table, the abstract painting, the camera angle and the lighting completely unchanged. Photorealistic interior photography."
},
"_meta": {
"title": "CLIP Text Encode (Positive Prompt)"
}
},
"92:114": {
"class_type": "CFGGuider",
"inputs": {
"cfg": 5,
"model": [
"92:106",
0
],
"negative": [
"92:84:119",
0
],
"positive": [
"92:84:121",
0
]
},
"_meta": {
"title": "CFG Guider"
}
},
"92:115": {
"class_type": "Flux2Scheduler",
"inputs": {
"height": [
"92:108",
1
],
"steps": 20,
"width": [
"92:108",
0
]
},
"_meta": {
"title": "Flux2Scheduler"
}
},
"92:84:119": {
"class_type": "ReferenceLatent",
"inputs": {
"conditioning": [
"92:112:116",
0
],
"latent": [
"92:84:120",
0
]
},
"_meta": {
"title": "Set Reference Latent"
}
},
"92:84:120": {
"class_type": "VAEEncode",
"inputs": {
"pixels": [
"92:85",
0
],
"vae": [
"92:107",
0
]
},
"_meta": {
"title": "VAE Encode"
}
},
"92:84:121": {
"class_type": "ReferenceLatent",
"inputs": {
"conditioning": [
"92:112:118",
0
],
"latent": [
"92:84:120",
0
]
},
"_meta": {
"title": "Set Reference Latent"
}
},
"92:85": {
"class_type": "ImageScaleToTotalPixels",
"inputs": {
"image": [
"81",
0
],
"megapixels": 1,
"resolution_steps": 1,
"upscale_method": "nearest-exact"
},
"_meta": {
"title": "Scale Image to Total Pixels"
}
},
"92:87": {
"class_type": "CLIPTextEncode",
"inputs": {
"clip": [
"92:111",
0
],
"text": ""
},
"_meta": {
"title": "CLIP Text Encode ( Negative Prompt)"
}
}
})
workflow.set_input("76", "image", client.assets.from_url("https://comfy.org/catalog-media/770b4262-9536-4046-b9b8-07a9e820b3db/13344aa2-bed2-489e-9004-7a1893b1c19d"))
workflow.set_input("81", "image", client.assets.from_url("https://comfy.org/catalog-media/969dc50c-6711-49b0-b129-27439b283721/5d2bfe11-0757-4584-99de-4fd83f3726b7"))
# 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("94"):
output.to_file(output.name)