Files
flynn/docs/runbooks/VOICE_TRANSCRIPTION_DEBUG.md

4.4 KiB

Voice Transcription Debug Runbook

This runbook covers Telegram voice-message troubleshooting for audio.transcribe.

Fast Checks

  1. Confirm tool is enabled in config:
audio:
  enabled: true
  provider:
    endpoint: http://localhost:18801/v1/audio/transcriptions
  1. Confirm recent tool events:
tail -n 400 ~/.local/share/flynn/audit.log | jq -c 'select(.event_type=="tool.start" or .event_type=="tool.success" or .event_type=="tool.error" or .event_type=="tool.args_rewritten")'
  1. If needed, confirm local endpoint behavior directly:
curl -sS -i -X POST http://localhost:18801/v1/audio/transcriptions \
  -F file=@/tmp/sample.ogg \
  -F model=whisper-1 \
  -F response_format=json

Interpreting Common Errors

  • Either data or url must be provided

    • Model/tool call had empty args and no hydrated attachment data.
  • Only http/https URLs are allowed, got file:

    • Model emitted file://... URL; Flynn should rewrite from latest session audio.
  • Transcription endpoint error: FFmpeg conversion failed.

    • Endpoint could not decode payload as audio. Often caused by model-provided fake or mismatched data/mime_type.
  • fetch failed

    • Flynn could not connect to the transcription endpoint for that attempt (transport/connectivity timeout/reset).
    • Confirm endpoint is reachable from Flynn host and check whisper-server logs around the same timestamp.
    • If this is intermittent, Flynn now retries transient failures before returning an error.
    • If you use localhost in config and this persists, set endpoint host to 127.0.0.1 to avoid local name-resolution edge cases:
      • http://127.0.0.1:18801/v1/audio/transcriptions
    • If docker logs whisper-server shows whisper server listening at http://127.0.0.1:8080, host-published port forwarding may reset connections. Verify container launch args:
      • docker inspect whisper-server --format '{{.Path}} {{json .Args}}'
      • Expected: path whisper-server with explicit --host 0.0.0.0 args.
  • [No speech detected]

    • Request succeeded and endpoint returned empty transcript text.

Correlate Events By Timestamp

To inspect one Telegram session with wall-clock timestamps:

tail -n 2000 ~/.local/share/flynn/audit.log | jq -c '
  select(
    .event.session_id=="telegram:8367012007" and
    (.event_type=="user.action" or .event_type=="backend.route" or .event_type=="tool.start" or .event_type=="tool.success" or .event_type=="tool.error")
  )
  | . + {ts_iso: ((.timestamp/1000)|strftime("%Y-%m-%d %H:%M:%S %Z"))}
'

Rewrite Metric

Flynn emits tool.args_rewritten whenever it replaces model-provided audio.transcribe args with trusted session audio bytes.

Fields:

  • source: latest_turn, persisted, or history
  • reason: latest_audio_preferred, voice_turn_fallback, invalid_model_args, missing_model_args
  • original_* and final_mime_type for quick diagnosis

Example:

{
  "event_type": "tool.args_rewritten",
  "event": {
    "tool_name": "audio.transcribe",
    "source": "persisted",
    "reason": "voice_turn_fallback",
    "original_mime_type": "audio/ogg",
    "final_mime_type": "audio/ogg"
  }
}

Where Audio Is Stored Locally

Audio bytes are not written as standalone files by default. They are persisted in SQLite:

  • DB path: ~/.local/share/flynn/sessions.db
  • Table: session_config
  • Key: lastAudioAttachment
  • Value: JSON with data (base64) or url, plus mimeType

Inspect current value:

sqlite3 ~/.local/share/flynn/sessions.db \
  "SELECT session_id,key,length(value) FROM session_config WHERE key='lastAudioAttachment';"

Clear Cached Audio for One Session

Delete only one chat/session cache entry (example session id: telegram:8367012007):

sqlite3 ~/.local/share/flynn/sessions.db \
  "DELETE FROM session_config WHERE session_id='telegram:8367012007' AND key='lastAudioAttachment';"

Verify:

sqlite3 ~/.local/share/flynn/sessions.db \
  "SELECT session_id,key,length(value) FROM session_config WHERE key='lastAudioAttachment';"

If /reset is run in that chat, it also clears the session's lastAudioAttachment row.

Data Lifecycle

  • session.clear() (e.g. /reset) removes messages, tool executions, and session config for that session.
  • Session TTL pruning removes stale sessions and associated config from SQLite.

For additional operational queries (sessions, tools, pairing, backups), see:

  • docs/runbooks/SQLITE_QUICK_REFERENCE.md