Skip to content
kazma.
ع Star 7 Get Started

Voice & Media

Kazma can hear (speech-to-text), speak (text-to-speech), and see (images/PDFs/docs) across every chat platform — Telegram, Discord, Slack, and the Web UI. This page covers how to enable and use voice and media.


Voice is a single config block that controls all platforms. When enabled, inbound audio is transcribed to text before reaching the agent. Optional auto voice-note replies (tts_reply) synthesize the agent’s reply back to audio only when that inbound turn was voice (not for plain text chats).

In kazma.yaml under gateway, or at runtime via the Web UI → Settings → Voice tab (writes to ConfigStore, takes effect immediately):

gateway:
voice:
enabled: true
tts_reply: true # platform auto voice-note replies (toggle in UI)
stt_provider: openai # speech-to-text provider
stt_language: auto # auto-detect; or "ar", "en", ...
tts_provider: edgetts # text-to-speech provider
tts_voice: default
tts_output_format: mp3
SettingEffect
Voice subsystem (enabled)Master on/off for STT + TTS everywhere
Auto voice-note replies (tts_reply)Telegram/Discord/Slack: speak the reply after a voice inbound. Off = text-only replies; STT still works

The same keys are read live by all adapters (voice_helpers.py), so changing a setting in the UI affects Telegram, Discord, Slack, and Web at once.

ProviderKeyNeedsNotes
OpenAI WhisperopenaiOPENAI_API_KEYDefault; robust across languages.
Groq WhispergroqGROQ_API_KEYFastest; great for real-time.
CoherecohereCOHERE_API_KEY
NVIDIA NIM / RivanvidiaNVIDIA_API_KEY
faster-whisper (local)faster-whisperpip install faster-whisperRuns on-device; no API key.
ProviderKeyNeedsNotes
Edge TTSedgettsnothingFree, no key — the default.
OpenAIopenaiOPENAI_API_KEYHigh-quality neural voices.
NVIDIA NIMnvidiaNVIDIA_API_KEY
Kokoro (local)kokorolocal installOn-device.
Coqui (local)coquilocal installOn-device.
PlatformInbound (you → agent)Outbound (agent → you)
TelegramVoice/audio note transcribed → textTTS voice reply only if tts_reply and this turn was voice
DiscordAudio attachment transcribed → textSame gate; audio file upload
SlackAudio file transcribed → textSame gate; file upload
Web UIPOST /api/voice/sttExplicit POST /api/voice/tts / live /ws/voice (not gated by platform tts_reply)

If STT is not configured (no key / disabled), an inbound voice note returns a friendly fallback message instead of failing silently.


Kazma’s message contract carries an attachments list (Attachment dataclass in gateway.py) alongside text. Each attachment has a kind (image / file / audio / video), mime, filename, and either in-memory data bytes or a fetchable url.

When you send an image or document, the attachment builder (agent_handler/attachments.py) decides how to present it to the LLM:

Attachment typeBehavior
Image (PNG/JPEG/WEBP/GIF, ≤ 8 MB)Inlined as a base64 image_url vision block — the LLM sees it directly.
Document (PDF/DOCX/large image/audio/…)Saved to kazma-data/attachments/; the prompt gets a [Attached: foo.pdf — use file_read to open: <path>] stub so the agent can open it via the file tools. This keeps prompt size bounded.

The multimodal content follows the OpenAI vision format (content: [{type:image_url,...}, {type:text,...}]) and passes through llm_provider.py verbatim — any vision-capable model works.

PlatformInbound mediaOutbound media
TelegramPhoto / document / video / animation captured (was silently dropped)sendPhoto / sendDocument / sendVideo / sendAudio
DiscordAttachments + image embedsMultipart file upload
Slackfiles (Socket Mode primary path)getUploadURLExternal → upload → completeUploadExternal
Web UIPOST /api/chat/upload (multipart, 20 MB cap)Download links
  1. Click the attachment (📎) button in the chat box and pick a file.
  2. Small text files (≤ 1 MB, .txt/.md/.py/…) are inlined into the message client-side — no upload round-trip.
  3. Images, PDFs, and binary files are uploaded via POST /api/chat/upload and attached to your next message.

The agent can also produce media to send back — e.g. generate_image (multi-backend) writes to kazma-data/images/ and the path flows out as an attachment on supported platforms.


Voice and media are opt-in. Voice defaults to enabled: false. Media capture is always on where the adapter supports it (it’s just data on the message contract); if you want to suppress outbound media, that’s controlled per-tool (the agent only sends attachments it explicitly creates).