All projects

Data storytelling · News analytics

Jakarta, 730 Hari

An AI-assisted data film about two years of Jakarta in the news.

Role
Author & developer
Year
2026
Status
Live · interactive data film
Scene 1: Jakarta as a map of news dots
  • 690,828news articles analysed
  • 102weeks, Nov 2024 to Oct 2026
  • 7scenes in the film
  • 8issues tracked

Overview

Why it exists, and what it does

The problem

News about a city arrives as thousands of separate stories. Almost no one can see what dominated, when attention rose and faded, or who was asked to answer for it.

The approach

A pipeline collects and cleans the news, removes duplicates, labels issues, tone and actors, and tests each claim statistically. A static film then tells the result in seven scenes, where every dot stands for about 1,200 articles.

Design principle

Coverage is not reality.

More flood stories do not prove more floods, and a missing week is not a quiet week. The film measures what the media covered, shows gaps as gaps, and labels every finding with how confident it is.

Findings

Two years, six findings.

Each finding is labelled with how confident it is, based on sample size and a statistical test.

  • High confidence21%

    of all Jakarta news in one week of March 2025 was about floods

    20× the normal share, and the highest peak of any issue in two years.

  • High confidence1 wk

    Media attention on floods halves within a week

    Five of the six major floods follow this pattern.

  • High confidence51%

    January 2026 was the darkest month

    The highest share of negative-toned articles in 24 months.

  • High confidence+46%

    Only public transport and crime grew convincingly

    Share of coverage in year 2 versus year 1. Crime grew by 23%.

  • Medium confidence4.3×

    Traffic stories are born from events at Monas and MRT works

    Traffic and public-space stories appear together 4.3× more often than expected.

  • Low confidence4.0×

    Foreign media write 4× more about pollution

    The foreign sample is small, so the direction is clear but the size is not.

What this does not claim

  • The film measures news coverage, not the city's actual condition.
  • Missing is not zero: two weeks in June 2025 are absent from the snapshot and shown as gaps.
  • “730 days” is the film's name for about two years; the data itself spans 102 weeks, from November 2024 to October 2026.
  • Topic, tone and entity labels are model output until checked against human-labelled examples.
  • International outlets are a small share of the sample.

Walkthrough

Don't just read about it. See each screen.

5 real screens from the film. Pick a tab to see what each one shows.

Scene 1 · Every dot is news screen
1/5 · Scene 1 · Every dot is news

Jakarta as a map of dots, one per roughly 1,200 articles, filling in week by week. Orange weeks lean negative and blue weeks lean positive, with a live ticker of incoming headlines.

Screenshots are from the built-in demo mode, which uses a fictional project.

How it works

From raw news to a tested story

  1. 1

    Collect and clean

    RSS feeds, sitemaps and responsible crawling, with GDELT as a supplement. Duplicates are removed on three levels, from identical URLs to the same event told by different outlets.

  2. 2

    Label and measure

    Every article gets issues, tone and the actors involved. Ambiguous cases go to a language model for review, then statistics test which patterns are real.

  3. 3

    Publish a snapshot

    Checked results become a versioned snapshot. The site only reads that file, so it never crawls or calls a model while you watch.

How the labels are made

Three levels of de-duplication

  1. Exact: SHA-256 hashes and canonical URLs.
  2. Near-duplicate: MinHash with LSH over five-word shingles and estimated Jaccard similarity.
  3. Shared event: multilingual-e5-base embeddings plus time, place and source context, to separate copies from independent coverage of one event.

Two-stage labelling

  1. Stage 1, local: GLiNER2 assigns issues, area relevance, sentiment and entities, with a confidence score and model version stored for every label.
  2. Stage 2, review: ambiguous or high-impact cases escalate to a language model that answers in a validated, logged format.
  3. Sentiment is scored per actor, so a resident's complaint and an official's reply in one story can differ.

Escalation triggers: a top issue score below 0.60, a gap under 0.15 between the top two, uncertain location, or a major story covered by 10+ outlets.

Architecture

Seven roles, one pipeline

Only some roles use a language model. The rest are deterministic or classic NLP, which keeps model calls and cost low.

  1. Scout
  2. Crawler
  3. Dedup
  4. Classifier LLM review for unclear cases
  5. Analyst
  6. Verifier
  7. Publisher
  • Discovery

    Scout

    Finds articles through RSS feeds, sitemaps and GDELT, strips tracking parameters and checks the queue before any fetch.

  • Rules + extraction

    Crawler

    Fetches within robots.txt, per-domain rate limits and paywall rules, then removes menus, ads and recommendations.

  • Hash + embeddings

    Dedup

    Separates duplicate copies from independent coverage of the same event.

  • NLP + LLM

    Classifier

    Runs GLiNER2 locally and escalates only the unclear or high-impact cases to a language model.

  • Statistics

    Analyst

    Issue share, surge detection, outlets per event, media half-life, co-occurrence and bootstrap intervals.

  • Quality gates

    Verifier

    Eight gates from source health to publishing. Failed extractions are flagged, never counted as zero.

  • Schema + review

    Publisher

    Validates the snapshot, opens a pull request for review, then ships it to the site.

Stack

Discovery
RSS · sitemaps · GDELT · httpx · Crawl4AI · Trafilatura
Orchestration
LangGraph · Prefect · Langfuse
Storage
PostgreSQL 16 with pgvector · Elasticsearch 8 · MinIO/S3
Models
GLiNER2 · multilingual-e5 embeddings · a structured LLM for escalations
Delivery
Pydantic validation · GitHub pull-request review · Next.js on Vercel

Quality & privacy

Built to be audited, and honest about its limits

Quality gates

  • Eight quality gates, from source health to publishing.
  • Every insight links back to article IDs; runs record stage counts, cost and model versions.
  • Missing weeks stay visible as gaps, and unsupported claims are not exported.
  • If the pipeline fails, the last published snapshot stays live.
  • Evaluation criteria were set up front: a 1,000-article human-labelled reference set. These are targets, not reported results.

Responsible data

  • Crawlers follow robots.txt and keep to one request every two seconds per domain.
  • Paywalls and access rules are respected, and public excerpts are kept short.
  • Raw HTML is kept for 180 days, and headlines stay credited to their publishers.
  • An independent personal project, not an official government service.

Want to watch it?

Press play, or step through the seven scenes yourself. Switch to EN for English.

Let's Connect

Let's build something meaningful together.

Let's connect to discuss how AI and innovation can drive real-world impact.

“AI and innovation for real-world impact.”