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.

100s
articles / day
1
digest / week
≥2
sources / story
0 articles 0 stories 0 dropped as noise
tone negative neutral positive

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.

reuters.com · "Central bank holds rates steady"
bloomberg.com · "Rate decision lands as expected"
ft.com · "Policymakers keep borrowing costs on hold"
apnews.com · "No change to interest rates this month"
CLUSTER
Top story · 4 sources

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.

01
Daily

Collect articles

Pull fresh articles from each topic's sources and extract the full text, de-duplicated.

02
Weekly

Cluster into stories

Group the week's articles into distinct stories by meaning, not by keyword.

03
Weekly

Summarize & score

Summarize each story per source and read its tone, with guardrails against AI errors.

04
Weekly

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), with VADER and TextBlob as 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_inline for 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.
DjangoFastAPIPostgreSQL Sentence-TransformersONNXspaCy NERDBSCAN / HDBSCAN OllamapysentimientoAPSchedulerDockerRaspberry Pi

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 →