Gemini 2.5 Pro Text to Speech
Gemini 2.5 Pro Text to Speech
- audio
- url
- all_urls_json
- task_id
- raw_json
- credits_consumed
- credits_left
What it's for
Most TTS nodes read one string in one voice. This one stages a scene. You define a cast of speakers - each with a voice, an accent, a style, a pace, even a character note - then write dialogue turns and tag the lines with delivery directions. The model performs the whole exchange and hands you back audio.
That puts it in a different category from "narration." It's the node you reach for when you want a two-hander: a radio-play bit, a game-style NPC exchange, a skit, a fictional podcast, dialogue for a character in a video you're cutting. Because the turns come back in sequence in one file, you don't have to stitch separate takes together, and the voices stay consistent across the whole conversation - which is the part that's genuinely hard to fake with a regular TTS node.
On the local-versus-API question: open TTS got genuinely good, and for plain single-voice narration you should absolutely consider running it at home rather than paying per call. Where a hosted model still earns its money is exactly this - multi-speaker dialogue, performance direction, and the long tail of accents. That's the trade here.
How it works
The node takes two JSON strings, parses them locally into the KIE request, submits the job with your saved key, waits for the task to complete and downloads the audio into a native ComfyUI AUDIO object. Because the JSON is parsed before submission, malformed input fails fast and locally - before anything is billed, which is the behaviour you want on a metered API.
The model's job is scheduling: it reads the speaker table to establish voices and delivery, then walks the dialogue turns in order, applying the inline directions it finds in the text. The defaults shipped on the node show the intended style clearly - bracketed cues like [shouting], [pensive], [whispers] inside a line, and per-speaker style and pace fields like "Deadpan" and "Staccato."
Inputs and outputs
Both required inputs are JSON arrays, edited as multiline text widgets:
speakers- "List of speaker configurations." Each entry carriesspeaker_id,voice_name(the defaults use Gemini's prebuilt voice names, e.g.FenrirandPuck), plusaudio_profile,accent,styleandpace. Theaudio_profileis a short character description, which is where you actually steer the performance.dialogue_turns- "List of dialogue turns, output in sequential order." Each entry is aspeaker_idplus the line oftext, with delivery cues inline in brackets.
Optional: scene and sample_context are both free text that set overall tone and setting - "A quiet, warm room with a fireplace" alongside "Audiobook style narration." temperature (FLOAT, default 1, range 0–2, step 0.01) controls variation in delivery; drop it for consistency, raise it for a looser read. timeout_seconds is the usual INT, default 1200, min 30, max 7200, step 30. And callback_url - leave it empty for normal ComfyUI use.
Outputs: audio (AUDIO), url, all_urls_json, task_id, raw_json (STRING), credits_consumed, credits_left (FLOAT). Wire audio into a video pipeline, a save-audio node, or a lip-sync tool; url is for anything outside Comfy.
Installing
cd ComfyUI/custom_nodes
git clone https://github.com/felipederosilva/ComfyUI-KIE-Nodes-Next
pip install -r ComfyUI-KIE-Nodes-Next/requirements.txt
Restart ComfyUI, then paste your KIE key at Settings → KIE.ai Nodes Next → Connection. The pack validates the key before saving, then shows a masked fingerprint rather than the key itself; the stored credential lives in ComfyUI's user config and never enters the workflow JSON. KIE_API_KEY handles headless installs.
Requirements: requests, Pillow, numpy, PyYAML. No TTS model downloads, no GPU. On Windows, the one-click installer in dist/ is the documented route.
Where people get burned
JSON syntax, overwhelmingly. These are multiline text widgets, and a stray unescaped quote or a missing comma in a long dialogue_turns array is the single most common failure. The good news is it fails before the call is made. Validate the JSON in a node that previews text, or keep the structure and only ever edit the string values.
Second: speaker IDs must match between the two fields. A turn tagged for a speaker that doesn't exist in the config won't be assigned a voice properly, and you'll hear it.
Third, the one people underrate - accents and delivery are directions to a model, not a channel strip. You can ask for a British RP deadpan and get something in the neighbourhood. If you need a specific performance, plan on a couple of takes with different audio_profile wording rather than one perfect prompt, and check the price per take first, because this is a paid API call each time.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| speakers | STRING | [ { "speaker_id": "Speaker 1", "voice_name": "Fenrir", "audio_profile": "A stern and weary gatekeeper", "accent": "British (RP)", "style": "Deadpan", "pace": "Natural" }, { "speaker_id": "Speaker 2", "voice_name": "Puck", "audio_profile": "A determined and courageous traveler seeking answers.", "accent": "American (Gen)", "style": "Empathetic", "pace": "Staccato" } ] | List of speaker configurations |
| dialogue_turns | STRING | [ { "speaker_id": "Speaker 1", "text": "[shouting] Halt, traveler! The northern pass is sealed by order of the council." }, { "speaker_id": "Speaker 2", "text": "[determination] I carry a message for the elder. Step aside, or I will force my way through." }, { "speaker_id": "Speaker 1", "text": "[caution] No one passes. [pensive] The elder is... he's no longer receiving visitors." }, { "speaker_id": "Speaker 2", "text": "It's too late. [whispers] The shadow... it reached him first. [urgency] You need to leave. [shouting] Now." } ] | List of dialogue turns, output in sequential order |
| temperatureopt | FLOAT | 1.000–2 | Sampling temperature, e.g., 1 |
| sceneopt | STRING | A dark, crumbling dungeon... | Scene description, e.g., "A quiet, warm room with a fireplace crackling softly." |
| sample_contextopt | STRING | Fantasy RPG style... | Sample context/overall tone, e.g., "Audiobook style narration. Tone is gentle and inviting." |
| timeout_secondsopt | INT | 120030–7200 | — |
| callback_urlopt | STRING | Optional KIE callback URL. Leave empty for normal ComfyUI use. |
Outputs (7)
| Name | Type | Description |
|---|---|---|
| audio | AUDIO | — |
| url | STRING | — |
| all_urls_json | STRING | — |
| task_id | STRING | — |
| raw_json | STRING | — |
| credits_consumed | FLOAT | — |
| credits_left | FLOAT | — |