What NewsBot does
The week's news,
grouped into stories.
NewsBot reads articles across many sources every day, clusters the ones covering the same event, summarizes each one source by source, scores the tone, and emails a single digest once a week.
Grouping coverage
One event, covered many times, shown once.
Most events are reported by several outlets at once. NewsBot groups those articles into a single entry per story: what happened, how each source covered it, and the overall tone.
Central bank leaves rates unchanged amid cooling inflation
One entry with a summary per source, the aggregated tone, and how many outlets covered it.
The pipeline
Four stages, daily to weekly.
Collection runs every day. Once a week the rest of the chain turns seven days of articles into a finished digest.
Collect articles
Pull fresh articles from each topic's sources and extract the full text, de-duplicated.
Cluster into stories
Group the week's articles into distinct stories by meaning, not by keyword.
Summarize & score
Summarize each story per source and read its tone, with guardrails against AI errors.
Deliver the digest
Render the digest, email every subscriber, and archive it in the web app.
Under the hood
The algorithm, in detail.
For the curious and the technical. Expand any stage to see the models, the math, and the guardrails.
01 Daily collection & filteringRSS / Atom feeds · HTML pages · trafilatura extraction ▸
A scraper agent fetches articles from every source configured for a topic — both RSS / Atom feeds and ordinary HTML pages. For an HTML source it discovers the article links on a listing page, then pulls each full article body with trafilatura (falling back to BeautifulSoup) rather than trusting feed snippets.
- Each article is filtered by keyword and by semantic relevance to the topic, using a configurable cosine-similarity threshold.
- Duplicates are dropped by URL and title similarity before storage.
- Survivors land in PostgreSQL with their extracted text, ready for the weekly pass.
02 Story clusteringsentence-transformer embeddings · DBSCAN / HDBSCAN · geographical penalty ▸
The core step. Each week the last seven days of articles are embedded and grouped into stories.
- Embeddings: a sentence-transformer model running on an ONNX backend. Each article is embedded as a hybrid of its title plus the start of its body — a richer signal than the title alone.
- Similarity: cosine similarity between article embeddings.
- Clustering: configurable per topic —
DBSCAN,HDBSCAN, or greedy — with a tunable similarity threshold. - Geographical penalty: spaCy named-entity recognition extracts the locations each article mentions; when two articles name different, non-overlapping places their similarity is reduced — so a factory fire in Hamburg and one in Osaka never fuse into a single story.
- Quality gate: a cluster only becomes a top story if it draws on at least two independent sources; single-outlet clusters are dropped as noise.
The top N clusters move on, each sampled for central, recent, and deliberately diverse articles so the summary sees the full spread.
03 Summarizationtwo-pass LLM · per-source · LLM-as-judge · entity validation ▸
Each story is summarized from the perspective of every source that covered it, using a large language model — a cloud model, or a local Ollama model, configurable.
- Two-pass: an intermediate summary is built from the cluster, then condensed into the final — steadier on large clusters.
- LLM-as-judge: a separate judge agent reviews each summary for hallucinations and rejects ones that don't hold up.
- Name validation: named entities in a summary are checked against the source articles; anything that was never in the source is flagged as a likely hallucination.
04 Sentiment analysispysentimiento · VADER / TextBlob fallback · per-source aggregation ▸
Every article's tone is scored, then averaged per source within each story.
- Primary model:
pysentimiento(transformer-based, multilingual), withVADERandTextBlobas fallbacks. - Each article gets a compound score from
-1.0(very negative) to+1.0(very positive), labelled negative / neutral / positive. - Aggregating by source shows, at a glance, which outlets framed a story warmly and which didn't.
05 Report generation & deliveryJinja2 · inlined CSS · HMAC unsubscribe tokens ▸
The finished analysis is rendered to HTML, Markdown and plain text with Jinja2, themed from the topic's palette (the same colours dressing this page).
- Email CSS is inlined with
css_inlinefor client compatibility, with dedicated dark-mode handling. - Each subscriber gets a personalized email carrying an HMAC-signed unsubscribe / manage-subscriptions token.
- Delivery runs through a pluggable provider layer — SMTP, Resend, or EmailJS. Every report is archived in the web app.
Curious about the internals? The full source is public on GitHub — github.com/Jastchi/newsbot-public ↗
Getting started
Sign in to choose your topics.
Signing in lets you choose which topics NewsBot tracks for you, browse the report archive, and manage your weekly email.
Sign in → Explore the app →