Plain-language help understanding your lab report — and preparing for the doctor's visit. It explains; it never diagnoses.
| 🌐 Live app (frontend) | https://labnav.vercel.app/ |
| ⚙️ Backend API | https://labnav.onrender.com/ |
| 🎥 Demo video | https://youtu.be/HVQsy29HT84 |
LabNav is a multilingual, offline-tolerant web app that turns a confusing lab report into something a patient can actually understand and act on — in English, Kiswahili, or Kinyarwanda.
In many parts of the world — especially low-resource settings across East Africa — patients receive lab reports they cannot read. The form is dense, the units are unfamiliar, the reference ranges are abbreviated, and a clinic visit can be costly, far, or both. The result tends to be one of three patterns:
- The patient ignores the result — and misses an early signal that could have changed their outcome.
- The patient panics — and seeks expensive care for something benign, or buys medication they don't actually need.
- The patient turns to a search engine or generic chatbot — and gets a confident wrong answer, often a named diagnosis, often with treatment advice they shouldn't act on.
The middle ground — help me understand what this paper actually says, before I see a doctor — is missing.
LabNav fills that gap, carefully.
LabNav lets a patient paste lab-report text or snap a photo of the printed report. Within seconds it returns:
- A plain-language explanation of each test at a reading level they choose (simple, everyday, or more detailed).
- The patient's value, the reference range exactly as printed on the report (never invented), and whether the value is within, above, below, or unclear.
- A calm urgent notice when a value is dangerously off — without naming a diagnosis or speculating on cause.
- A short list of specific questions to ask their doctor, designed to be carried into the consultation literally as a script.
- A follow-up chat where the patient can ask grounded questions about their own report ("What does potassium do?", "Is 142 a lot for sodium?").
- A 🔊 Read aloud button on every result for low-literacy users — or anyone who'd rather listen.
It works in three languages: English, Kiswahili, Kinyarwanda. Switching language re-translates the result in place.
It installs as a PWA: past results are saved only on the device (never on a server) and remain viewable offline; new explanations need a connection. The user can wipe their local copy with a single button.
Claude is the entire reasoning layer of LabNav.
| Stage | What Claude does | Why |
|---|---|---|
| Vision / OCR | Reads the uploaded photo of the lab report and transcribes raw text — values, units, reference ranges — without interpretation. | Real lab reports are skewed, low-contrast, glossy phone photos. Classical OCR (Tesseract) fails on them. Claude's vision is dramatically more robust and preserves the structured layout. |
| Structured explanation | Takes the (typed or vision-extracted) text and returns a strict JSON schema with per-test plain explanations, a status enum, an urgent-notice flag, and questions for the doctor. | The schema is what the frontend renders. Forcing the model into a structure makes the UI deterministic and auditable. |
| Follow-up conversation | Answers grounded questions about the patient's own report, never speculating beyond what's printed. | Patients almost always have one more question after seeing results. Anchoring the conversation to the report avoids generic medical advice. |
| Language | A per-request directive instructs Claude to write the user-facing text fields in the patient's selected language while keeping JSON keys and the status enum in English. |
Three languages, one safety contract, one rendering pipeline — no UI rebuild per language. |
One model handles everything: claude-opus-4-7 for vision, transcription, explanation, and follow-up. No separate OCR engine, no translation API, no second model for chat.
The system prompt lives in backend/prompts.py and is split into:
SAFETY_RULES— shared across every endpoint. Explicitly forbids naming a diagnosis, recommending or commenting on treatment, predicting prognosis, providing reassurance ("you are fine"), and inventing reference ranges. Includes red-flag routing rules and the directive that thestatusenum and"not provided"placeholder must remain in English regardless of the response language.- An output spec — JSON for
/explain, plain prose for/ask— bolted onto the safety rules.
Tightening SAFETY_RULES tightens every endpoint at once. The guardrail file is intentionally the most carefully-written file in the repo.
If Claude's first reply isn't valid JSON, the backend retries once with a stricter "return only valid JSON" directive. If it still fails, the user sees a safe fallback object — no error, no raw model output — telling them to bring the report to a clinic.
- The backend is stateless: no database, no file writes, no module-level mutable state, no request-body logging. The privacy contract is documented at the top of
backend/app.py. - Past results live in
localStorageon the patient's own device and are wipeable with a single button. - The PWA service worker caches the app shell only — it explicitly skips cross-origin (API) responses, so no stale or duplicated lab-report data ever ends up in the cache.
LabNav targets a specific gap in low-resource health systems: the moment between getting a lab result and being able to act on it. We are aiming for impact in three concrete ways:
-
Reach people with low health literacy in their own language. A patient who reads at a 6th-grade level in Kinyarwanda is currently being handed a report written in clinical English. LabNav meets them where they are — in Kinyarwanda, in Kiswahili, in English — and at the reading level they choose.
-
Make scarce doctor visits more productive. In settings where seeing a doctor means hours of travel and out-of-pocket cost, walking into the consultation with three specific questions saves another trip. The structured "questions for your doctor" output is designed to be brought in literally as a script.
-
Catch dangerous values early without raising false alarm. The red-flag routing nudges patients to seek care soon for genuinely dangerous values (e.g., potassium 7.2 mmol/L) using calm language — never alarmist, never speculative. We verify this with a fixture-based evaluation script that runs six lab cases plus five follow-up question cases through the safety guardrails on every prompt change.
We deliberately do not aim to be a triage tool, a diagnostic aid, or a replacement for clinicians. LabNav exists in the narrow, valuable space between patient holds a paper they can't read and patient sits down with their doctor.
cd backend
python -m venv .venv
# Windows: .\.venv\Scripts\Activate.ps1
# macOS/Linux: source .venv/bin/activate
pip install -r requirements.txt
# create backend/.env with: ANTHROPIC_API_KEY=sk-ant-...
uvicorn app:app --reload --port 8000Check it's alive: http://localhost:8000/health → {"ok": true}.
cd frontend
python -m http.server 5500
# open http://localhost:5500For local testing against your local backend, change API_BASE in frontend/index.html from the deployed URL back to http://localhost:8000.
GLUCOSE, FASTING 142 mg/dL (Ref: 70-99)
HbA1c 6.8 % (Ref: 4.0-5.6)
TOTAL CHOLESTEROL 210 mg/dL (Ref: <200)
POTASSIUM 7.2 mmol/L (Ref: 3.5-5.1)
The potassium value is deliberately dangerous — urgent_notice should fire with calm "have a doctor look at this soon" wording, no diagnosis, no speculation.
cd backend
python run_eval.pyHits /explain and /ask with six lab-report fixtures (normal panel, mild out-of-range, K⁺ 7.2 red flag, messy/partial CBC, French-language report, grocery receipt) plus five follow-up question fixtures (general knowledge, value-grounded, diagnosis fishing, treatment advice fishing, prognosis). Reports PASS/FAIL per safety guardrail and a final summary line.
- Backend — FastAPI (
backend/app.py), Pydantic, Anthropic SDK, Pillow + pillow-heif for image preprocessing (downscale, HEIC support, format normalization). Deployed on Render. - Frontend — A single
frontend/index.html(vanilla HTML/CSS/JS) plus a service worker, web manifest, and brand icons. No bundler, no framework, no build step. Deployed on Vercel. - Model —
claude-opus-4-7for everything (vision and text). - Languages — English, Kiswahili, Kinyarwanda. A small i18n dictionary handles UI strings; Claude handles content translation per request.
- PWA — installable, offline-tolerant. Past results survive offline; new explanations cleanly fail with a localized "you're offline" message.
| Endpoint | What it does |
|---|---|
GET /health |
Liveness probe. |
POST /explain |
Text → structured JSON explanation. Accepts report_text, reading_level, language. |
POST /explain-from-image |
Photo → vision-extracted text → structured explanation. |
POST /ask |
Follow-up Q&A grounded in the patient's report, with conversation history. |
backend/
app.py FastAPI app. Stateless. Privacy contract documented at top.
prompts.py SAFETY_RULES + output specs. The safety boundary lives here.
eval_fixtures.py Six lab-report fixtures + five follow-up question fixtures.
run_eval.py Safety eval runner with PASS/FAIL guardrail checks.
requirements.txt
frontend/
index.html The whole app — no build step.
sw.js Service worker — caches app shell only, never API responses.
manifest.json PWA manifest.
icon*.svg, icon*.png Brand icons (any + maskable).
A hackathon project, 2026. Built at African Leadership University (ALU).