ComfyUI Node

Gemini TTS

2,000 voices, one text box, and a typo that costs you a run

By Aryan185·Created about a year ago·Updated a day ago· 14
Gemini TTS
    • audio
    ◄text►
    ◄voiceBodi►
    ◄modelgemini-3.8-flash-tts►
    ◄api_key►
    ◄seed69►
    ◄temperature1.00►
    ◄style►

    Audio in ComfyUI has always been the awkward layer. The models are good, the integration is a permanent workaround - you're forever one pip install away from a transformers fight that takes three other packs down with it. So if your workflow ends in a Wan S2V or an LTX render and you just need a voice to feed it, calling Google's speech model from inside the graph is the boring, reliable answer. Transcript in, AUDIO tensor out, right type for SaveAudio or whatever lip-sync node comes next.

    GeminiTTS3Node is the current Gemini TTS node in ComfyUI-ExternalAPI-Helpers. It ships next to an older Gemini TTS (Legacy) in the same pack, and that's the first thing to get straight, because half the tutorials out there were written against the legacy node. If a guide tells you to pick Zephyr from a dropdown and set pace and accent, it's describing that one - this node has no such dropdowns.

    Where the voices come from

    The hook is the voice library. The author's README pitches Google's "Extended Voice Library" - 2,000-plus voices, the kind of names that show up as Bodi, Lumi, Koda, Nika, Tavi - and the legacy celestial set (Puck, Zephyr) still works too. ElevenLabs is still the reliability bar; this is the hosted option that doesn't feel like a downgrade.

    The catch is how you pick one: voice is a plain text field, not a dropdown. Autocomplete won't catch a typo, so a misspelled voice doesn't fail in the UI - it fails when the request hits Google and comes back as a Gemini API Error. Copy names out of AI Studio, not off a screenshot.

    How it works

    The mechanism is straightforward. It builds a google-genai client from your key and streams the response (generate_content_stream), accumulating audio bytes chunk by chunk instead of waiting on one blob.

    • Your text gets wrapped. Unless it already starts with ## Transcript:, the node prepends that header before sending. Don't hand-write your own transcript-style markdown - you're just fighting the wrapper the model expects.
    • That format is what makes the inline tags work. The text tooltip lists the full set the author supports: <breath>, <laugh>, <sigh>, <long pause>, <whispering>, <cough>, and thirty-odd more. They're point-in-time - a breath lands where you typed it - which is the whole reason this is more fun than a straight read-through.

    Audio comes back as raw PCM or a RIFF WAV container; the node decodes it to float32 and returns {"waveform", "sample_rate"}, standard ComfyUI AUDIO. One quirk: IS_CHANGED hashes your inputs, so re-queueing the same graph won't call the API again. Great for your wallet, confusing the first time you hit Queue expecting a different take. Change seed for a new one.

    Inputs that matter

    • text - the transcript, inline tags and all. Empty raises immediately.
    • voice - as above, free text, default Bodi.
    • style - the optional acting note, passed through to speech_metadata. The author's example: "Bright, sunny morning greeting with a subtle vocal smile and crisp pacing." Add the Style: prefix yourself or the node does it for you. This is your global direction; the inline tags are the local ones.
    • model - gemini-3.8-flash-tts (default) or gemini-3.8-flash-lite-tts.
    • api_key - a raw key or the name of an env var. temperature and seed are the variation levers; leave them near default until you have a reason.

    Install

    ComfyUI Manager, search ExternalAPI-Helpers, or by hand:

    cd ComfyUI/custom_nodes
    git clone https://github.com/Aryan185/ComfyUI-ExternalAPI-Helpers.git
    cd ComfyUI-ExternalAPI-Helpers
    pip install -r requirements.txt
    

    Restart ComfyUI. Then put your key in a .env next to the pack's files - GEMINI_API_KEY=... - and set api_key to GEMINI_API_KEY instead of pasting the raw key into the widget. Workflow JSONs get shared freely, and a key baked into a widget travels with them. Free key over at AI Studio.

    Where people get burned

    Don't skip requirements.txt. This node alone needs only google-genai and torch, but the pack's __init__.py imports every module in the pack on load, with no per-module guard. One missing dependency - av and opencv-python are in there for the video and image nodes - takes the whole pack down, and it fails as "no Gemini TTS node in the menu," not as anything naming the real culprit.

    Long scripts need chunking. True of TTS in this ecosystem generally, not just here: past a couple of minutes of narration, people cut the transcript into beats and stitch the audio afterward. Long speech either crashes or gets worse.

    Your key and text leave the machine. This is an API node - the category that already shipped credential-stealing malware once under a friendly "vision node" name. Verify this pack rather than assuming.

    If you get Gemini API Error, the raw API message is in the traceback - usually a bad voice name or exhausted quota. If you get "contained no audio data," the request went through and came back without speech; reword and re-run rather than assuming the node broke.

    Categoryaudio/generation

    Inputs (7)

    NameTypeDefaultDescription
    textSTRINGTranscript text. Supports inline tags: <argh>, <breath>, <cackle>, <cheer>, <chuckle>, <chuckles>, <cough>, <cry>, <exhales>, <gasp>, <giggle>, <groan>, <growl>, <grr>, <grunt>, <heavy breath>, <hiss>, <laugh>, <laughter>, <long pause>, <moan>, <pant>, <pff>, <phew>, <scream>, <short pause>, <shout>, <shriek>, <sigh>, <sighs>, <sneeze>, <snicker>, <snort>, <sob>, <throat-clearing>, <tsk>, <whimper>, <whispering>, <whispers>, <yawn>
    voiceSTRINGBodiVoice name from AI Studio (e.g. Bodi, Lumi, Sola, Koda, Nika, Tavi, Kira, Ludo, or legacy celestial names like Puck, Zephyr)
    modelCOMBOgemini-3.8-flash-tts2 options: gemini-3.8-flash-tts, gemini-3.8-flash-lite-tts
    api_keySTRINGDirectly put Gemini API key or .env variable name (GEMINI_API_KEY)
    seedINT69-1–2147483646—
    temperatureFLOAT1.000–2—
    styleoptSTRINGActing style passed to speech_metadata (e.g. 'Bright, sunny morning greeting with a subtle vocal smile and crisp pacing.')

    Outputs (1)

    NameTypeDescription
    audioAUDIO—