# 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": "KSampler",
"inputs": {
"cfg": 1,
"denoise": 1,
"latent_image": [
"98",
0
],
"model": [
"78",
0
],
"negative": [
"47",
0
],
"positive": [
"94",
0
],
"sampler_name": "euler",
"scheduler": "simple",
"seed": 31,
"steps": 8
},
"_meta": {
"title": "KSampler"
}
},
"18": {
"class_type": "VAEDecodeAudio",
"inputs": {
"samples": [
"3",
0
],
"vae": [
"106",
0
]
},
"_meta": {
"title": "VAE Decode Audio"
}
},
"47": {
"class_type": "ConditioningZeroOut",
"inputs": {
"conditioning": [
"94",
0
]
},
"_meta": {
"title": "Conditioning Zero Out"
}
},
"78": {
"class_type": "ModelSamplingAuraFlow",
"inputs": {
"model": [
"104",
0
],
"sampling": "flow",
"shift": 3
},
"_meta": {
"title": "ModelSamplingAuraFlow"
}
},
"94": {
"class_type": "TextEncodeAceStepAudio1.5",
"inputs": {
"bpm": 195,
"cfg_scale": 2,
"clip": [
"105",
0
],
"duration": 75,
"generate_audio_codes": True,
"keyscale": "E minor",
"language": "en",
"lyrics": "[Intro]\n\n[Verse 1]\nConcrete cracked and the summer's gone\nWheels on fire since the break of dawn\nNobody's waiting at the end of the street\nJust the hum of the city and the sound of our feet\n\n[Chorus]\nHey! Hey! Never slowing down!\nHey! Hey! Burn across this town!\n\n[Verse 2]\nRusted rails and a broken fence\nEvery bruise is a souvenir of sense\nCoast on the edge of the parking lot light\nWe don't need a reason, we just need the night\n\n[Chorus]\nHey! Hey! Never slowing down!\nHey! Hey! Burn across this town!\n\n[Outro]",
"min_p": 0,
"seed": 31,
"tags": "Genre: Fast-paced 1990s skate punk.\nTempo: 195 BPM.\nKey: E minor.\nMood: Raw, frantic aggression that builds into triumphant catharsis.\nProduction Style: Dry, abrasive basement demo production with biting midrange and saturated transient punch.\nInstrumentation: Searing buzzsaw lead electric guitar, overdriven solid-body rhythm guitar, gritty picked electric bass, and a pummeling drum kit heavy on tight snare rolls and bright crash cymbals.\nArrangement:\n- Intro: Blistering drum fill into a high-speed descending lead guitar run.\n- Verse: Rapid palm-muted power chords over a driving, walking bassline and urgent double-time beat.\n- Chorus: Explosive, wide open chords driven by raw, passionate, shouted group vocals chanting a short English refrain.\n- Outro: Sudden syncopated full-band stop accented by a harsh burst of trailing amplifier feedback.",
"temperature": 0.85,
"timesignature": "4",
"top_k": 0,
"top_p": 0.9
},
"_meta": {
"title": "TextEncodeAceStepAudio1.5"
}
},
"98": {
"class_type": "EmptyAceStep1.5LatentAudio",
"inputs": {
"batch_size": 1,
"seconds": 75
},
"_meta": {
"title": "Empty Ace Step 1.5 Latent Audio"
}
},
"104": {
"class_type": "UNETLoader",
"inputs": {
"unet_name": "acestep_v1.5_turbo.safetensors",
"weight_dtype": "default"
},
"_meta": {
"title": "Load Diffusion Model"
}
},
"105": {
"class_type": "DualCLIPLoader",
"inputs": {
"clip_name1": "qwen_0.6b_ace15.safetensors",
"clip_name2": "qwen_1.7b_ace15.safetensors",
"device": "default",
"type": "ace"
},
"_meta": {
"title": "Load CLIP (Dual)"
}
},
"106": {
"class_type": "VAELoader",
"inputs": {
"vae_name": "ace_1.5_vae.safetensors"
},
"_meta": {
"title": "Load VAE"
}
},
"107": {
"class_type": "SaveAudioMP3",
"inputs": {
"audio": [
"18",
0
],
"filename_prefix": "audio/ComfyUI",
"quality": "V0"
},
"_meta": {
"title": "Save Audio (MP3) (DEPRECATED)"
}
}
})
# 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("107"):
output.to_file(output.name)