Speech Recognition
NeMo Labs Voice Agent transcribes the user with a cache-aware streaming FastConformer automatic speech recognition (ASR) model that runs locally on the GPU. Audio arrives from the WebSocket transport in 16 ms frames and is buffered into 80 ms chunks. The model decodes each chunk incrementally against a persistent encoder cache, so partial text is available before the user stops speaking.
The service lives in nemo_voice_agent/pipecat/services/nemo/stt.py (NemoSTTService), which wraps the model
loading and cache management in nemo_voice_agent/pipecat/services/nemo/streaming_asr.py
(NemoStreamingASRService). The pipeline stage is constructed by build_stt in
nemo_voice_agent/pipecat/services/nemo/builders.py.
Supported Models
All shipped models are English. Choose based on whether you need end-of-utterance (EOU) prediction or punctuation — no current model gives you both.
NeMo receives stt.model without modification. A plain identifier is resolved with
ASRModel.from_pretrained(). A value ending in .nemo is treated as a local checkpoint path and loaded with
ASRModel.restore_from().
The STT Configuration Block
The default stt block is in examples/generic_voice_agent/server/server_configs/default.yaml:
To switch models, uncomment the second model: line and comment out the first. Keep model_config pointing
at nemo_cache_aware_streaming.yaml — both models are cache-aware FastConformers and share those parameters.
model_config behaves like the large language model (LLM) configuration. The system uses only its
basename, resolved against server_configs/stt_configs/. The sub-YAML overrides the top-level stt
block, not the other way round. The _configure_stt function in
nemo_voice_agent/utils/config_manager.py logs each override at startup.
If model_config is omitted and server.use_model_registry is true, the model name is looked up in
stt_models in server/model_registry.yaml instead. For registry behavior, refer to
Model registry.
The shipped sub-configuration contains three settings:
Keys Read by the STT Builder
The following table lists the keys that get_stt_service_from_config reads for type: nemo. The service
ignores other keys in the block.
Two constructor arguments are fixed by the builder and are not configurable from YAML: the decoding backend
(legacy) and decoder_type (rnnt, which selects the transducer branch on hybrid checkpoints). Audio
passthrough is on, so frames continue downstream to diarization and turn-taking after transcription.
EOU Detection and Turn Taking
parakeet_realtime_eou_120m-v1 emits EOU (end of utterance) and EOB (end of backchannel) tokens inline in
the hypothesis. NemoSTTService keeps a module-level allowlist, ASR_EOU_MODELS, and enables EOU-driven
turn taking only for models on it. The flag is derived from the model name and cannot be forced by configuration.
The behavior difference is visible in the frames that the service emits:
- EOU model. Every transcript is pushed as an
InterimTranscriptionFrame. The turn-taking service downstream watches for theEOU/EOBsuffix, strips it, and promotes the buffered text to a finalTranscriptionFrame. For downstream behavior, refer to Turn taking. - Non-EOU model. The service uses the model’s own
is_finalflag to choose betweenInterimTranscriptionFrameandTranscriptionFrame, and turn ends come from VADstop_secs.
If VAD reports the user stopped speaking while the ASR still considers the utterance incomplete, the service
logs [EOU missing] and resets the encoder cache. Occasional lines are normal. Frequent lines indicate that
the EOU head is not firing. Check the model name or set ignore_eou_eob: true to make VAD authoritative.
Setting ignore_eou_eob: true strips the special tokens from emitted text and disables EOU-driven turn taking,
even for an allowlisted model. The evaluation harness uses this setting to make both bots’ turn ends purely
VAD-driven, as shown in evaluation/server_configs/agent.yaml:
Hosted ASR
Set type: nvidia to call a hosted NVIDIA endpoint instead of loading a local checkpoint. This path uses
Pipecat’s NvidiaSTTService and reads model, function_id, server, language, and sample_rate. It also
reads an API key from the NVIDIA_API_KEY environment variable and falls back to api_key in the block.
model and function_id are a matched pair that addresses one deployment. Change both or neither. An example
configuration ships as server_configs/default_nvidia.yaml. For endpoint setup, refer to
NVIDIA NIM.
Verify Your Setup
Start the server and grep the log for the resolved configuration — _configure_stt prints the merged block,
and the service prints the model it loaded:
A Setting has_turn_taking to True line confirms that the EOU path is active. With
server.log_level: DEBUG, the log also includes one line per non-empty chunk with the inference time and
running transcript. EOU and EOB latency and probability appear when the tokens fire. Use these measurements
to confirm that ASR inference is faster than the 80 ms of audio consumed per step.
Related Topics
Use these pages to understand the stages that act on ASR output and to configure other speech services.
- Turn taking — how EOU tokens, VAD, and backchannel phrases combine into turn ends.
- Diarization — the optional speaker-tagging stage that sits after ASR.
- Server configuration — configuration layering and the full file layout.
- Audio logging — capturing the per-turn audio and transcripts referenced above.
- Troubleshooting — diagnose recognition and latency problems.