Text to Speech
NeMo Labs Voice Agent synthesizes the bot’s speech with a local text-to-speech (TTS) model that runs in the server
process. The service classes live in nemo_voice_agent/pipecat/services/nemo/tts.py. The factory
get_tts_service_from_config in that file dispatches on tts.model and is what
build_tts (in nemo_voice_agent/pipecat/services/nemo/builders.py) calls.
Available Models
Three local models ship with configurations under
examples/generic_voice_agent/server/server_configs/tts_configs/. The tts.model value is the
dispatch key — it must be exactly one of the three strings below, or the factory raises ValueError.
A fourth option, tts.type: nvidia, routes to a hosted NVIDIA Riva/NIM endpoint instead of a local
model. For endpoint configuration, refer to
NVIDIA NIM endpoints.
For local models, main_model_id is the primary checkpoint and sub_model_id is the secondary one:
the Kokoro voice, the HiFi-GAN vocoder for FastPitch, and null for Magpie. Both accept a
Hugging Face or NGC identifier or a local .nemo path (FastPitch, HiFi-GAN, and Magpie call
restore_from when the string ends in .nemo).
Select a Model
tts.model and tts.model_config live in the top-level configuration
(examples/generic_voice_agent/server/server_configs/default.yaml). ConfigManager merges the sub-YAML
named by model_config after the top-level block, so any key in the sub-YAML takes precedence. For details,
refer to Server configuration.
Then restart the server:
tts.model_config short-circuits the registry: _configure_tts in
nemo_voice_agent/utils/config_manager.py only consults
examples/generic_voice_agent/server/model_registry.yaml when model_config is unset and
server.use_model_registry is true. The registry’s tts_models section lists only
fastpitch-hifigan and hexgrad/Kokoro-82M. Setting model_config explicitly, as the shipped
default does, is the reliable path. For registry behavior, refer to
Model registry.
Shared TTS Keys
The following keys apply to every local model:
The last three have no entry in the shipped YAML files — add them under tts: if you need them.
Chunking and Latency
Text aggregation is not part of the TTS service. Since Pipecat 1.0, it belongs to an
LLMTextProcessor that build_llm_text_processor inserts between the LLM and the TTS service, built
from SimpleSegmentedTextAggregator (nemo_voice_agent/pipecat/utils/text/simple_text_aggregator.py).
That aggregator is why extra_separator includes ,. It emits a chunk at the last valid comma, so
audio starts before the sentence is finished. Its period and comma heuristics avoid splitting on decimals
(3.14), bullet numbering (1.), abbreviations (e.g., Dr.), and times (p.m.).
Pipecat silently ignores the aggregator when you pass it to the TTS service because it drops unknown constructor keyword arguments. Segmentation then degrades without an error. In a custom pipeline, keep the processor upstream of TTS. For the construction pattern, refer to Builders.
If TTS playback stutters on the client, raise transport.audio_out_10ms_chunks in
default.yaml. The shipped value is 8, and Pipecat’s WebSocket default is 4.
Reasoning Models
think_tokens keeps a reasoning model’s reasoning text out of the audio. _handle_think_tokens
tracks the open/close markers across streamed chunks and returns only the text after the closing
token, so the user hears the answer and not the deliberation. Set it to null to think out loud.
When the LLM runs on vLLM with a reasoning parser, the parser strips the reasoning upstream. For details,
refer to Reasoning mode.
Kokoro-Specific Keys
The following settings control Kokoro voice selection, speed, and text normalization behavior.
KokoroTTSService preloads both English pipelines (a = American, b = British) at startup so voice
switches at conversation time do not pay a download cost.
Kokoro is also the canonical component-owned tool provider. setup_tool_calling registers six direct
functions that the LLM can call mid-conversation:
tool_tts_speak_fasterandtool_tts_speak_slower, each applying a 15% relative change.tool_tts_set_speedandtool_tts_reset_speed.tool_tts_set_voiceandtool_tts_reset_voice. The setter acceptsAmerican EnglishorBritish Englishplus gender and maps toaf_heart,am_michael,bf_emma, orbm_george.
The functions are only registered when
llm.enable_tool_calling is true. server.py passes the TTS service in the tool_mixins list. For registration
details, refer to Tool calling. FastPitch-HiFiGAN and
Magpie register no tools.
An RTVI context reset also resets the service: Kokoro’s reset() restores the original speed, voice,
accent, and pipeline, so a new session never inherits the previous caller’s “speak faster”.
Magpie-Specific Keys
The following settings control Magpie language and text normalization behavior.
Magpie warms up at load time by synthesizing a fixed sentence, so the first real turn is not slowed by lazy CUDA initialization.
Licensing Note for Kokoro
Kokoro’s upstream grapheme-to-phoneme stack falls back to espeak-ng through phonemizer, both GPL-3.0,
which this repository excludes. _espeak_gpl_shim.py installs no-op substitutes so kokoro and misaki import
cleanly, and _g2p_fallback.py supplies an Apache-2.0 replacement built on g2p_en that maps ARPAbet
to misaki’s phoneme inventory. Without that fallback, out-of-vocabulary words would be silently
dropped from the audio. Both modules are in nemo_voice_agent/pipecat/services/nemo/.
Record Synthesized Audio
Audio logging captures synthesized output alongside the other session audio when recording is enabled.
build_tts accepts the audio logger built by build_audio_logger, so bot audio is captured when
recording is enabled. For recording configuration, refer to
Audio logging.
Related Topics
Use these pages to understand the upstream language-model stream and configure speech output behavior.
- LLM Backends — select and configure the upstream language model.
- Reasoning Mode — prevent reasoning text from reaching speech output.
- Server Configuration — understand configuration precedence.
- Audio Logging — capture synthesized output.