Transcribe a meeting recording with speaker labels and automatic language detection, identify speakers by name, then send the transcript to LLM Gateway for a formatted summary with action items. Products used: Pre-recorded STT + speaker diarization + Speaker Identification + language detection + LLM Gateway Model selection: This example uses bothDocumentation Index
Fetch the complete documentation index at: https://assemblyai.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
universal-3-pro and universal-2 for broad language coverage across 99 languages. If your meetings are English-only, you can use universal-3-pro alone for the highest accuracy.
- Python
- JavaScript
import requests
import time
# ── Config ────────────────────────────────────────────────────
base_url = "https://api.assemblyai.com"
headers = {"authorization": "YOUR_API_KEY"}
audio_url = "https://assembly.ai/wildfires.mp3"
# ── Step 1: Transcribe with speaker labels + language detection ──
data = {
"audio_url": audio_url,
"speech_models": ["universal-3-pro", "universal-2"],
"language_detection": True,
"speaker_labels": True,
}
response = requests.post(base_url + "/v2/transcript", headers=headers, json=data)
response.raise_for_status()
transcript_id = response.json()["id"]
while True:
result = requests.get(f"{base_url}/v2/transcript/{transcript_id}", headers=headers).json()
if result["status"] == "completed":
break
elif result["status"] == "error":
raise RuntimeError(f"Transcription failed: {result['error']}")
time.sleep(3)
# ── Step 2: Identify speakers by name ──
understanding_response = requests.post(
"https://llm-gateway.assemblyai.com/v1/understanding",
headers=headers,
json={
"transcript_id": transcript_id,
"speech_understanding": {
"request": {
"speaker_identification": {
"speaker_type": "name",
"known_values": ["Alice", "Bob"], # Replace with actual participant names
}
}
},
},
)
understanding_response.raise_for_status()
identified = understanding_response.json()
# ── Step 3: Format identified transcript for the LLM ──
speaker_transcript = "\n".join(
f"{u['speaker']}: {u['text']}" for u in identified["utterances"]
)
# ── Step 4: Generate meeting notes via LLM Gateway ──
llm_response = requests.post(
"https://llm-gateway.assemblyai.com/v1/chat/completions",
headers=headers,
json={
"model": "claude-sonnet-4-5-20250929",
"messages": [
{
"role": "user",
"content": (
"You are a meeting notes assistant. Given the transcript below, produce:\n"
"1. A concise summary (3-5 sentences)\n"
"2. Key decisions made\n"
"3. Action items with owners (use speaker labels)\n\n"
f"Transcript:\n{speaker_transcript}"
),
}
],
"max_tokens": 2000,
},
)
llm_response.raise_for_status()
print("=== Meeting Notes ===\n")
print(llm_response.json()["choices"][0]["message"]["content"])
const baseUrl = "https://api.assemblyai.com";
const headers = {
authorization: "YOUR_API_KEY",
"Content-Type": "application/json",
};
const audioUrl = "https://assembly.ai/wildfires.mp3";
// Step 1: Transcribe with speaker labels + language detection
let res = await fetch(`${baseUrl}/v2/transcript`, {
method: "POST",
headers,
body: JSON.stringify({
audio_url: audioUrl,
speech_models: ["universal-3-pro", "universal-2"],
language_detection: true,
speaker_labels: true,
}),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const { id: transcriptId } = await res.json();
let result;
while (true) {
res = await fetch(`${baseUrl}/v2/transcript/${transcriptId}`, { headers });
result = await res.json();
if (result.status === "completed") break;
if (result.status === "error")
throw new Error(`Transcription failed: ${result.error}`);
await new Promise((r) => setTimeout(r, 3000));
}
// Step 2: Identify speakers by name
const understandingRes = await fetch(
"https://llm-gateway.assemblyai.com/v1/understanding",
{
method: "POST",
headers,
body: JSON.stringify({
transcript_id: transcriptId,
speech_understanding: {
request: {
speaker_identification: {
speaker_type: "name",
known_values: ["Alice", "Bob"], // Replace with actual participant names
},
},
},
}),
}
);
if (!understandingRes.ok) throw new Error(`Error: ${understandingRes.status}`);
const identified = await understandingRes.json();
// Step 3: Format identified transcript for the LLM
const speakerTranscript = identified.utterances
.map((u) => `${u.speaker}: ${u.text}`)
.join("\n");
// Step 4: Generate meeting notes via LLM Gateway
res = await fetch("https://llm-gateway.assemblyai.com/v1/chat/completions", {
method: "POST",
headers,
body: JSON.stringify({
model: "claude-sonnet-4-5-20250929",
messages: [
{
role: "user",
content:
"You are a meeting notes assistant. Given the transcript below, produce:\n" +
"1. A concise summary (3-5 sentences)\n" +
"2. Key decisions made\n" +
"3. Action items with owners (use speaker labels)\n\n" +
`Transcript:\n${speakerTranscript}`,
},
],
max_tokens: 2000,
}),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const llmResult = await res.json();
console.log("=== Meeting Notes ===\n");
console.log(llmResult.choices[0].message.content);
Example output
Example output
=== Meeting Notes ===
## Summary
The discussion covered the impact of Canadian wildfire smoke on US air quality.
Experts explained how particulate matter affects respiratory and cardiovascular
health. The group reviewed current air quality index readings and discussed
protective measures for affected communities.
## Key decisions
- Monitor AQI levels daily until smoke clears
- Issue public health advisories for sensitive groups
## Action items
- Alice: Compile daily AQI data for the affected regions
- Bob: Draft public advisory messaging for distribution
- Alice: Coordinate with local health departments on response protocols
Speaker Identification maps generic labels like “Speaker A” to real names. You can pass a list of
known_values to guide identification, or omit it to let the model infer names from the conversation. Learn more in the Speaker Identification guide.See the End-to-end examples overview for all available pipelines.