AssemblyAI Streaming & Live Transcription Skill
Overview
Use this skill to build and maintain code that talks to AssemblyAI’s:
- Streaming Speech-to-Text (STT) via WebSockets (
wss://streaming.assemblyai.com/v3/ws)
- Async / pre-recorded STT via REST (
https://api.assemblyai.com/v2/transcript)
- LLM Gateway for applying Claude/GPT/Gemini-style models to transcripts (
https://llm-gateway.assemblyai.com)
The emphasis is on streaming/live transcription, meeting notetakers, and voice agents, while still covering async workflows and post-processing.
This skill assumes a Claude Code environment with access to Python (preferred) and Bash.
When to Use
Use this skill when:
- Implementing real-time transcription from a microphone, telephony stream, or audio file.
- Building a live meeting notetaker (Zoom/Teams/Meet), especially with summaries, action items, and highlights.
- Implementing a voice agent where latency and natural turn-taking matter.
- Migrating from other STT providers (OpenAI/Deepgram/Google/AWS/etc.) to AssemblyAI.
- Applying LLMs to audio via LLM Gateway for summaries, Q&A, topic tagging, or custom prompts.
Do not use this skill when:
- The task is generic HTTP client usage with no AssemblyAI-specific logic.
- The request clearly targets a different STT vendor.
- The environment cannot safely store or use an API key.
AssemblyAI Mental Model
1. Products to care about
Pre-recorded Speech-to-Text (Async)
- REST API:
POST /v2/transcript → GET /v2/transcript/{id}
- Designed for files from URLs, uploads, S3, etc.
- Supports extra models: summarization, topic detection, sentiment, PII redaction, chapters, etc.
Streaming Speech-to-Text
- WebSocket:
wss://streaming.assemblyai.com/v3/ws
- Low-latency, immutable transcripts (~300ms).
- Turn detection built in; fits voice agents and live captioning.
LLM Gateway
- REST API:
POST /v1/chat/completions at https://llm-gateway.assemblyai.com
- Unified access to multiple LLMs (Claude, GPT, Gemini, etc.).
- Designed for “LLM over transcripts” workflows.
2. Key model knobs (Async)
speech_models: ["slam-1", "universal"] etc.
- Slam-1: best English accuracy + keyterms_prompt, good for medical/technical conversations.
- Universal: multilingual coverage; good default if language is unknown.
language_code vs language_detection:
- Use
language_code when the language is known.
- Use
language_detection: true when unknown; optionally set language_confidence_threshold.
keyterms_prompt:
- Domain words/phrases to boost (med terms, product names, etc.).
- Extra intelligence:
summarization, iab_categories, content_safety, entity_detection, auto_chapters, sentiment_analysis, speaker_labels, auto_highlights, redact_pii, etc.
3. Key model knobs (Streaming)
Connection URL:
- US:
wss://streaming.assemblyai.com/v3/ws
- EU:
wss://streaming.eu.assemblyai.com/v3/ws
Important query parameters:
sample_rate (required): e.g. 16000
format_turns (bool): return formatted final transcripts; avoid for low-latency voice agents.
speech_model: universal-streaming-english (default) or universal-streaming-multi.
- `keyterms_p
rompt: JSON-encoded list of terms, e.g. ["AssemblyAI", "Slam-1", "Keanu Reeves"]`.
- Turn detection:
end_of_turn_confidence_threshold (0.0–1.0, default ~0.4)
min_end_of_turn_silence_when_confident (ms, default ~400)
max_turn_silence (ms, default ~1280)
Headers:
- Use either
Authorization: <API_KEY> or a short-lived token query parameter issued by your backend.
Messages:
- Client sends:
- Binary audio chunks (50–1000ms each).
- Optional JSON messages:
{"type": "UpdateConfig", ...}, {"type": "Terminate"}, {"type": "ForceEndpoint"}.
- Server sends:
Begin event with id, expires_at.
Turn events with:
transcript (immutable partials/finals),
utterance (complete semantic chunk),
end_of_turn (bool),
turn_is_formatted (bool),
words array with timestamps/confidences.
Termination event with summary stats.
4. Regions and data residency
- Async:
- US:
https://api.assemblyai.com
- EU:
https://api.eu.assemblyai.com
- Streaming:
- US:
wss://streaming.assemblyai.com/v3/ws
- EU:
wss://streaming.eu.assemblyai.com/v3/ws
Always keep base URLs consistent per project; don’t mix US/EU endpoints for the same data.
Security & API Keys
- Always require an AssemblyAI API key and keep it out of source in Claude Code output:
- Use environment variables:
ASSEMBLYAI_API_KEY.
- Or placeholders (
"<YOUR_API_KEY>") in snippets.
- For browser/client code:
- Do not embed the API key.
- Instruct the user to generate temporary streaming tokens on their backend and pass only the token into the WebSocket connection.
- Never print real keys in logs or comments.
High-Level Workflow Patterns
Decision tree
Is the audio live?
- Yes → Use Streaming STT.
- No → Use Async STT.
Is latency critical (<1s) for responses?
- Yes → Streaming with
format_turns=false and careful turn detection.
- No → Async, then Summarization/Chapters/etc.
Do transcripts leave the backend?
- Yes → Consider
redact_pii (and optionally redact_pii_audio) before sharing.
- No → Use raw transcripts as needed.
Need LLM-based processing (Q&A, structured summaries)?
- Yes → Pipe transcripts into LLM Gateway via
chat/completions.
How Claude Should Work with This Skill
General principles
- Prefer official AssemblyAI SDKs (Python/JS) when available; fall back to
requests/websocket-client only if SDK cannot be installed.
- Always:
- Validate HTTP responses and WebSocket status.
- Surface useful error messages (
status, error fields in transcript JSON).
- Respect documented min/max chunk sizes (50–1000ms of audio per binary message).
- For voice-agent code, optimize for:
- Immutable partials (
transcript) and utterance field.
- Minimal latency, avoid extra formatting passes.
Recipe 1 – Minimal Streaming from Microphone (Python SDK)
Goal: Stream mic audio to AssemblyAI and print transcripts in real time.
Use this when the environment has Python and assemblyai + pyaudio installed, and the user wants a quick streaming demo.
import assemblyai as aai
from assemblyai.streaming import v3 as aai_stream
import pyaudio
API_KEY = "<YOUR_API_KEY>"
aai.settings.api_key = API_KEY
SAMPLE_RATE = 16000
CHUNK_MS = 50
FRAMES_PER_BUFFER = int(SAMPLE_RATE * (CHUNK_MS / 1000.0))
def main():
client = aai_stream.StreamingClient(
aai_stream.StreamingClientOptions(
api_key=API_KEY,
api_host="streaming.assemblyai.com", # or "streaming.eu.assemblyai.com"
)
)
def on_begin(_client, event: aai_stream.BeginEvent):
print(f"Session started: {event.id}, expires at {event.expires_at}")
def on_turn(_client, event: aai_stream.TurnEvent):
# Use immutable transcript text
text = (event.transcript or "").strip()
if not text:
return
# Use formatted finals only for display; keep unformatted for LLMs
if event.turn_is_formatted:
print(f"[FINAL] {text}")
else:
print(f"[PARTIAL] {text}", end="\r")
def on_terminated(_client, event: aai_stream.TerminationEvent):
print(f"\nTerminated. Audio duration={event.audio_duration_seconds}s")
def on_error(_client, error: aai_stream.StreamingError):
print(f"\nStreaming error: {error}")
client.on(aai_stream.StreamingEvents.Begin, on_begin)
client.on(aai_stream.StreamingEvents.Turn, on_turn)
client.on(aai_stream.StreamingEvents.Termination, on_terminated)
client.on(aai_stream.StreamingEvents.Error, on_error)
client.connect(
aai_stream.StreamingParameters(
sample_rate=SAMPLE_RATE,
format_turns=False, # better latency for voice agents
)
)
pa = pyaudio.PyAudio()
stream = pa.open(
format=pyaudio.paInt16,
channels=1,
rate=SAMPLE_RATE,
input=True,
frames_per_buffer=FRAMES_PER_BUFFER,
)
try:
print("Speak into your microphone (Ctrl+C to stop)...")
def audio_gen():
while True:
yield stream.read(FRAMES_PER_BUFFER, exception_on_overflow=False)
client.stream(audio_gen())
except KeyboardInterrupt:
pass
finally:
client.disconnect(terminate=True)
stream.stop_stream()
stream.close()
pa.terminate()
if __name__ == "__main__":
main()
1---2name: assemblyai-streaming3description: This skill should be used when working with AssemblyAI’s Speech-to-Text and LLM Gateway APIs, especially for streaming/live transcription, meeting notetakers, and voice agents that need low-latency transcripts and audio analysis.4license: MIT5---67# AssemblyAI Streaming & Live Transcription Skill89## Overview1011Use this skill to build and maintain code that talks to AssemblyAI’s:1213- **Streaming Speech-to-Text (STT)** via WebSockets (`wss://streaming.assemblyai.com/v3/ws`)14- **Async / pre-recorded STT** via REST (`https://api.assemblyai.com/v2/transcript`)15- **LLM Gateway** for applying Claude/GPT/Gemini-style models to transcripts (`https://llm-gateway.assemblyai.com`)1617The emphasis is on **streaming/live transcription**, **meeting notetakers**, and **voice agents**, while still covering async workflows and post-processing.1819This skill assumes a Claude Code environment with access to Python (preferred) and Bash.2021---2223## When to Use2425Use this skill when:2627- Implementing **real-time transcription** from a microphone, telephony stream, or audio file.28- Building a **live meeting notetaker** (Zoom/Teams/Meet), especially with summaries, action items, and highlights.29- Implementing a **voice agent** where latency and natural turn-taking matter.30- Migrating from other STT providers (OpenAI/Deepgram/Google/AWS/etc.) to AssemblyAI.31- Applying **LLMs to audio** via LLM Gateway for summaries, Q&A, topic tagging, or custom prompts.3233Do **not** use this skill when:3435- The task is generic HTTP client usage with no AssemblyAI-specific logic.36- The request clearly targets a different STT vendor.37- The environment cannot safely store or use an API key.3839---4041## AssemblyAI Mental Model4243### 1. Products to care about44451. **Pre-recorded Speech-to-Text (Async)**46 - REST API: `POST /v2/transcript` → `GET /v2/transcript/{id}`47 - Designed for files from URLs, uploads, S3, etc.48 - Supports extra models: summarization, topic detection, sentiment, PII redaction, chapters, etc.49502. **Streaming Speech-to-Text**51 - WebSocket: `wss://streaming.assemblyai.com/v3/ws`52 - Low-latency, immutable transcripts (~300ms).53 - Turn detection built in; fits voice agents and live captioning.54553. **LLM Gateway**56 - REST API: `POST /v1/chat/completions` at `https://llm-gateway.assemblyai.com`57 - Unified access to multiple LLMs (Claude, GPT, Gemini, etc.).58 - Designed for “LLM over transcripts” workflows.5960### 2. Key model knobs (Async)6162- `speech_models`: `["slam-1", "universal"]` etc.63 - **Slam-1**: best English accuracy + keyterms_prompt, good for medical/technical conversations.64 - **Universal**: multilingual coverage; good default if language is unknown.65- `language_code` vs `language_detection`:66 - Use `language_code` when the language is known.67 - Use `language_detection: true` when unknown; optionally set `language_confidence_threshold`.68- `keyterms_prompt`:69 - Domain words/phrases to boost (med terms, product names, etc.).70- Extra intelligence: `summarization`, `iab_categories`, `content_safety`, `entity_detection`, `auto_chapters`, `sentiment_analysis`, `speaker_labels`, `auto_highlights`, `redact_pii`, etc.7172### 3. Key model knobs (Streaming)7374Connection URL:7576- US: `wss://streaming.assemblyai.com/v3/ws`77- EU: `wss://streaming.eu.assemblyai.com/v3/ws`7879Important query parameters:8081- `sample_rate` (required): e.g. `16000`82- `format_turns` (bool): return formatted final transcripts; **avoid** for low-latency voice agents.83- `speech_model`: `universal-streaming-english` (default) or `universal-streaming-multi`.84- `keyterms_p8586rompt`: JSON-encoded list of terms, e.g. `["AssemblyAI", "Slam-1", "Keanu Reeves"]`.87- Turn detection:88 - `end_of_turn_confidence_threshold` (0.0–1.0, default ~0.4)89 - `min_end_of_turn_silence_when_confident` (ms, default ~400)90 - `max_turn_silence` (ms, default ~1280)9192Headers:9394- Use either `Authorization: <API_KEY>` or a short-lived `token` query parameter issued by your backend.9596Messages:9798- Client sends:99 - Binary audio chunks (50–1000ms each).100 - Optional JSON messages: `{"type": "UpdateConfig", ...}`, `{"type": "Terminate"}`, `{"type": "ForceEndpoint"}`.101- Server sends:102 - `Begin` event with `id`, `expires_at`.103 - `Turn` events with:104 - `transcript` (immutable partials/finals),105 - `utterance` (complete semantic chunk),106 - `end_of_turn` (bool),107 - `turn_is_formatted` (bool),108 - `words` array with timestamps/confidences.109 - `Termination` event with summary stats.110111### 4. Regions and data residency112113- Async:114 - US: `https://api.assemblyai.com`115 - EU: `https://api.eu.assemblyai.com`116- Streaming:117 - US: `wss://streaming.assemblyai.com/v3/ws`118 - EU: `wss://streaming.eu.assemblyai.com/v3/ws`119120Always keep base URLs consistent per project; don’t mix US/EU endpoints for the same data.121122---123124## Security & API Keys125126- Always require an AssemblyAI API key and keep it **out of source** in Claude Code output:127 - Use environment variables: `ASSEMBLYAI_API_KEY`.128 - Or placeholders (`"<YOUR_API_KEY>"`) in snippets.129- For browser/client code:130 - Do **not** embed the API key.131 - Instruct the user to generate **temporary streaming tokens** on their backend and pass only the token into the WebSocket connection.132- Never print real keys in logs or comments.133134---135136## High-Level Workflow Patterns137138### Decision tree1391401. **Is the audio live?**141 - Yes → Use **Streaming STT**.142 - No → Use **Async STT**.1431442. **Is latency critical (<1s) for responses?**145 - Yes → Streaming with `format_turns=false` and careful turn detection.146 - No → Async, then Summarization/Chapters/etc.1471483. **Do transcripts leave the backend?**149 - Yes → Consider `redact_pii` (and optionally `redact_pii_audio`) before sharing.150 - No → Use raw transcripts as needed.1511524. **Need LLM-based processing (Q&A, structured summaries)?**153 - Yes → Pipe transcripts into **LLM Gateway** via `chat/completions`.154155---156157## How Claude Should Work with This Skill158159### General principles160161- Prefer **official AssemblyAI SDKs** (Python/JS) when available; fall back to `requests`/`websocket-client` only if SDK cannot be installed.162- Always:163 - Validate HTTP responses and WebSocket status.164 - Surface useful error messages (`status`, `error` fields in transcript JSON).165 - Respect documented min/max chunk sizes (50–1000ms of audio per binary message).166- For voice-agent code, optimize for:167 - Immutable partials (`transcript`) and `utterance` field.168 - Minimal latency, avoid extra formatting passes.169170---171172## Recipe 1 – Minimal Streaming from Microphone (Python SDK)173174> Goal: Stream mic audio to AssemblyAI and print transcripts in real time.175176Use this when the environment has Python and `assemblyai` + `pyaudio` installed, and the user wants a quick streaming demo.177178```python179import assemblyai as aai180from assemblyai.streaming import v3 as aai_stream181import pyaudio182183API_KEY = "<YOUR_API_KEY>"184185aai.settings.api_key = API_KEY186187SAMPLE_RATE = 16000188CHUNK_MS = 50189FRAMES_PER_BUFFER = int(SAMPLE_RATE * (CHUNK_MS / 1000.0))190191def main():192 client = aai_stream.StreamingClient(193 aai_stream.StreamingClientOptions(194 api_key=API_KEY,195 api_host="streaming.assemblyai.com", # or "streaming.eu.assemblyai.com"196 )197 )198199 def on_begin(_client, event: aai_stream.BeginEvent):200 print(f"Session started: {event.id}, expires at {event.expires_at}")201202 def on_turn(_client, event: aai_stream.TurnEvent):203 # Use immutable transcript text204 text = (event.transcript or "").strip()205 if not text:206 return207 # Use formatted finals only for display; keep unformatted for LLMs208 if event.turn_is_formatted:209 print(f"[FINAL] {text}")210 else:211 print(f"[PARTIAL] {text}", end="\r")212213 def on_terminated(_client, event: aai_stream.TerminationEvent):214 print(f"\nTerminated. Audio duration={event.audio_duration_seconds}s")215216 def on_error(_client, error: aai_stream.StreamingError):217 print(f"\nStreaming error: {error}")218219 client.on(aai_stream.StreamingEvents.Begin, on_begin)220 client.on(aai_stream.StreamingEvents.Turn, on_turn)221 client.on(aai_stream.StreamingEvents.Termination, on_terminated)222 client.on(aai_stream.StreamingEvents.Error, on_error)223224 client.connect(225 aai_stream.StreamingParameters(226 sample_rate=SAMPLE_RATE,227 format_turns=False, # better latency for voice agents228 )229 )230231 pa = pyaudio.PyAudio()232 stream = pa.open(233 format=pyaudio.paInt16,234 channels=1,235 rate=SAMPLE_RATE,236 input=True,237 frames_per_buffer=FRAMES_PER_BUFFER,238 )239240 try:241 print("Speak into your microphone (Ctrl+C to stop)...")242 def audio_gen():243 while True:244 yield stream.read(FRAMES_PER_BUFFER, exception_on_overflow=False)245 client.stream(audio_gen())246 except KeyboardInterrupt:247 pass248 finally:249 client.disconnect(terminate=True)250 stream.stop_stream()251 stream.close()252 pa.terminate()253254if __name__ == "__main__":255 main()