Evidence before belief.
Jachai is a Bangladesh-first rumor scanner for verifying text claims and news photocards. It searches the live web, evaluates source quality and independence, and returns an inspectable evidence report instead of an unsupported AI answer.
The interface is English, while the verification engine can investigate both English and Bengali claims and sources.
Download the full-resolution architecture PDF
The pipeline is designed around three principles:
- Retrieve before reasoning — conclusions must be connected to attributable URLs.
- Audit deterministically — source tiers, reachability, dates, entities, and publisher independence are checked in code.
- Escalate only when necessary — cached and routine claims stay inexpensive; weak, sensitive, or conflicting evidence receives another research pass.
| Stage | What happens |
|---|---|
| Input | Accepts one text claim or a JPG, PNG, or WebP photocard up to 10 MB. Images can also be pasted from the clipboard. |
| Cache | Checks exact claims, strict semantic matches, and perceptual image fingerprints. A cache hit uses no model call. |
| Intake | Detects language, enforces a single factual claim, and runs local Tesseract OCR for images. |
| Retrieval | Searches known fact-checks, configured search providers, Gemini Search when available, and Google News RSS as a fallback. |
| Classification | The active LLM converts the retrieved material into structured, claim-specific evidence. |
| Audit | Validates URLs and grades relevance, provenance, independence, entity match, and date match. |
| Decision | Requires a relevant Tier A source or multiple independent Tier B sources for a decisive verdict. |
| Report | Returns the verdict, confidence, limitations, source tiers, and clickable evidence links. |
Jachai returns one of four evidence states:
supported— qualifying evidence directly supports the claim.contradicted— qualifying evidence directly contradicts the same claim and event.mixed— reliable sources conflict or support different parts of the claim.insufficient_evidence— the available evidence is not strong enough to decide.
Missing evidence is never treated as proof that a claim is false.
| Tier | Meaning | Examples |
|---|---|---|
| A | Primary evidence | Official notices, court records, government data, original documents, direct statements |
| B | Established reporting | Independent newsrooms with editorial standards, dates, bylines, and attributable evidence |
| C | Context only | Blogs, aggregators, social posts, or sources with limited provenance |
Tier C evidence can provide context but cannot determine a verdict by itself.
- API: FastAPI with asynchronous verification jobs
- Progress: Server-sent events
- Frontend: Responsive HTML, CSS, and vanilla JavaScript
- Models: OpenRouter or Google Gemini
- Retrieval: Google Fact Check, Tavily, Brave, Gemini Search, and Google News RSS
- OCR: Local Tesseract with optional Google Cloud Vision fallback
- Caching: In-memory locally; Redis for shared production jobs and cache
- Validation: Pydantic schemas and deterministic source auditing
Requirements:
- Python 3.11 or newer
- Tesseract with English and Bengali language data for local photocard OCR
- An OpenRouter or Gemini API key
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
cp .env.example .envConfigure one model provider in .env.
OPENROUTER_API_KEY=your_key_here
LLM_PROVIDER=openrouter
OPENROUTER_MODEL=openrouter/freeFree OpenRouter models are useful for development and demonstrations, but their availability, latency, model selection, and daily rate limits can vary. Use a specific paid model for predictable production behavior.
GEMINI_API_KEY=your_key_here
LLM_PROVIDER=gemini
INTAKE_MODEL=gemini-2.5-flash-lite
RESEARCH_MODEL=gemini-2.5-flash
CLASSIFICATION_MODEL=gemini-2.5-flash-lite
ESCALATION_MODEL=gemini-3.6-flashStart the application:
./start.shOpen http://localhost:8000.
| Variable | Default | Purpose |
|---|---|---|
LLM_PROVIDER |
auto |
Selects openrouter, gemini, or the first configured provider. |
OPENROUTER_MODEL |
openrouter/free |
OpenRouter model or router slug. |
SEARCH_PROVIDER |
auto |
Prefers Tavily, then Brave, then native Gemini Search, then RSS fallback. |
FACT_CHECK_API_KEY |
empty | Enables Google Fact Check lookup before general research. |
TAVILY_API_KEY |
empty | Enables Tavily news search. |
BRAVE_SEARCH_API_KEY |
empty | Enables Brave web search. |
VISION_API_KEY |
empty | Enables Cloud Vision when local OCR is insufficient. |
ENABLE_IMAGE_WEB_DETECTION |
false |
Enables paid visual-match discovery during escalation. |
ENABLE_QUALITY_ESCALATION |
true |
Runs a second research pass for uncertain or high-risk claims. |
RESULT_CACHE_TTL_SECONDS |
86400 |
Keeps verification results for 24 hours. |
SEMANTIC_CACHE_THRESHOLD |
0.92 |
Controls strict semantic cache reuse. |
MAX_CLAIMS_PER_VERIFICATION |
1 |
Prevents one submission from multiplying model and search calls. |
RATE_LIMIT_PER_HOUR |
10 |
Per-client verification limit. |
REDIS_URL |
empty | Enables shared production jobs and cache. |
See .env.example for the full configuration template. Never
commit .env or production API keys.
Create a text verification:
curl -X POST http://localhost:8000/api/v1/verifications \
-H "Content-Type: application/json" \
-d '{"text":"The government has announced a nationwide public holiday tomorrow."}'Create a photocard verification:
curl -X POST http://localhost:8000/api/v1/verifications \
-F "file=@photocard.jpg"The API responds with 202 Accepted and provides URLs for job status, live SSE
progress, and the final report. A running job can be cancelled with:
DELETE /api/v1/verifications/{request_id}
Completed jobs expire according to JOB_TTL_SECONDS.
Run the automated suite:
PYTHONPATH=backend .venv/bin/pytest -qThe tests cover evidence decisions, URL normalization, API validation, cache safety, image fingerprints, OCR quality gates, single-claim enforcement, and the crucial no-evidence behavior.
For quality benchmarking, prepare a JSONL dataset with claim,
expected_status, and optional required_domains, then run:
PYTHONPATH=backend .venv/bin/python scripts/evaluate_pipeline.py benchmark.jsonlThe evaluator reports verdict accuracy, source recall, latency, and individual case failures. Use human-reviewed claims rather than synthetic ground truth.
To regenerate the architecture image:
PYTHONPATH=backend .venv/bin/python scripts/render_system_graph.pyrender.yaml defines a Docker web service and managed Redis.
Before deployment:
- Add model and optional search keys as secret environment variables.
- Set
ALLOWED_ORIGINSto the deployed HTTPS origin. - Set
OPENROUTER_SITE_URLto the public application URL when using OpenRouter. - Keep image web detection disabled unless its additional cost is intentional.
- Monitor provider usage, cache-hit rate, latency, and insufficient-evidence rate.
The Docker image includes English and Bengali Tesseract language data for the zero-cost OCR path.
Jachai reports the strength of available evidence; it does not declare absolute truth. Important political, legal, medical, financial, or safety decisions should always be checked against the original primary sources and qualified experts.
