nemo_voice_agent.pipecat.services.nvidia.tts

View as Markdown

Retry wrapper around pipecat’s NvidiaTTSService.

Upstream treats any SynthesizeOnline exception as terminal for the stream (pipecat/services/nvidia/tts.py: “Once SynthesizeOnline raises, no further reliable audio is expected”). For a locally-hosted Riva server that is the right call, but against NVCF the first request to a cold or rescheduled worker routinely fails with::

StatusCode.DEADLINE_EXCEEDED: failed to establish link to worker

That is a routing/capacity condition, not a synthesis failure — the next attempt normally succeeds within a second. Upstream’s terminal handling turns it into a silently dropped bot turn: the pipeline gets an ErrorFrame and the user simply hears nothing.

The STT side needs no equivalent: pipecat’s NvidiaSTTService already reconnects on any grpc.RpcError via _handle_stream_drop -> _do_reconnect, and does so turn-aware. Only TTS lacks a retry path.

Module Contents

Classes

NameDescription
ResilientNvidiaTTSServiceNvidiaTTSService that retries a synthesis stream that never produced audio.

Functions

NameDescription
_is_transientTrue when error is a gRPC failure that is worth retrying.

Data

TRANSIENT_STATUS_CODES

API

class nemo_voice_agent.pipecat.services.nvidia.tts.ResilientNvidiaTTSService(
max_retries: int = 2,
retry_backoff_secs: float = 0.25,
kwargs = {}
)

Bases: NvidiaTTSService

NvidiaTTSService that retries a synthesis stream that never produced audio.

Parameters:

max_retries
int" default="2

Additional attempts after the first failure. 0 restores upstream behaviour exactly.

retry_backoff_secs
float" default="0.25

Base delay between attempts; doubled each retry.

**kwargs
Defaults to {}

Forwarded to NvidiaTTSService.

_max_retries
= max(0, int(max_retries))
_retry_backoff_secs
= max(0.0, float(retry_backoff_secs))
nemo_voice_agent.pipecat.services.nvidia.tts.ResilientNvidiaTTSService._synthesis_handler(
state
) -> None

Run the SynthesizeOnline stream, retrying establishment failures.

Overrides upstream’s single-shot handler. Same contract: forward each response onto state.response_queue, push the exception on failure, and always terminate with a None sentinel so _process_responses can finish.

Retry is deliberately restricted to attempts that produced no audio. Once any frame has reached the audio context, re-running the request would splice a duplicate prefix into the middle of an utterance, which is worse than the dropped turn we are trying to avoid. Since “failed to establish link to worker” fails before the first response, the narrow rule still covers the case that motivated this class.

nemo_voice_agent.pipecat.services.nvidia.tts._is_transient(
error: BaseException
) -> bool

True when error is a gRPC failure that is worth retrying.

nemo_voice_agent.pipecat.services.nvidia.tts.TRANSIENT_STATUS_CODES: Set[StatusCode] = {grpc.StatusCode.DEADLINE_EXCEEDED, grpc.StatusCode.UNAVAILABLE, grpc.StatusCode...