Protoface Seed Speech TTS 2.0 · Text to Speech
Forty voices, one kilobyte of text per call
- audio
- files
- run id
Why pay for TTS when Kokoro is free
Fair question, and the KB's answer is that local TTS in ComfyUI is genuinely viable now - Kokoro and Piper run on CPU, Chatterbox clones a voice under 8GB, and TTS Audio Suite wraps several engines. The catch is what that layer costs you in maintenance: dependency conflicts between engines are the default failure mode of audio in ComfyUI, and the whole thing exists because TTS was never designed into the graph.
Seed Speech TTS 2.0 is the other trade. One node, no engines, no transformers version roulette - and forty voice presets across ten-ish languages, which is more than most local stacks will hand you without downloading another suite. The bill is per character, with a minimum of one credit a request, and the catalog's units suggest you're paying in fractions of a cent per word. For a voiceover on a project that has a budget, that's fine. For "read me this paragraph forty times while I tune the timing," it isn't.
The mechanism
Every Protoface node is a client: the pack posts your text and settings to the Protoface API, polls the async job, downloads the result and returns a native ComfyUI AUDIO object. Controls are generated from the provider's public request schema, so each field maps to something their API takes. Your script text leaves your machine - worth a thought if it's an unreleased client document.
The controls
text is a single-line string, not a multiline box, and this is where the big constraint lives: the provider clips a request at 1000 characters. Long scripts need chunking into several nodes and a concatenation step, or a local engine. Nothing in the node warns you when you paste 4000 characters; you get one clipped reading.
voice defaults to stokie_en and the preset list is a trip: forty entries with language suffixes like mindy_en_es_id_pt_zh, sven_de, minimi_ja, usseau_fr, pinky_es_ko_mixed_en_zh. Decoding the names tells you which voices are multilingual - _mixed_ presets are built for multi-language output, single-language ones for clean delivery in one.
language is optional and exists to override detection; leave it unset and the model figures it out from the text. Override it for mixed-language scripts where you know what the body of the text is.
voice_instruction is the sleeper feature: a free-text direction like "tired, quiet, slightly impatient" that shapes delivery and is not spoken aloud. That's the local-model gap - most open TTS gives you a speed dial, not a mood.
speed (0.5–2.0), volume (0.5–2.0) and pitch (−12 to +12 semitones) are the knobs to reach for before rerolling a whole take. sample_rate is 8000 to 48000 with 24000 default - go higher if the audio will be processed or slowed down. output_format is mp3 or opus.
generation_id handles the paid job: fixed ID with identical inputs resumes the recorded run; increment for a fresh generation. request_scope is auto-assigned per node, non-secret, only relevant headless.
Outputs: audio (list, native AUDIO), files (originals), run id.
Install
ComfyUI 0.41.0+ and Python 3.10+.
cd ComfyUI
git clone --branch v0.1.0 --depth 1 https://github.com/protoface-ai/protoface-comfyui.git custom_nodes/protoface
python -m pip install -r custom_nodes/protoface/requirements.txt
Manager route works too: search Protoface, install protoface-nodes, restart, reload. Pip with ComfyUI's interpreter. Then click Protoface bottom-right and paste your key, or export PROTOFACE_API_KEY. Requirements are httpx, jsonschema, Pillow and PyAV - PyAV being the one that actually gets touched when decoding returned audio.
Where it goes wrong
The 1000-character clip. Split long narration yourself. And note the per-request minimum: five short chunks cost more than one full request.
Wiring the output somewhere that wants a file. audio is a native ComfyUI AUDIO object; the sibling files output is where the actual downloaded file lives, and Protoface Save File writes originals to ComfyUI's output directory.
Iterating by re-queueing. Same inputs plus a fixed generation_id resumes rather than re-bills - but changing the text is a new request by definition. Get the text settled before you start tuning delivery.
Expecting a clone. This is a preset TTS model, not a voice-cloning one. If you need a specific person's voice, that's a different tool.
Timeout ≠ failed job. Requeue unchanged or use run id in Resume Run; don't increment generation_id and pay twice for one render.
Verdict
The most boringly useful node in the pack. Feed it to a video node's audio input and you've got narration for a clip without leaving ComfyUI or installing a speech stack. Keep your lines under a thousand characters and use voice_instruction more than you think you should - it's the part that sounds like direction rather than a text box.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | The text to synthesize into speech. | |
| language | COMBO | Optional language override. Leave unset for automatic language detection. | |
| output_format | COMBO | mp3 | Output audio format. |
| pitch | INT | 0-12–12 | Voice pitch shift in semitones. 0 is normal pitch. |
| sample_rate | COMBO | 24000 | Sample rate of the output audio in Hz. |
| speed | FLOAT | 1.00.5–2 | Speech speed. 1.0 is normal speed. |
| voice | COMBO | stokie_en | Voice preset to use for speech synthesis. |
| voice_instruction | COMBO | Optional natural-language instruction for tone, emotion, pace, or volume. It is not spoken aloud. | |
| volume | FLOAT | 1.00.5–2 | Speech volume. 1.0 is normal volume. |
| generation_id | INT | 00–9007199254740991 | Keep fixed to reuse/resume this paid job. Increment for a fresh paid generation; independent of the model seed. |
| request_scope | STRING | Automatically assigned per node. Headless clients must supply a stable unique workflow/node ID. This is not a secret. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| audio | AUDIO | — |
| files | PROTOFACE_FILE | — |
| run id | STRING | — |