Live demo: https://vital-lens.pages.dev (direct: https://vitallens.space.zhipuaidemo.cn) Demo video (3:17, with subtitles): https://43aquarius.github.io/vital-lens/ (direct MP4: https://43aquarius.github.io/vital-lens/demo.mp4) Code: https://github.com/43aquarius/vital-lens One-pager (PDF): https://43aquarius.github.io/vital-lens/project-description.pdf · Full source as PDF: https://43aquarius.github.io/vital-lens/source-code.pdf
Inspiration
A family member handed me her latest blood test results. "Everything's normal," the portal said — yet three markers sat just below range, and the only explanation anyone offered was a shrug. She spent that evening spiraling through search engines, while the actually valuable information — how those markers had been drifting across her last three tests — stayed locked inside three separate PDFs that nobody had ever connected. VitalLens exists to close that gap between what labs measure and what patients understand.
What it does
VitalLens speaks blood-test fluently, in four modules:
- Lab Decoder — upload a photo or scan of a lab report. A vision-language model extracts every marker (value, unit, and the reference range printed on that specific report), then writes a plain-language briefing: what the report shows, what looks off, what to do next, and exactly what to ask your doctor.
- Health Timeline — every report lands on one timeline with per-marker trend charts and reference bands, so a slow drift becomes impossible to miss.
- Symptom Guide (Nurse V) — a triage-style conversation: describe symptoms, get structured follow-ups and calm guidance, with rule-based escalation when it matters.
- Doctor Prep — a one-tap appointment briefing: current values vs. ranges, deltas since last visit, and talking points.
How I built it
Three stages, deliberately ordered so that no safety call ever depends on a language model:
- Vision extraction — a GLM vision model (via z-ai-web-dev-sdk) reads the report image and returns strict JSON: patient, date, lab, and every marker with its printed reference range. If a range isn't printed on the report, it's filled from a built-in clinical reference table — never invented.
- Deterministic medical layer (src/lib/medical.ts) — 40+ markers with reference ranges, critical-value thresholds, status evaluation, and trend math, all in ordinary TypeScript.
- Language layer — an LLM turns the structured data into the briefing you read. Every red flag a user ever sees is computed by the rules engine; the model can explain a flag, but it can never create or hide one.
Stack: Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS 4 + shadcn/ui, Prisma + SQLite, recharts, framer-motion, react-markdown, z-ai-web-dev-sdk (GLM VLM + LLM).
Challenges I ran into
- Getting a vision model to return strict JSON with every numeric marker — no invented values, no dropped panels. Structured-output prompting plus a hard validation layer on top.
- Making trend charts honest: mixed markers with wildly different units on one screen, reference bands that clip axis domains, and only comparing like-for-like (same marker, same unit) for trend claims.
- Keeping the AI visibly out of the safety path — the hard part is architectural discipline, not model choice.
Accomplishments that I'm proud of
- One pass over a real lab-report photo: 16/16 markers extracted, 17 seconds end-to-end.
- A red-flag engine that fires deterministically — testable, provable, no prompt required.
- The seeded demo story: across three reports, hemoglobin 13.2 → 11.9 → 10.8 g/dL and ferritin 38 → 22 → 11 ng/mL. No single report is an emergency. The trend is the finding — and VitalLens says so out loud.
What I learned
- Structured-output prompting beats post-hoc parsing, every time.
- The most important AI decision in a health app is deciding what the AI is not allowed to do.
- Medical UX means plain words and numbers side by side — never one without the other.
What's next for VitalLens
PDF lab reports (not just images), multi-panel trending, clinician-shareable summaries, FHIR import, and i18n.
Built With
- ai
- framer-motion
- glm
- javascript
- next.js
- prisma
- react
- recharts
- shadcn-ui
- sqlite
- tailwind
- typescript
- vision-language-model


Log in or sign up for Devpost to join the conversation.