Hey, how to implement stt and tts fallback
# ask-ai
g
Hey, how to implement stt and tts fallback
✅ 1
t
Thanks for reaching out, ashutosh. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I can help with implementing STT and TTS fallback. Quick clarifying question first: are you using LiveKit Agents/Inference pipeline (Agents plugins like Deepgram/AssemblyAI for STT and ElevenLabs/Google for TTS), or a custom pipeline/integration? If you’re using LiveKit Agents/Inference, I can provide example configs and error-handling patterns. If you’re using a custom setup, tell me which STT and TTS providers you currently have and whether you want automatic model fallback, retries, or a static provider order. Sources: OpenRouter LLM plugin guide | LiveKit Documentation | Introducing LiveKit Inference: A unified model interface for voice AI | Liv... | Introducing LiveKit Inference: A unified model interface for voice AI | Liv... | Sequential Pipeline Architecture for Voice Agents | LiveKit | Speech-to-text (STT) models overview | LiveKit Documentation, with interactive elements
g
i am using the deepgram plugin for the stt
t
Thanks — since you’re using the Deepgram STT plugin, here’s a concise plan and example configs to implement STT fallback plus recommended TTS fallback options. Acknowledgement • You’re using Deepgram for STT and want a fallback strategy for STT and TTS. STT fallback (Deepgram primary) 1. Configure a primary Deepgram model and one or more fallback models/providers. Example pattern:
Copy code
stt: new inference.STT({
  model: "deepgram/nova-3",
  fallback: ["assemblyai/universal-streaming", "google/speech-to-text"],
})
1. Runtime behavior: • Try the primary model first. • If the primary returns an error, empty result, or low-confidence transcript, retry using the next provider in
fallback
. • Apply a short retry/backoff (e.g., 1–2 retries, exponential backoff) per provider. 1. Failure handling: • If all providers fail or confidence is too low, prompt the user for a repeat or use a brief confirmation step before passing text downstream. TTS fallback (recommended approach) • Use a primary TTS provider (e.g., ElevenLabs or Google) and list simpler or more available providers as fallbacks. Example pattern:
Copy code
tts: new inference.TTS({
  model: "elevenlabs/high-quality",
  fallback: ["google/text-to-speech", "azure/text-to-speech"],
})
• If TTS generation fails or latency is high, fall back to the next provider. • As a final fallback, play a short pre-recorded audio clip or an alert tone to avoid silence. Error handling & observability • Track per-stage results (STT confidence, TTS latency/errors). • Log provider, timestamp, error, and confidence to choose smarter routing later. • Use simple heuristics: treat empty transcripts or confidence < threshold (e.g., 0.6) as failures. Next step for me to help • Do you want a full sample integration (Node or Python) using the LiveKit inference API with Deepgram primary + AssemblyAI fallback for STT and ElevenLabs + Google for TTS? If so, tell me which language you prefer., with interactive elements
g
from livekit.plugins import openai, deepgram, cartesia, elevenlabs, google, groq, xai
t
Thanks — I’ll provide a concise Python example showing STT fallback (Deepgram primary, AssemblyAI fallback) and TTS fallback (ElevenLabs primary, Google fallback) using your plugin imports, plus notes on configuration and error handling. Python example (LiveKit inference-style pseudocode)
Copy code
from livekit.plugins import deepgram, assemblyai, elevenlabs, google
from livekit import inference

# Configure STT pipeline: Deepgram primary, AssemblyAI fallback
stt = inference.STT(
    model="deepgram/nova-3",
    fallback=["assemblyai/universal-streaming"],
    # optional confidence threshold to treat low-confidence as failure
    confidence_threshold=0.6,
    # optional per-provider retry settings
    retries=1,
    backoff_seconds=0.5,
)

# Configure TTS pipeline: ElevenLabs primary, Google fallback
tts = inference.TTS(
    model="elevenlabs/high-quality",
    fallback=["google/text-to-speech"],
    # optional timeout and retries
    timeout_seconds=8,
    retries=1,
    backoff_seconds=0.5,
)

# Simple pipeline runner
def process_audio(audio_bytes):
    # 1) STT with fallback logic handled by inference.STT
    stt_result = None
    try:
        stt_result = stt.transcribe(audio_bytes)
    except Exception as e:
        # inference.STT should automatically try fallbacks; catch if all fail
        print("STT failed:", e)

    # check result and confidence
    if not stt_result or stt_result.text.strip() == "" or stt_result.confidence < stt.confidence_threshold:
        # final policy: ask for repeat or return an error response
        return {"error": "Could not transcribe reliably; please repeat."}

    user_text = stt_result.text

    # 2) (Optional) pass user_text to LLM / app logic here, produce reply_text
    reply_text = f"Echo: {user_text}"

    # 3) TTS with fallback
    tts_audio = None
    try:
        tts_audio = tts.synthesize(reply_text)
    except Exception as e:
        print("TTS failed:", e)

    if not tts_audio:
        # final fallback: return pre-recorded clip or brief tone
        with open("fallback_tone.mp3", "rb") as f:
            return {"audio_bytes": f.read()}

    return {"audio_bytes": tts_audio}
