Skip to content

jinan-kordab/piste

Repository files navigation

Piste β€” AI Fact-Checking Pipeline

video.mp4

Piste (French for "trail") β€” every claim leaves a complete, replayable forensic audit trail.

A multilingual fact-checking platform that combines LLMs, blind web retrieval, and an append-only audit ledger. Built with DSPy, FastAPI, PostgreSQL, Redis, and vanilla JavaScript.


Why Piste?

Most fact-checking tools search with the claim itself β€” baking in confirmation bias. Piste is different:

  • πŸ•ΆοΈ Blind by design β€” the retrieval engine never sees the original claim. No confirmation bias. Period.
  • πŸ”’ Immutable audit trail β€” every LLM call, every source, every vote is INSERT-only. Replay any verdict.
  • πŸ‡¨πŸ‡¦ Built for Canada & QuΓ©bec β€” bilingual EN/FR pipeline pre-configured for federal + provincial political discourse.
  • βš™οΈ Configurable β€” currently tuned for political fact-checking, but the pipeline accepts any domain. Swap the search domains and criticality keywords, and you're checking science, health, or finance claims.

Architecture

Designed and implemented by Jinan Kordab, 2026.

The pipeline runs in four stages, each leaving an immutable record:

Claim β†’ Stage 1 (Check-Worthiness + Atomic Decomposition)
     β†’ Stage 2 (Blind Web Retrieval β€” Tavily + Serper + Google CSE)
     β†’ Stage 3 (Per-Source Classification β€” asyncio parallel)
     β†’ Stage 4 (Verdict Aggregation β€” 7-way PolitiFact scale)
     β†’ Append-Only Audit Ledger (PostgreSQL)

Key architectural properties:

  • Blind retrieval β€” Stage 2 never sees the original claim. Prevents confirmation bias at the architecture level.
  • Immutable audit trail β€” Every LLM call, every source, every classification is INSERT-only. Replay any historical run.
  • Multi-provider search β€” Tavily (AI search) + Serper (Google proxy) aggregated concurrently with graceful fallback.
  • Bilingual β€” Full EN/FR support across UI, pipeline stages, verdict labels, and LLM-generated explanations.
flowchart LR
    A[Claim] --> B[Stage 1<br/>Check-Worthiness]
    B --> C[Stage 2<br/>Blind Retrieval]
    C --> D[Stage 3<br/>Classification]
    D --> E[Stage 4<br/>Verdict]
    E --> F[(Audit Ledger)]
Loading

View full architecture β†’


Screenshots

Claim verdict β€” French (QuΓ©bec political fact-checking):

FR Verdict

Replay & Audit β€” comparing pipeline versions:

FR Replay


Quick Start

Prerequisites

1. Clone and configure

git clone https://github.com/YOUR_USERNAME/piste.git
cd piste
cp .env.example .env

Edit .env and add your API keys:

  • DEEPSEEK_API_KEY β€” required (LLM)
  • TAVILY_API_KEY or SERPER_API_KEY β€” at least one required (web search)

2. Start the backend

docker compose -f docker/docker-compose.yml up -d

This starts three containers:

  • PostgreSQL 16 β€” append-only audit ledger (port 5432)
  • Redis 7.2 β€” idempotency guard + verdict cache (port 6379)
  • FastAPI backend β€” pipeline + API (port 8000)

The backend automatically runs alembic upgrade head on startup, so the schema is provisioned on first boot. If you ever need to apply migrations manually (e.g. after editing a revision), run:

docker compose -f docker/docker-compose.yml exec backend alembic upgrade head

Verify:

curl http://localhost:8000/health
# {"status":"ok","version":"0.1.0"}

3. Start the frontend

cd frontend
python -m http.server 3000

Open http://localhost:3000 β€” the entire UI is a single index.html file. No build step, no npm, no node_modules.

4. Submit a claim

Type a claim in the textarea (English or French) and click Fact-Check Claim. The pipeline runs in ~40 seconds β€” watch the SSE progress bar as it moves through each stage.


API Keys Required

Key Where to get it Required?
DEEPSEEK_API_KEY https://platform.deepseek.com/api_keys βœ… Required
TAVILY_API_KEY https://app.tavily.com/home ⚠️ One search provider required
SERPER_API_KEY https://serper.dev/ ⚠️ One search provider required
GOOGLE_CSE_API_KEY + GOOGLE_CSE_ID https://console.cloud.google.com/apis/library/customsearch.googleapis.com Optional fallback

Minimum setup: DeepSeek + either Tavily or Serper. Without these, the pipeline cannot function.


