Getting startedEnd-to-end examples

Sales call intelligence

Transcribe a sales call with speaker labels and sentiment analysis, identify speakers by role, then use LLM Gateway to generate a coaching scorecard with talk/listen ratio and sentiment insights.

Products used: Pre-recorded STT + speaker diarization + Speaker Identification + sentiment analysis + LLM Gateway

Model selection: Uses universal-3-pro for the highest English accuracy. For multilingual sales teams, add universal-2 as a fallback.

1import requests
2import time
3from collections import Counter
4
5# ── Config ────────────────────────────────────────────────────
6base_url = "https://api.assemblyai.com"
7headers = {"authorization": "YOUR_API_KEY"}
8
9audio_url = "https://assembly.ai/wildfires.mp3"
10
11# ── Step 1: Transcribe with speaker labels + sentiment analysis ──
12data = {
13 "audio_url": audio_url,
14 "speech_models": ["universal-3-pro"],
15 "speaker_labels": True,
16 "sentiment_analysis": True,
17}
18
19response = requests.post(base_url + "/v2/transcript", headers=headers, json=data)
20response.raise_for_status()
21transcript_id = response.json()["id"]
22
23while True:
24 result = requests.get(f"{base_url}/v2/transcript/{transcript_id}", headers=headers).json()
25 if result["status"] == "completed":
26 break
27 elif result["status"] == "error":
28 raise RuntimeError(f"Transcription failed: {result['error']}")
29 time.sleep(3)
30
31# ── Step 2: Identify speakers by role ──
32understanding_response = requests.post(
33 "https://llm-gateway.assemblyai.com/v1/understanding",
34 headers=headers,
35 json={
36 "transcript_id": transcript_id,
37 "speech_understanding": {
38 "request": {
39 "speaker_identification": {
40 "speaker_type": "role",
41 "known_values": ["Sales Rep", "Customer"],
42 }
43 }
44 },
45 },
46)
47understanding_response.raise_for_status()
48identified = understanding_response.json()
49
50# ── Step 3: Calculate talk/listen ratio per speaker ──
51speaker_durations = Counter()
52for utterance in identified["utterances"]:
53 duration_ms = utterance["end"] - utterance["start"]
54 speaker_durations[utterance["speaker"]] += duration_ms
55
56total_ms = sum(speaker_durations.values())
57talk_ratios = {
58 speaker: round(dur / total_ms * 100, 1)
59 for speaker, dur in speaker_durations.items()
60}
61
62# ── Step 4: Summarize sentiment shifts ──
63sentiment_by_speaker = {}
64for s in result["sentiment_analysis_results"]:
65 speaker = s.get("speaker", "Unknown")
66 sentiment_by_speaker.setdefault(speaker, []).append(s["sentiment"])
67
68sentiment_summary = ""
69for speaker, sentiments in sentiment_by_speaker.items():
70 counts = Counter(sentiments)
71 sentiment_summary += (
72 f"{speaker}: "
73 f"{counts.get('POSITIVE', 0)} positive, "
74 f"{counts.get('NEUTRAL', 0)} neutral, "
75 f"{counts.get('NEGATIVE', 0)} negative\n"
76 )
77
78# ── Step 5: Format transcript and generate coaching scorecard ──
79speaker_transcript = "\n".join(
80 f"{u['speaker']}: {u['text']}" for u in identified["utterances"]
81)
82
83llm_response = requests.post(
84 "https://llm-gateway.assemblyai.com/v1/chat/completions",
85 headers=headers,
86 json={
87 "model": "claude-sonnet-4-5-20250929",
88 "messages": [
89 {
90 "role": "user",
91 "content": (
92 "You are a sales coaching assistant. Analyze this sales call and produce a scorecard.\n\n"
93 f"Talk/listen ratios: {talk_ratios}\n\n"
94 f"Sentiment breakdown:\n{sentiment_summary}\n"
95 f"Transcript:\n{speaker_transcript}\n\n"
96 "Produce:\n"
97 "1. Call summary (2-3 sentences)\n"
98 "2. Talk/listen ratio analysis (ideal is 40/60 for the rep)\n"
99 "3. Customer sentiment shifts and what caused them\n"
100 "4. Top 3 coaching suggestions for the sales rep"
101 ),
102 }
103 ],
104 "max_tokens": 2000,
105 },
106)
107llm_response.raise_for_status()
108
109print("=== Sales Call Scorecard ===\n")
110print(llm_response.json()["choices"][0]["message"]["content"])
=== Sales Call Scorecard ===
## Call summary
This call discussed the environmental and health impacts of wildfire smoke on
US communities. The speakers covered air quality data, health risks, and
recommended precautions for the public.
## Talk/listen ratio
Sales Rep: 65.3% | Customer: 34.7%
Analysis: The ratio is inverted from the ideal 40/60 split. The rep dominated
the conversation — focus on asking more open-ended questions.
## Customer sentiment shifts
- Started neutral during introductions
- Shifted negative when discussing health risks and poor air quality readings
- Returned to neutral during the action-planning portion
## Coaching suggestions
1. Ask more discovery questions early to understand the customer's specific concerns
2. When the customer expresses concern, acknowledge before pivoting to solutions
3. Summarize key points at the end and confirm next steps with clear ownership

See the End-to-end examples overview for all available pipelines.