Key configuration & error-handling notes • Use
fallback
lists on both
STT
and
TTS
to declare provider order; the system will try primary then fallbacks. • Treat empty transcripts or confidence below a threshold (e.g., 0.6) as failures and trigger fallback or user confirmation. • Apply small retries with exponential backoff per provider to handle transient errors. • For TTS, have a final non-network fallback (short prerecorded clip) to avoid silence. • Log provider chosen, errors, latencies, and confidence to tune routing later. If you’d like, I can: • Convert this to exact LiveKit client calls for your environment (Node or more concrete Python SDK usage). • Swap AssemblyAI/Google for other plugins you imported (cartesia, groq, xai, etc.). Which providers do you prefer for fallback?, with interactive elements
g
return sarvam.STT( model=config_values["model"], language=config_values["language"], _api_key_=get_config().sarvam_api_key, ) how to insert fallback in this ?
t
You can add fallback in two ways depending on whether
sarvam.STT
supports a
fallback
parameter. 1) If
sarvam.STT
accepts a
fallback
list like other plugins:
Copy code
return sarvam.STT(
    model=config_values["model"],
    language=config_values["language"],
    api_key=get_config().sarvam_api_key,
    fallback=["assemblyai/universal-streaming", "deepgram/nova-3"],
)
2) If
sarvam.STT
does NOT support
fallback
natively, implement fallback logic around the call:
Copy code
def transcribe_with_fallback(audio_bytes):
    providers = [
        lambda: sarvam.STT(model=config_values["model"], language=config_values["language"], api_key=get_config().sarvam_api_key).transcribe(audio_bytes),
        lambda: assemblyai.STT(model="assemblyai/universal-streaming", api_key=... ).transcribe(audio_bytes),
        lambda: deepgram.STT(model="deepgram/nova-3", api_key=... ).transcribe(audio_bytes),
    ]
    for call in providers:
        try:
            result = call()
            if result and getattr(result, "confidence", 1.0) >= 0.6 and result.text.strip():
                return result
        except Exception:
            pass
    # final fallback: ask user to repeat or return error
    return None
Which approach do you prefer? If
sarvam.STT
supports
fallback
, I can show exact parameter usage; otherwise I can adapt the wrapper example to your environment and return types. , with interactive elements
g
what is the difference bt using inference and using the , plugin.STT
t
Good question — here’s a concise comparison of using LiveKit’s
inference.STT
vs a provider plugin's
plugin.STT
(e.g.,
deepgram.STT
). Acknowledgement • You’re asking how
inference.STT
differs from directly calling
deepgram.STT
(or another plugin’s
STT
). Key differences • Scope and abstraction: ◦ `inference.STT`: High-level, provider-agnostic interface that can route requests to multiple providers and supports built-in fallback lists, retries, timeouts, and unified return shapes. ◦
plugin.STT
(e.g.,
deepgram.STT
): Provider-specific client that talks directly to that provider’s API and exposes provider-specific options and features. • Fallback and routing: ◦ `inference.STT`: Supports
fallback
parameter to declare an ordered list of models/providers and will automatically try fallbacks and handle retry/backoff logic. ◦ `plugin.STT`: No automatic multi-provider fallback unless you implement wrapper logic yourself. • Observability and billing: ◦ `inference.STT`: Centralized routing, consolidated usage/billing, and built-in metrics/observability across providers. ◦ `plugin.STT`: Logs/metrics and billing are per-provider; you must correlate across providers yourself. • Simplicity vs control: ◦ `inference.STT`: Easier to implement robust pipelines quickly (fallback, thresholds, unified results). ◦ `plugin.STT`: More granular control of provider-specific features, fine-tuned parameters, or newer provider capabilities not yet surfaced by inference. When to use which • Use
inference.STT
when you want automatic fallback, unified behavior across providers, easier retries/observability, and less custom code. • Use
plugin.STT
when you need provider-specific features, the absolute latest provider options, or you’re optimizing a single provider tightly. Practical advice • If you need fallback and multi-provider resilience, prefer
inference.STT
and set
fallback=[...]
. • If
sarvam.STT
or another plugin already supports
fallback
, you can use that directly; otherwise wrap plugin calls in a small fallback wrapper as shown earlier. If you want, I can: • Show a concrete Python example using
inference.STT
with your Deepgram primary and AssemblyAI fallback, or • Show a wrapper that calls
deepgram.STT
then falls back to
assemblyai.STT
. Which example would you like? , with interactive elements
g
so does inference is a feature of livekit cloud?
t
Yes — Inference is a feature of LiveKit Cloud. It provides a high-level, provider-agnostic layer that routes requests to STT/LLM/TTS providers, supports fallback lists, retries, timeouts, consolidated observability, and centralized billing. Use it when you want automatic multi-provider routing and unified results; use provider plugins directly when you need provider-specific features or tighter control. , with interactive elements