Gemini 3.8 Flash TTS · Text to Speech
30 voices, cues that get acted out, half the Pro price
- audio
- task id
Of the three Gemini text-to-speech nodes in this pack, this is the one I'd wire up first. $0.00032 per second, 30 voices, 24 kHz mono WAV, and - the part that matters - bracketed cues are acted rather than read. Write [whispering], [sighs], [laughing] and you get a performance, not the word "laughing" in a flat voice.
It's the middle of the line. Gemini 2.5 Pro TTS costs about 40% more per second and takes direction slightly better; Gemini 3.8 Flash-Lite is cheaper still but treats bracket cues much less reliably. If you want one node to keep in a narration workflow, Flash is the sweet spot, and the instructions and scene fields are where you get the remaining quality for free.
What happens when you run it
The script and settings go to SpicyAPI, the hosted model renders audio, and the pack hands it back as a ComfyUI AUDIO. Nothing is installed locally and no voice model occupies your VRAM, which is the point of the pack on a CPU-only or laptop install. One behaviour to know before you wire it: multiple results can come back as a batch, and Save Audio writes one file for each.
Inputs
text- spoken exactly as written. Put direction inside the text where you want it acted:[whispering] don't tell anyone.voice_id- 30 prebuilt voices,Koreby default. Fixed character per voice; audition rather than assume.style,pace,accent- all default to the model's own choice on this node. Set them when you want a specific read rather than a discovery.instructions- how to read: mood, distance from the microphone, who's listening. Not spoken, not billed.scene- where and to whom the words are spoken. Also unbilled, also effective.temperature- −1 leaves it to the model; up to 2 for more variation between takes.dialogue+speakers- two-voice conversations as JSON, used instead oftext. Leavetextempty when you take this route.
Speakers look like this:
[{"name": "Narrator", "voice_id": "Kore", "style": "calm"}]
and each line references a speaker by name:
[{"speaker": "Narrator", "text": "[sighs] Nobody came back that winter."}]
Outputs are audio and task id - the second a STRING naming the request in SpicyAPI's logs.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/spicyapi-ai/comfyui-spicyapi
Restart ComfyUI, then Settings > SpicyAPI → paste a key from spicyapi.ai/console/keys, or set SPICY_API_KEY in the environment on a headless machine. Restart again so the node list comes from your account. ComfyUI Manager: search SpicyAPI. The pack installs no Python packages and downloads no models.
Cost
$0.00032 per second of audio, so a two-minute narration runs to a few cents. The rate is on the node, and each run is quoted before it's submitted. Settings > SpicyAPI > Max cost per run is the ceiling: a run quoted above it never goes out. Because the pack sets seeds to fixed, re-queueing a graph reuses the result instead of buying another read - handy for TTS, where you often don't want a reroll, and mildly annoying when you do.
If a cue gets read aloud instead of performed, that's the model being literal rather than a bug: rephrase it as a described action inside the text, which is the more reliable shape on the Flash tiers.
Errors you'll meet: No SpicyAPI key is set, 40310 (unverified email), 40004 (no deployment serves that combination; the field is named, nothing charged), and request_id ... for support. Bad JSON in dialogue or speakers is an input error - check it before blaming the service.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | The words to be spoken, exactly as written. Direction such as [whispering] or [sighs] goes into the text itself. | |
| dialogue | STRING | A scripted conversation, used instead of text: each line names a speaker from speakers. JSON. A list of objects with "text", "speaker". | |
| speakers | STRING | The cast for dialogue: one or two voices, each with a name the lines refer to. JSON. A list of objects with "name", "pace"?, "style"?, "accent"?, "profile"?, "voice_id". | |
| voice_id | COMBO | Kore | Prebuilt voice that reads the text. Each voice has a fixed character. |
| style | COMBO | model default | Overall manner of the reading. Omit it to use the voice's own default manner. |
| pace | COMBO | model default | Rhythm of the reading. Omit it to keep the voice's own rhythm. |
| accent | COMBO | model default | English accent used for the reading. |
| instructions | STRING | How to read the text: mood, distance from the microphone, who is listening. Shapes the delivery and is not spoken. | |
| scene | STRING | Where and to whom the words are spoken. Shapes the delivery and is not spoken. | |
| temperature | FLOAT | -1.00-1–2 | Variation between takes; higher is less predictable. -1 leaves it to the model. |
| seed | INT | 00–2147483647 | This model takes no seed, so the number is never sent. Changing it makes ComfyUI run the node again: set 'control after generate' to randomize for a new result on every run; every run is billed. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| audio | AUDIO | Several results come back as a batch; Save Audio writes one file each. |
| task id | STRING | The SpicyAPI task id, for the console logs or support. |