xAI Text-to-Speech
The pack's shared speech engine, exposed as a bare audio node
- speech
- audioSettings
- audio
This node is where the pack's text-to-speech actually happens, even though it's not the flashiest place to meet it. xAI Text-to-Speech (xai:tts@0, audioInference) takes text and turns it into an AUDIO output - and it's the same speech engine the video nodes lean on. When you feed a script into a lip-sync or avatar workflow, the Speech builder you used under the hood hits something very much like this. Here it's the bare version: text in, audio out, nothing else between you and the result.
The required input isn't a text box either. It's the speech socket - a RUNWARE_SPEECH typed input fed by the Runware/Params → Speech builder. That builder is where the fun lives: a text field (multiline, with support for dialogue speaker tags like [Sam] Hello [Bob] Hi there, plus provider markup like [laughs] or [short pause]), a voice dropdown with a whole catalog of star-named voices (default Zephyr), and volume, speed, and language controls. So the real workflow is: build a Speech, wire it into this node, get audio back. One builder + one model node = a TTS pipeline with a ridiculous number of voices.
How it works
Standard pack machinery: the node builds a request with the speech parameters, sends it over REST through the runware-sdk, and returns the generated speech as a native AUDIO output (the pack decodes audio via soundfile/libsndfile, no FFmpeg needed). The optional audioSettings socket takes a Runware/Params → Audio Settings builder if you want to override the codec side - bitrate (kbps), channels (mono/stereo), and sampleRate - instead of accepting the model defaults. outputFormat defaults to MP3.
The inputs that matter
- speech (required) - wire in a Speech builder; set its
text, pick avoice, adjustspeed/volume/languagethere. - audioSettings - optional Audio Settings builder for bitrate, channels, sample rate.
- numberResults - generate a few takes, each on a different seed.
- outputFormat - MP3 default; that's usually fine.
Output is audio (AUDIO) - wire it into an audio save/playback node, or keep it as the AUDIO many ComfyUI setups now handle natively. The audio is also available as a URL internally, so you can point downstream cloud nodes at it.
Install and API key
Install once for the whole pack:
cd ComfyUI/custom_nodes
git clone https://github.com/Runware/ComfyUI-Runware
pip install -r ComfyUI-Runware/requirements.txt
Restart ComfyUI (or install Runware from ComfyUI Manager). API key from runware.ai/api-keys, set in ComfyUI Settings → Runware API key, exported as RUNWARE_API_KEY, or via runware auth login.
Gotchas
The trap is assuming speech takes plain text - it doesn't; you must build a Speech node and wire it in. Second, the dialogue tags are provider-specific markup, so [laughs] working depends on the voice/provider honoring it - if a tag does nothing, that's not your bug, it's the engine. Third, TTS is cheap but not free, and numberResults multiplies the bill; generate one take, review, adjust. And a genuinely useful detail from the builder's docs: speed at 100 doubles playback, -50 halves it - so rather than re-queueing for a pacing fix, adjust the speed slider and rerun the same text.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| speech | RUNWARE_SPEECH | — | |
| audioSettingsopt | RUNWARE_AUDIOSETTINGS | — | |
| numberResultsopt | INT | 11–4 | Number of results to generate. Each result uses a different seed, producing variations of the same parameters. |
| ttlopt | BOOLEAN | false | Enable to set ttl. Off uses the model's default. |
| ttl_valueopt | INT | 60 | Time-to-live (TTL) in seconds for generated content. Only applies when `outputType` is `URL`. |
| outputFormatopt | COMBO | MP3 | File format for the generated audio. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| audio | AUDIO | — |