Voice Notes (Speech-to-Text)

Automatically transcribe inbound voice messages on Telegram, Slack, WhatsApp, Discord, and Signal

Voice notes sent to your gateway bot are transcribed and delivered to the agent as text — no code changes required, on by default across Telegram, Slack, WhatsApp, Discord, and Signal.

Diagram

Voice Note Flow

🎙️ Voice note

📥 Channel adapter

📝 Transcribe

🤖 Agent

💬 Reply

Quick Start

  1. Works out of the box

    Voice notes are transcribed automatically — no config needed.

    yaml
    # gateway.yaml
    channels:
      telegram:
        token: ${TELEGRAM_BOT_TOKEN}
    agent:
      name: "assistant"
      instructions: "Reply helpfully to any question, including voice notes."
    python
    from praisonaiagents import Agent
    
    agent = Agent(
        name="assistant",
        instructions="Reply helpfully to any question, including voice notes.",
    )
    # Start the gateway — voice notes are transcribed automatically.
  2. Echo the transcript back

    Mirror the recognised text back so users can verify what the bot heard.

    yaml
    channels:
      telegram:
        token: ${TELEGRAM_BOT_TOKEN}
        stt:
          enabled: true          # default; set false to opt out
          echo_transcripts: true # echo the recognised text back to the user
  3. Force a language

    Skip auto-detection for faster, more accurate short clips.

    yaml
    channels:
      telegram:
        stt:
          language: "en"
  4. Custom STT model

    Swap the default model for any LiteLLM-supported STT model.

    yaml
    channels:
      telegram:
        stt:
          model: "openai/whisper-1"   # default; any LiteLLM-supported STT model
  5. Opt out entirely

    Disable transcription for a channel.

    yaml
    channels:
      telegram:
        stt:
          enabled: false

How It Works

A voice note is downloaded, transcribed, and handed to the agent as text.

Diagram
AudioAgent.transcribetranscribe helperGateway adapterTelegram / Slack / WhatsApp / Discord / SignalUserAudioAgent.transcribetranscribe helperGateway adapterTelegram / Slack / WhatsApp / Discord / SignalUser🎙️ Voice noteInbound mediaDownload to SSRF-safe media cachetranscribe(path, language, model)stt_tool(…) → whisper-1transcript text“Hey, what’s the weather?”(optional) echo transcript backAgent reply

A user records a voice note in Telegram (or Slack, WhatsApp, Discord, or Signal) and taps send. Within a second, the bot’s typing indicator appears — the audio has been downloaded and handed to whisper-1. When the transcript comes back, the agent processes it exactly as if the user had typed the text. If echo_transcripts: true, the user first sees the recognised text confirmed back to them, then the agent’s reply — helpful during onboarding so users know their voice was heard correctly.

Graceful degradation

A voice note is never silently dropped — the agent always sees at least a placeholder.

  • STT disabled → the turn still reaches the agent with [Voice message received].
  • Transcription fails → same placeholder.
  • STT tool import fails (missing whisper/litellm deps) → same placeholder plus a WARNING in logs.

Configuration Options

The stt: block lives under any channel in gateway.yaml / bot.yaml.

OptionTypeDefaultDescription
enabledboolTrueTranscribe inbound audio. On by default.
echo_transcriptsboolFalseEcho the recognised text back to the user.
languageOptional[str]NoneISO language code (e.g. "en", "es"). None = auto-detect.
modelOptional[str]NoneSTT model override. None uses openai/whisper-1.
yaml
channels:
  <platform>:
    stt:
      enabled: true
      echo_transcripts: false
      language: null
      model: null

Bool shorthand

yaml
channels:
  telegram:
    stt: true    # equivalent to {enabled: true}

Resolution order

The effective policy is resolved from, in order:

  1. config.metadata["stt"] (operator override; dict or bool),
  2. a direct config.stt attribute (schema-backed configs), then
  3. the on-by-default default.

Platform Support

PlatformNative voice-note supportBehaviour
Telegram✅Downloads voice file, transcribes, feeds transcript to agent.
Slack✅Downloads voice file via bot token through the SSRF-safe media cache.
WhatsApp✅Transcribes inbound audio, forwards transcript plus cached audio to the agent.
Discord✅Transcribes the first audio/* attachment of an audio-only message; access gates run first, so rejected senders trigger no STT work.
Signal✅Fetches the first audio/* attachment from the operator-configured signal-cli-rest-api bridge (GET /v1/attachments/{id}) and transcribes it.
Email / AgentMail / Linear❌No voice-note surface.

Discord and Signal share the same stt: block, size cap, and [Voice message received] placeholder as Telegram, Slack, and WhatsApp.


Placeholder Behaviour

When transcription is unavailable, the agent receives [Voice message received] instead of nothing.

ScenarioWhat the agent sees
STT enabled, transcription succeedsThe transcript (e.g. "Hey, what's the weather?")
STT enabled, echo_transcripts: true[Voice message]: Hey, what's the weather?
STT disabled (enabled: false)[Voice message received]
Transcription fails or deps missing[Voice message received]

The invariant: a voice note always reaches the agent with at least the placeholder.


Common Patterns

Voice notes fit several bot styles.

Voice-first assistant

No config needed. The user taps the mic, records a question, and the agent replies in text — the transcription happens automatically.

yaml
channels:
  telegram:
    token: ${TELEGRAM_BOT_TOKEN}

Multilingual support

Force a language for a single-language community bot. Auto-detection is skipped for faster, more accurate recognition.

yaml
channels:
  whatsapp:
    stt:
      language: "es"

Debug transcription quality

Echo the recognised text back so users can spot recognition errors and rephrase.

yaml
channels:
  slack:
    stt:
      echo_transcripts: true

Best Practices

Set a language when your users speak one language

language: "en" (or "es", "fr", …) skips auto-detection — faster and more accurate for short clips.

Turn on echo_transcripts during onboarding

echo_transcripts: true shows users what the bot heard so they can rephrase if recognition was off.

Keep enabled: true unless you have a reason to disable

Even with STT off, the placeholder fallback still lets voice-note messages reach the agent. Only disable for privacy, cost, or latency reasons.

Ship your STT provider's API key

openai/whisper-1 is the default, so set OPENAI_API_KEY. Any LiteLLM-supported STT model works via the model: field.


Related