Skip to main content
Source Code: src/gaia/audio/
Import: from gaia.audio.audio_client import AudioClient

Detailed Spec: spec/audio-client Purpose: Voice interaction with ASR (Whisper) and TTS (Kokoro).

Audio Client

AudioClient glues Whisper ASR and Kokoro TTS together into a full voice-chat loop. It is used by the Talk SDK and the gaia talk CLI. Because the voice loop runs microphone I/O alongside LLM calls, start_voice_chat is async:
To list available input devices, use WhisperAsr.list_audio_devices() directly (see ASR section below). AudioClient itself does not expose a device-enumeration method.

Whisper ASR (Speech-to-Text)

Import: from gaia.audio.whisper_asr import WhisperAsr
WhisperAsr is the live microphone path only — it has no file-transcription method. To transcribe a recording you already have, use the agent’s transcribe_media tool (Transcription & Meeting Notes), which runs on Lemonade and writes a plain-text transcript to disk. It returns the transcript’s path, duration, language, and the words Whisper itself was least confident about — not timestamps or speaker labels in the result itself. transcribe_media also runs acoustic speaker diarization on the same audio (see Speaker Diarization below); a separate refine_transcript call then attaches real names to those voices, inferred from what’s said, and writes the speaker-labelled transcript.

Speaker Diarization (Who Spoke When)

Import: from gaia.audio.diarize import diarize, is_available, ensure_ready
diarize() runs pyannote’s segmentation network and a WeSpeaker embedding model — both ONNX, executed via sherpa-onnx. No PyTorch, no HuggingFace account or gated licence: the models are plain GitHub release downloads (~33 MB total), redistributed under their original MIT terms. Everything installs on first call, never at import time — the sherpa-onnx wheel (~40 MB) plus the two models. A failed install is not silently swallowed: ensure_ready and diarize raise DiarizationError with the command that fixes it. transcribe_media catches that error and falls back to text-only speaker inference rather than failing the transcription.
Measured on a real 46-minute, 4-speaker meeting: 4 speakers found against a ground truth of 4. num_speakers is more accurate than auto-detection whenever the count is known; auto-detection instead uses a clustering threshold (cluster_threshold, default 0.65) that is sensitive to tune — 0.50 over-split the same recording into 10 clusters, 0.75 collapsed it to 2. Very short clips can miss a voice entirely: a 90-second clip where a second speaker only interjected a few words came back as one speaker. diarize() returns acoustic labels only — Speaker 1, Speaker 2, and so on. Turning those into real names is a separate, text-based inference step built on top; see Transcription & Meeting Notes.

Kokoro TTS (Text-to-Speech)

Import: from gaia.audio.kokoro_tts import KokoroTTS