> ## 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.

# AI Summary → News Digest with Personas

### Scenario

Perigon provides AI-generated summaries for articles, saving you from parsing raw content. This job pulls summarized articles for your industry, creates Mavera personas representing different audience segments, then rewrites the digest in each persona's voice — so your newsletter can have a section for executives, one for practitioners, and one for students.

**Flow:** Perigon `GET /all` (with summaries) → Mavera `POST /personas` → `POST /speak` per persona → Multi-voice digest

### Code

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

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

  TOPIC = "fintech"

  # 1. Fetch articles with summaries
  r = requests.get(f"{PG_BASE}/all", params={
      "apiKey": PG_KEY, "q": TOPIC, "sortBy": "date",
      "size": 12, "sourceGroup": "top100",
  })
  r.raise_for_status()
  articles = r.json().get("articles", [])
  print(f"Fetched {len(articles)} articles for '{TOPIC}'")

  # 2. Build digest from summaries
  digest_items = []
  for a in articles:
      summary = a.get("summary", a.get("description", ""))
      if not summary:
          continue
      digest_items.append(
          f"**{a.get('title','')}** ({a.get('source',{}).get('name','')})\n{summary[:400]}"
      )

  digest_text = "\n\n".join(digest_items[:10])

  # 3. Create audience personas
  AUDIENCES = [
      {"name": "C-Suite Executive", "desc": "CEO/CFO at a fintech company. Cares about market trends, regulation, fundraising signals, and strategic positioning. Prefers bullet points, numbers, and bottom-line impact."},
      {"name": "Product Manager", "desc": "PM at a fintech startup. Cares about feature trends, user expectations, competitive moves, and technology shifts. Prefers actionable insights with implementation angles."},
      {"name": "Finance Student", "desc": "Graduate student studying financial technology. Cares about industry structure, career opportunities, and understanding how concepts connect. Prefers explanations with context."},
  ]
  persona_ids = []
  for aud in AUDIENCES:
      p = requests.post(f"{MV_BASE}/personas", headers=MV_H, json={
          "name": f"Digest: {aud['name']}",
          "description": aud["desc"],
      }).json()
      persona_ids.append({"id": p["id"], "name": aud["name"]})
      time.sleep(0.3)

  # 4. Generate persona-voiced digest
  for persona in persona_ids:
      speak = requests.post(f"{MV_BASE}/speak", headers=MV_H, json={
          "persona_id": persona["id"],
          "input": [
              {"role": "system", "content": f"You are a {persona['name']}. Rewrite this news digest in YOUR voice — the way you'd summarize it for peers. 5-7 bullet points. Match your communication style."},
              {"role": "user", "content": f"This week's {TOPIC} news:\n\n{digest_text}"},
          ],
          "mode": "interview",
      }).json()

      print(f"\n{'='*60}\nDIGEST FOR: {persona['name']}\n{'='*60}")
      for ex in speak.get("exchanges", speak.get("messages", [])):
          if ex.get("role") == "assistant":
              print(ex["content"][:600])
      time.sleep(0.3)
  ```

  ```javascript JavaScript theme={"dark"}
  const PG_KEY = process.env.PERIGON_API_KEY;
  const PG_BASE = "https://api.goperigon.com/v1";
  const 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 TOPIC = "fintech";

  // 1. Articles with summaries
  const articles = (await (await fetch(
    `${PG_BASE}/all?apiKey=${PG_KEY}&q=${encodeURIComponent(TOPIC)}&sortBy=date&size=12&sourceGroup=top100`
  )).json()).articles || [];
  console.log(`Fetched ${articles.length} articles`);

  // 2. Build digest
  const digestItems = articles.filter(a => a.summary || a.description)
    .map(a => `**${a.title || ""}** (${a.source?.name || ""})\n${(a.summary || a.description || "").slice(0, 400)}`);
  const digestText = digestItems.slice(0, 10).join("\n\n");

  // 3. Audience personas
  const AUDIENCES = [
    { name: "C-Suite Executive", desc: "CEO/CFO. Market trends, regulation, fundraising. Bullet points." },
    { name: "Product Manager", desc: "PM at fintech startup. Features, competition, tech shifts. Actionable." },
    { name: "Finance Student", desc: "Grad student. Industry structure, careers, explanations with context." },
  ];
  const personaIds = [];
  for (const aud of AUDIENCES) {
    const p = await fetch(`${MV_BASE}/personas`, { method: "POST", headers: MV_H,
      body: JSON.stringify({ name: `Digest: ${aud.name}`, description: aud.desc }),
    }).then(r => r.json());
    personaIds.push({ id: p.id, name: aud.name });
    await new Promise(r => setTimeout(r, 300));
  }

  // 4. Persona-voiced digest
  for (const persona of personaIds) {
    const speak = await fetch(`${MV_BASE}/speak`, { method: "POST", headers: MV_H,
      body: JSON.stringify({ persona_id: persona.id, mode: "interview",
        input: [
          { role: "system", content: `You are a ${persona.name}. Rewrite this digest in YOUR voice. 5-7 bullets.` },
          { role: "user", content: `This week's ${TOPIC} news:\n\n${digestText}` },
        ],
      }),
    }).then(r => r.json());
    console.log(`\n${"=".repeat(60)}\nDIGEST FOR: ${persona.name}\n${"=".repeat(60)}`);
    for (const ex of speak.exchanges || speak.messages || [])
      if (ex.role === "assistant") console.log(ex.content.slice(0, 600));
    await new Promise(r => setTimeout(r, 300));
  }
  ```
</CodeGroup>

### Example Output

```text theme={"dark"}
Fetched 12 articles for 'fintech'

DIGEST FOR: C-Suite Executive
============================================================
• Stripe valuation hits $95B — signals public market appetite for payments
  infrastructure. Watch for IPO filing by Q3.
• EU PSD3 draft tightens open banking. Compliance cost: estimate €2-5M for
  mid-size players. Budget now.
• Plaid acquires identity verification startup. Build-vs-buy calculus shifts.
• Neobank customer acquisition costs up 34% YoY. CAC/LTV ratios compressing.

DIGEST FOR: Finance Student
============================================================
• Stripe just hit a $95B valuation — that's the highest for any private fintech.
  To put it in context, that's more than Goldman Sachs was worth 10 years ago.
  An IPO would test whether public markets agree with private valuations.
• The EU is working on PSD3, which updates rules about how banks share data.
  PSD2 created open banking — PSD3 adds more security requirements.
```

### Error Handling

<AccordionGroup>
  <Accordion title="Missing summaries">Not all articles have AI summaries. Fall back to `description` field. If both are empty, skip the article.</Accordion>
  <Accordion title="Persona voice drift">If persona output sounds generic, add more specifics to the description — communication style, jargon preferences, typical sentence length.</Accordion>
  <Accordion title="Digest length">10 articles × 400 chars = \~4,000 chars. Within Mavera's context limits. For larger digests, split into two Speak sessions.</Accordion>
</AccordionGroup>
