Ingests twenty world news feeds, summarizes each story into labelled facts, plots it where it happened, and produces a spoken broadcast with per-platform posts — that never publish themselves.
The challenge
Automated news summarization has two failure modes that matter more than quality.
The first is quiet fabrication: about a third of RSS items ship no usable body at
all — some publishers put a bare <img> tag in <content> and nothing else —
which leaves a summarizer working from a headline and padding the result with
restatements of the same fact until it hits a bullet count. The second is that
the output format of automated news is also the output format of automated
disinformation, and building the photoreal version of this makes you a tooling
vendor for it.
What we built
A self-hosted Next.js application over Postgres and Prisma, with MapLibre for the
map, node-cron for scheduling, and a provider adapter for AI.
Facts are labelled and sourced. Each bullet is marked fact or attributed,
carries its source, a topic, a country and a map position. Ingest falls through
three body sources — the feed snippet, the article’s real paragraphs minus
boilerplate, then schema.org articleBody — in one request that also collects
the photograph. The prompt requires each bullet to carry information no other
bullet carries, and to return fewer rather than pad.
The presenter is deliberately not photoreal. It is a drawn figure, nobody in
particular, carrying a permanent non-dismissible “AI PRESENTER” mark, imitating
no real broadcaster’s branding. It lip-syncs from SpeechSynthesis boundary
events through a viseme set, gestures on emphasis scoring, and moves on damped
springs rather than linear interpolation — which is what stopped it reading as
robotic. It is fully deterministic: no Math.random, so the same script always
produces the same performance. Story pictures are never generated; each is
the outlet’s own photograph, credited on screen and linked back.
Nothing spends money or goes outward by itself. Reading is public; ingest,
broadcast, retell, edit and publish all require a token exchanged for a signed
httpOnly session. The scheduler builds bulletins but will not render audio,
because audio costs money — a ~2,100-character bulletin runs about $0.32, and it
waits for a human. Drafts never publish themselves. In webhook mode the app POSTs
approved posts to the operator’s own automation, so platform credentials never
live in this app; internal and plaintext URLs are refused. Every draft is
validated against its platform’s real limits — threaded on X and Mastodon,
truncated elsewhere, parked as rejected with a reason when it cannot be made
valid.
Capabilities this demonstrates
- AI & Automation — multi-provider adapter, keyless mock path, bounded spend, responsible synthetic media
- Secure Software Engineering — SSRF-bounded feed allowlist, token/session auth, rate limits, body caps, tenancy isolation