Project Structure

piste/
β”œβ”€β”€ README.md
β”œβ”€β”€ LICENSE                    # MIT License
β”œβ”€β”€ FINAL.mermaid              # Architecture diagram
β”œβ”€β”€ .gitignore
β”œβ”€β”€ .dockerignore
β”œβ”€β”€ .env.example               # Template β€” copy to .env
β”œβ”€β”€ docker/
β”‚   β”œβ”€β”€ docker-compose.yml     # PostgreSQL + Redis + Backend + Frontend
β”‚   β”œβ”€β”€ Dockerfile.backend
β”‚   └── Dockerfile.frontend
β”œβ”€β”€ frontend/
β”‚   └── index.html             # Single-page vanilla JS UI
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ requirements.txt
β”‚   β”œβ”€β”€ alembic.ini
β”‚   β”œβ”€β”€ alembic/               # Database migrations
β”‚   └── app/
β”‚       β”œβ”€β”€ main.py            # FastAPI entry point
β”‚       β”œβ”€β”€ api/               # REST endpoints (claims, verdicts, audit, replay, etc.)
β”‚       β”œβ”€β”€ core/              # Config, middleware, debug logging
β”‚       β”œβ”€β”€ db/                # SQLAlchemy models, session, base
β”‚       β”œβ”€β”€ models/            # Pydantic schemas
β”‚       └── services/          # Pipeline service, SSE, caching, observability
└── pipeline/
    β”œβ”€β”€ compiler.py            # DSPy configuration + compiler
    β”œβ”€β”€ replay_engine.py       # Replay historical claims
    β”œβ”€β”€ stage1/                # Check-worthiness + atomic decomposition
    β”œβ”€β”€ stage2/                # Blind web retrieval (multi-provider)
    β”œβ”€β”€ stage3/                # Per-source classification
    β”œβ”€β”€ stage4/                # Verdict aggregation + criticality gate
    β”œβ”€β”€ signatures/            # DSPy typed signatures
    β”œβ”€β”€ offline/               # VERIFAID offline dataset pipeline
    └── replay.py              # Replay utility

How It Works

Stage 1 β€” Claim Processing

  • 1a: Check-Worthiness β€” 3-vote LLM consensus classifies the claim as CFC (Check-worthy Factual Claim), UFC (Unimportant), or NFC (Non-Factual). Non-factual claims stop here.
  • 1b: Atomic Decomposition β€” Breaks compound claims into independent sub-claims. "Poilievre plans to abolish foreign aid and cut taxes" β†’ two separate verifiable claims.

Stage 2 β€” Blind Retrieval

  • 2a: Search Decision β€” LLM decides if web search is needed and generates neutral queries. The retriever NEVER sees the original claim.
  • 2b: Web Search β€” Queries run concurrently across Tavily, Serper, and Google CSE. Results are merged and deduplicated by URL. French claims get French-language sources.

Stage 3 β€” Per-Source Classification

Each source is independently classified as SUPPORTS, REFUTES, or UNRELATED to the claim. Classifications run in parallel via asyncio.gather. This prevents cross-contamination β€” one source's rating doesn't influence another's.

Stage 4 β€” Verdict Aggregation

  • 4a: Criticality Gate β€” High-stakes claims are flagged for human review.
  • 4b: Verdict Aggregator β€” Synthesizes all classifications into a 7-way PolitiFact-aligned verdict (True β†’ Pants on Fire) with a probability distribution and natural-language explanation.

Audit & Replay

Every pipeline run leaves an immutable forensic trail in PostgreSQL. Click Audit Trail to see every stage's input/output snapshots, every source retrieved, and every classification decision. Click Replay to re-run the claim through the current pipeline and see a side-by-side comparison.


Tech Stack

Layer Technology
LLM Framework DSPy 2.6 over LiteLLM
Model DeepSeek (deepseek-chat)
Backend FastAPI 0.115 + Uvicorn
Database PostgreSQL 16 (append-only audit ledger)
Cache Redis 7.2 (idempotency + verdict cache)
Search Tavily + Serper + Google CSE (aggregated)
Frontend Single-file vanilla JS, served by Python http.server
Containerization Docker Compose (3 services)

License

MIT License. See LICENSE.

Copyright (c) 2026 Jinan Kordab.


Piste β€” every verdict leaves a trail.

About

Multilingual AI fact-checking platform. Blind retrieval prevents confirmation bias; every verdict leaves an immutable forensic audit trail. DSPy + FastAPI + PostgreSQL + Redis.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors