> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mavera.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Customer Call Intelligence

> Transcribe customer calls with diarization and per-utterance sentiment, mine customer language for pain points and product language, and build messaging playbooks via Mavera.

## Scenario

Transcribe customer calls with diarization and per-utterance sentiment. Separate customer from agent speech and mine the customer's exact language — how they describe problems, what words they use for pain points — to build a messaging playbook in the customer's own voice.

**Flow:** Deepgram `POST /v1/listen?model=nova-3&diarize=true&sentiment=true&utterances=true` → speaker-separated transcript with sentiment → Mavera `POST /mave/chat` → Messaging playbook

## Code

<CodeGroup>
  ```python Python theme={"dark"}
  import os, requests, time

  DG = os.environ["DEEPGRAM_API_KEY"]
  MV = os.environ["MAVERA_API_KEY"]
  MV_BASE = "https://app.mavera.io/api/v1"
  MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

  CALLS = ["calls/discovery-acme.wav", "calls/support-globex.wav",
      "calls/onboarding-initech.wav", "calls/renewal-umbrella.wav", "calls/churn-soylent.wav"]
  params = {"model": "nova-3", "smart_format": "true", "punctuate": "true",
      "diarize": "true", "sentiment": "true", "utterances": "true", "language": "en"}
  all_cust = []
  for call_file in CALLS:
      with open(call_file, "rb") as f:
          resp = requests.post("https://api.deepgram.com/v1/listen", params=params,
              headers={"Authorization": f"Token {DG}", "Content-Type": "audio/wav"},
              data=f, timeout=120)
      resp.raise_for_status()
      r = resp.json()
      utts = r.get("results",{}).get("utterances",[])
      sents = r.get("results",{}).get("sentiments",{}).get("segments",[])
      sent_map = {f"{s.get('start',0):.1f}": s.get("sentiment","neutral") for s in sents}
      spk_wc = {}
      for u in utts:
          sp = u.get("speaker",0); spk_wc[sp] = spk_wc.get(sp,0) + len(u.get("transcript","").split())
      cust_sp = max(spk_wc, key=spk_wc.get) if spk_wc else 0
      cust_utts = [{"text": u["transcript"],
          "sentiment": sent_map.get(f"{u.get('start',0):.1f}", "neutral"),
          "time": f"{int(u.get('start',0)//60)}:{int(u.get('start',0)%60):02d}"}
          for u in utts if u.get("speaker") == cust_sp]
      all_cust.append({"file": os.path.basename(call_file), "utts": cust_utts})
      print(f"{os.path.basename(call_file)} — {len(utts)} total, {len(cust_utts)} customer")
      time.sleep(2)

  corpus = ""
  for c in all_cust:
      corpus += f"\n### {c['file']}\n"
      for u in c["utts"][:15]:
          corpus += f"  [{u['time']}] ({u['sentiment']}) \"{u['text'][:250]}\"\n"

  time.sleep(1)
  playbook = requests.post(f"{MV_BASE}/mave/chat", headers=MV_H, json={
      "message": f"Voice-of-customer analyst. {len(CALLS)} calls (customer only).\n\n"
          f"{corpus[:10000]}\n\nProduce:\n"
          "1. **PAIN POINT VOCABULARY** — Exact phrases for problems\n"
          "2. **PRODUCT LANGUAGE** — How customers describe your product vs. you\n"
          "3. **EMOTIONAL TRIGGERS** — Words with negative sentiment\n"
          "4. **SUCCESS LANGUAGE** — How customers describe wins\n"
          "5. **OBJECTION PATTERNS** — Recurring concerns\n"
          "6. **MESSAGING PLAYBOOK** — 10 copy lines using customer vocabulary\n"
          "7. **WORDS TO STEAL** — Customer phrases better than your copy\n"
  }).json()
  print(playbook.get("content", "")[:4000])
  ```

  ```javascript JavaScript theme={"dark"}
  import fs from "fs";
  import path from "path";
  const DG = process.env.DEEPGRAM_API_KEY, MV = process.env.MAVERA_API_KEY;
  const MV_BASE = "https://app.mavera.io/api/v1";
  const MV_H = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };

  const CALLS = ["calls/discovery-acme.wav", "calls/support-globex.wav",
    "calls/onboarding-initech.wav", "calls/renewal-umbrella.wav", "calls/churn-soylent.wav"];
  const params = new URLSearchParams({ model: "nova-3", smart_format: "true", punctuate: "true",
    diarize: "true", sentiment: "true", utterances: "true", language: "en" });

  const allCust = [];
  for (const f of CALLS) {
    const r = await fetch(`https://api.deepgram.com/v1/listen?${params}`, { method: "POST",
      headers: { Authorization: `Token ${DG}`, "Content-Type": "audio/wav" },
      body: fs.readFileSync(f) }).then(r => r.json());
    const utts = r.results?.utterances || [];
    const sentMap = Object.fromEntries(
      (r.results?.sentiments?.segments||[]).map(s => [s.start?.toFixed(1), s.sentiment||"neutral"]));
    const spkW = {};
    for (const u of utts) spkW[u.speaker??0] = (spkW[u.speaker??0]||0) + (u.transcript||"").split(/\s+/).length;
    const custSp = Object.entries(spkW).sort((a,b) => b[1]-a[1])[0]?.[0];
    allCust.push({ file: path.basename(f),
      utts: utts.filter(u => String(u.speaker)===custSp).map(u => ({
        text: u.transcript, sentiment: sentMap[u.start?.toFixed(1)]||"neutral",
        time: `${Math.floor((u.start||0)/60)}:${String(Math.floor((u.start||0)%60)).padStart(2,"0")}` })) });
    await new Promise(r => setTimeout(r, 2000));
  }

  let corpus = allCust.map(c => `### ${c.file}\n` +
    c.utts.slice(0,15).map(u => `  [${u.time}] (${u.sentiment}) "${u.text.slice(0,250)}"`).join("\n")).join("\n\n");
  const playbook = await fetch(`${MV_BASE}/mave/chat`, { method: "POST", headers: MV_H,
    body: JSON.stringify({ message: `VoC analyst. ${CALLS.length} calls, customer only.\n\n${corpus.slice(0,10000)}\n\n`
      + "Produce: PAIN POINT VOCABULARY, PRODUCT LANGUAGE, EMOTIONAL TRIGGERS, "
      + "SUCCESS LANGUAGE, OBJECTION PATTERNS, MESSAGING PLAYBOOK (10 lines), WORDS TO STEAL" }),
  }).then(r => r.json());
  console.log(playbook.content || "");
  ```
</CodeGroup>

## Example Output

```text theme={"dark"}
discovery-acme.wav — 142 total, 68 customer | churn-soylent.wav — 121 total, 63 customer

PAIN POINT VOCABULARY
  "We're flying blind on what's working" (3 calls)
  "I spend half my Monday pulling reports nobody reads" (2 calls)

PRODUCT LANGUAGE
  They say: "the dashboard thing" → You say: "analytics platform"
  They say: "when it tells me what to do" → You say: "AI recommendations"

MESSAGING PLAYBOOK
  1. "Stop flying blind. See what's working in real time."
  2. "Your Monday shouldn't start with report pulling."

WORDS TO STEAL
  "flying blind" > "lack visibility" (use in hero copy)
```

## Error Handling

<AccordionGroup>
  <Accordion title="Wrong speaker assignment">Deepgram assigns IDs (0, 1, 2...) without labeling customer vs. agent. The code assumes the speaker with the most words is the customer. For inbound support calls, flip the logic or detect based on a known agent greeting.</Accordion>
  <Accordion title="Sentiment granularity">Sentiment is segment-level (5-15 seconds), not per-word. Values are `positive`, `neutral`, or `negative` — no numeric scores.</Accordion>
  <Accordion title="Batch processing">Processing 5+ calls sequentially takes time. Parallelize with `asyncio` or `Promise.all`, limiting to 5 concurrent requests.</Accordion>
</AccordionGroup>
