Scenario
Track how media sentiment around your brand, product category, or key topics shifts week over week. This job searches for mentions across all sources, batches them into weekly windows, sends each batch to Mavera Chat for structured sentiment analysis, and outputs a time-series sentiment dashboard with trend arrows. Flow: NewsAPIGET /everything?q={topic} (weekly batches) → Mavera POST /mave/chat per batch → Sentiment time series
Code
import os, requests, time
from datetime import datetime, timedelta
NA_KEY = os.environ["NEWSAPI_KEY"]
NA_BASE = "https://newsapi.org/v2"
NA_H = {"X-Api-Key": NA_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"}
TOPIC = "artificial intelligence marketing"
WEEKS = 4
# 1. Fetch articles in weekly batches
weekly_data = []
for week in range(WEEKS):
end = datetime.now() - timedelta(weeks=week)
start = end - timedelta(days=7)
r = requests.get(f"{NA_BASE}/everything", headers=NA_H, params={
"q": TOPIC, "from": start.strftime("%Y-%m-%d"),
"to": end.strftime("%Y-%m-%d"), "sortBy": "relevancy",
"language": "en", "pageSize": 25,
})
if not r.ok:
print(f"Week {week}: API error {r.status_code}")
continue
articles = r.json().get("articles", [])
weekly_data.append({
"week_label": f"{start.strftime('%b %d')} – {end.strftime('%b %d')}",
"articles": articles, "count": len(articles),
})
print(f"Week {week}: {len(articles)} articles ({start.strftime('%b %d')} – {end.strftime('%b %d')})")
time.sleep(1)
# 2. Batch sentiment analysis via Mave
sentiment_series = []
for week in weekly_data:
corpus = "\n".join(
f"- [{a.get('source',{}).get('name','')}] {a['title']}: {a.get('description','')[:150]}"
for a in week["articles"][:20]
)
analysis = requests.post(f"{MV_BASE}/mave/chat", headers=MV_H, json={
"message": f"Sentiment analyst. Analyze media coverage for '{TOPIC}' during {week['week_label']}.\n\n"
f"ARTICLES ({week['count']}):\n{corpus}\n\n"
"Return JSON with: overall_sentiment (positive/negative/neutral/mixed), "
"confidence (0-100), positive_pct, negative_pct, neutral_pct, "
"top_positive_theme, top_negative_theme, notable_shift, key_quote."
}).json()
content = analysis.get("content", "")
sentiment_series.append({"week": week["week_label"], "count": week["count"], "analysis": content[:600]})
time.sleep(0.5)
# 3. Trend summary
trend = requests.post(f"{MV_BASE}/mave/chat", headers=MV_H, json={
"message": f"Given these {WEEKS} weeks of sentiment data for '{TOPIC}', identify the overall trend.\n\n"
+ "\n\n".join(f"**{s['week']}** ({s['count']} articles):\n{s['analysis']}" for s in sentiment_series)
+ "\n\nProvide: trend direction (improving/declining/stable), confidence, biggest driver, prediction for next week, recommended action."
}).json()
print(f"\n{'='*60}\nSENTIMENT TREND: {TOPIC}\n{'='*60}")
for s in sentiment_series:
print(f"\n{s['week']} ({s['count']} articles):\n{s['analysis'][:300]}")
print(f"\n{'='*60}\nTREND ANALYSIS\n{'='*60}")
print(trend.get("content", "")[:800])
const NA_KEY = process.env.NEWSAPI_KEY;
const NA_BASE = "https://newsapi.org/v2";
const NA_H = { "X-Api-Key": NA_KEY };
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 = "artificial intelligence marketing";
const WEEKS = 4;
// 1. Weekly batches
const weeklyData = [];
for (let week = 0; week < WEEKS; week++) {
const end = new Date(Date.now() - week * 7 * 86400000);
const start = new Date(end - 7 * 86400000);
const r = await fetch(
`${NA_BASE}/everything?q=${encodeURIComponent(TOPIC)}&from=${start.toISOString().slice(0,10)}&to=${end.toISOString().slice(0,10)}&sortBy=relevancy&language=en&pageSize=25`,
{ headers: NA_H });
if (!r.ok) { console.log(`Week ${week}: error ${r.status}`); continue; }
const articles = (await r.json()).articles || [];
const label = `${start.toLocaleDateString("en",{month:"short",day:"numeric"})} – ${end.toLocaleDateString("en",{month:"short",day:"numeric"})}`;
weeklyData.push({ week_label: label, articles, count: articles.length });
console.log(`Week ${week}: ${articles.length} articles (${label})`);
await new Promise(r => setTimeout(r, 1000));
}
// 2. Batch sentiment
const sentimentSeries = [];
for (const week of weeklyData) {
const corpus = week.articles.slice(0, 20)
.map(a => `- [${a.source?.name||""}] ${a.title}: ${(a.description||"").slice(0,150)}`).join("\n");
const analysis = await fetch(`${MV_BASE}/mave/chat`, { method: "POST", headers: MV_H,
body: JSON.stringify({ message: `Sentiment analyst. '${TOPIC}' coverage for ${week.week_label}.\n\nARTICLES (${week.count}):\n${corpus}\n\nReturn JSON: overall_sentiment, confidence, positive_pct, negative_pct, neutral_pct, top themes, key_quote.` }),
}).then(r => r.json());
sentimentSeries.push({ week: week.week_label, count: week.count, analysis: (analysis.content||"").slice(0,600) });
await new Promise(r => setTimeout(r, 500));
}
// 3. Trend
const trend = await fetch(`${MV_BASE}/mave/chat`, { method: "POST", headers: MV_H,
body: JSON.stringify({ message: `${WEEKS}-week sentiment trend for '${TOPIC}'.\n\n${sentimentSeries.map(s=>`**${s.week}** (${s.count} articles):\n${s.analysis}`).join("\n\n")}\n\nTrend direction, confidence, biggest driver, next-week prediction, recommended action.` }),
}).then(r => r.json());
console.log(`\n${"=".repeat(60)}\nSENTIMENT TREND: ${TOPIC}`);
for (const s of sentimentSeries)
console.log(`\n${s.week} (${s.count} articles):\n${s.analysis.slice(0,300)}`);
console.log(`\n${"=".repeat(60)}\nTREND ANALYSIS`);
console.log((trend.content || "").slice(0, 800));
Example Output
Week 0: 25 articles (Mar 10 – Mar 17)
Week 1: 22 articles (Mar 03 – Mar 10)
Week 2: 19 articles (Feb 24 – Mar 03)
Week 3: 23 articles (Feb 17 – Feb 24)
SENTIMENT TREND: artificial intelligence marketing
============================================================
Mar 10 – Mar 17 (25 articles):
{"overall_sentiment": "positive", "confidence": 78,
"positive_pct": 56, "negative_pct": 20, "neutral_pct": 24,
"top_positive_theme": "Personalization ROI gains",
"top_negative_theme": "Privacy regulation fears"}
TREND ANALYSIS
============================================================
Direction: IMPROVING (↑ 12% positive shift over 4 weeks)
Driver: Enterprise adoption stories replacing hype-cycle skepticism.
Prediction: Continued positive bias until Q2 earnings season.
Action: Publish thought leadership now — sentiment tailwind amplifies reach.
Error Handling
Weekly batch gaps
Weekly batch gaps
Free tier limits search to past 30 days. Reduce
WEEKS to 4 max on free plans. Business tier supports full archive.JSON parsing
JSON parsing
Mave returns natural language by default. Prompt for JSON explicitly and parse with
json.loads() / JSON.parse(). Wrap in try/catch for malformed responses.Topic specificity
Topic specificity
Broad topics like “AI” return noise. Use quoted phrases and boolean operators:
"AI marketing" AND ("ROI" OR "attribution").