Gemini 3.1 Flash Text to speech
3.1 Flash, Same Cast, Smaller Bill
- audio
- url
- all_urls_json
- task_id
- raw_json
- credits_consumed
- credits_left
What it's for
This is the Flash tier of Google's dialogue TTS, and it exists for the same reason fast image models exist: auditioning is expensive if you audition on the flagship. You get the same shape of node - a cast of speakers, a script of turns, delivery cues in the text - and you get audio back faster and cheaper.
The honest use is a two-pass workflow. Cold-read your script on Flash: does the joke land, are the two voices distinguishable, is the pacing right, does the scene note do anything. Then re-run the takes you're actually keeping on the Pro node. What you're giving up in the swap is fine performance detail - the subtle stuff, the exact accent, the emotional precision - and that's not what you're evaluating in a draft.
For single-voice narration the calculus is different, and worth saying out loud: open TTS running locally is genuinely competitive now, costs nothing per call, and keeps your script on your machine. Paid dialogue TTS earns its place on multi-speaker scenes and performance direction, not on "read me a paragraph."
How it works
The node parses your two JSON fields locally, submits the request to KIE with the key from Connection Settings, waits for the task, then downloads the resulting audio as a native ComfyUI AUDIO object. Local parsing is worth noting: bad JSON fails immediately and for free, before a single credit moves.
The model then walks the dialogue turns in order, assigning each line to the speaker it names and applying the delivery you've described - per-speaker style and pace from the speaker table, plus any inline bracketed cues inside a line. Everything lands in one file in script order, so the whole exchange stays glued together and the voices stay consistent across it.
Inputs and outputs
Two required JSON arrays, both multiline text widgets:
speakers- "List of speaker configurations." Each entry needs aspeaker_idand avoice_name(the shipped defaults use Gemini's prebuilt voicesFenrirandPuck), and can carryaudio_profile(a one-line character description - this is the field that actually steers the read), plusaccent,styleandpace.dialogue_turns- "List of dialogue turns, output in sequential order." Each turn names aspeaker_idand gives thetext, with cues like[shouting]or[whispers]inline.
Optional: scene and sample_context for setting and overall tone, temperature (FLOAT, default 1, min 0, max 2, step 0.01) for how loose the delivery gets, timeout_seconds (INT, default 1200, min 30, max 7200, step 30), and callback_url, which you should leave empty for normal ComfyUI use.
Outputs: audio (AUDIO), url, all_urls_json, task_id, raw_json (STRING), credits_consumed, credits_left (FLOAT). audio goes into your video or save node; url is for anything outside the graph.
Because the schema is identical to the Pro sibling node, swapping between them is a drop-in - same JSON, same wires. That's the nicest thing about this pair.
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 set the key at Settings → KIE.ai Nodes Next → Connection. The pack validates it against KIE before overwriting a working key and shows a masked fingerprint plus a CONNECTED status; the full key stays backend-side and out of your workflow JSON. Headless installs can use KIE_API_KEY, which takes priority.
Dependencies are requests, Pillow, numpy, PyYAML. Nothing model-shaped installs, and nothing downloads - the pack is a network client. Windows users can run the installer in dist/.
Where people get burned
JSON typos first, always. The long arrays are where this bites: one unescaped quote and the node refuses before the call. Edit values, not structure.
Then the expectation gap between tiers. Flash is the draft model; if a line feels flat on Flash it may well sing on Pro with the same script, so don't rewrite your script to fix a performance the cheaper model couldn't deliver. Conversely, if two voices are indistinguishable on Flash because your audio_profile fields are too vague, they'll blend on Pro too. Fix the descriptions.
And the price habit: because this tier is inexpensive, it's easy to rerun a scene ten times while fiddling with a comma. Add up credits_consumed over a session and decide whether the take you're chasing is worth it - and remember that the alternative for plain narration is free, local, and doesn't send your script anywhere.
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 | — |