Skip to content

Repository files navigation

title MediScan AI
emoji 🩺
colorFrom blue
colorTo purple
sdk docker
app_port 7860
pinned false
short_description AI-powered lab report analyzer β€” LangGraph + CrewAI + RAG

MediScan AI 🩺

AI-powered lab report analysis pipeline β€” Upload a blood test PDF or paste raw lab values, get a plain-English health report written by 6 AI agents, validated by a judge model, and downloadable as a PDF.

CI Python License


What It Does

Most people receive lab reports they can't understand. MediScan AI takes those reports and:

  1. Extracts every test value using a structured LLM extraction agent
  2. Enriches missing reference ranges from a WHO-sourced RAG database
  3. Calculates derived clinical metrics (eGFR, LDL, Non-HDL, VLDL, ratios)
  4. Researches abnormal values using live web search
  5. Writes a plain-English explanation using CrewAI multi-agent system
  6. Validates the output with a Qwen reasoning judge (loops back if quality is poor)
  7. Delivers a styled web report + downloadable PDF

System Architecture

User (text / PDF)
        β”‚
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  FastAPI Backend                          β”‚
β”‚                                                          β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ LangGraph Pipeline ───────────────┐  β”‚
β”‚   β”‚                                                   β”‚  β”‚
β”‚   β”‚  [1] Extractor Node  ──► [2] RAG Lookup Node      β”‚  β”‚
β”‚   β”‚        β”‚                       β”‚                  β”‚  β”‚
β”‚   β”‚        β–Ό                       β–Ό                  β”‚  β”‚
β”‚   β”‚  [3] Calculator Node ──► [4] Researcher Node      β”‚  β”‚
β”‚   β”‚                                β”‚                  β”‚  β”‚
β”‚   β”‚                                β–Ό                  β”‚  β”‚
β”‚   β”‚                     [5] CrewAI Node               β”‚  β”‚
β”‚   β”‚                       (2 AI agents)               β”‚  β”‚
β”‚   β”‚                                β”‚                  β”‚  β”‚
β”‚   β”‚                                β–Ό                  β”‚  β”‚
β”‚   β”‚                     [6] Judge Node (Qwen)         β”‚  β”‚
β”‚   β”‚                       pass ─────────► [7] Finalizeβ”‚  β”‚
β”‚   β”‚                       fail ◄──── retry (max 2)    β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                          β”‚
β”‚   /analyze/text   /analyze/pdf   /report/{id}            β”‚
β”‚   /download/{id}  /metrics       /health                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β–Ό
  Frontend (Vanilla JS + CSS)
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  β€’ Animated results rendering   β”‚
  β”‚  β€’ HIGH ↑ / LOW ↓ badges        β”‚
  β”‚  β€’ Calculated metrics cards     β”‚
  β”‚  β€’ PDF download (Arial TTF)     β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Tech Stack

Layer Technology Purpose
Orchestration LangGraph Stateful multi-agent pipeline with conditional retry loop
Agent Framework CrewAI Explainer + Report Architect agents (sequential)
LLM (Pipeline) Groq β€” llama-3.3-70b-versatile Extraction, Research, Judge (12K TPM pool)
LLM (Crew) Groq β€” llama-4-scout-17b-16e-instruct Report writing (30K TPM pool β€” separated to avoid rate limits)
Judge Groq β€” qwen/qwen3-32b Quality validation with pass/fail + feedback
RAG ChromaDB + all-MiniLM-L6-v2 WHO reference range lookup for missing test values
Web Search Tavily API Real-time context for abnormal lab values
PDF Extraction PyMuPDF (fitz) Extracts text from uploaded lab report PDFs
PDF Generation fpdf2 + Arial TTF Unicode-capable health report PDF output
API FastAPI + Uvicorn REST endpoints for analysis, reports, metrics
Frontend Vanilla HTML/CSS/JS No framework overhead β€” fast, no build step
CI/CD GitHub Actions + Render Unit tests on push, auto-deploy on main

Project Structure

UltimateAiProject/
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ main.py                  # FastAPI app + all endpoints
β”‚   β”œβ”€β”€ graph/
β”‚   β”‚   β”œβ”€β”€ graph.py             # LangGraph assembly + metrics logger
β”‚   β”‚   β”œβ”€β”€ nodes.py             # 6 agent nodes (extract, rag, calc, research, crew, judge, finalize)
β”‚   β”‚   └── state.py             # Shared state TypedDict
β”‚   β”œβ”€β”€ crew/
β”‚   β”‚   β”œβ”€β”€ agents.py            # CrewAI agent definitions (Llama4-Scout)
β”‚   β”‚   └── tasks.py             # CrewAI task definitions + run_crew()
β”‚   β”œβ”€β”€ tools/
β”‚   β”‚   β”œβ”€β”€ calculator.py        # Medical formulas (eGFR, LDL, Non-HDL, BMI, ratios)
β”‚   β”‚   └── search.py            # Tavily web search wrapper
β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   └── report_generator.py  # fpdf2 PDF generation (Arial TTF, Unicode-safe)
β”‚   └── ingest.py                # ChromaDB ingestion + retrieval
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ index.html               # Single-page app
β”‚   β”œβ”€β”€ style.css                # Dark theme + animations + badge styles
β”‚   └── script.js                # API calls + markdown rendering + badge injection
β”œβ”€β”€ documents/
β”‚   └── medical_ranges.txt       # WHO reference ranges corpus (RAG source)
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ test_calculator.py       # 8 unit tests β€” medical formula correctness
β”‚   └── test_pdf.py              # 8 unit tests β€” PDF generation + Unicode safety
β”œβ”€β”€ .github/workflows/ci.yml     # GitHub Actions CI (runs on push/PR)
β”œβ”€β”€ render.yaml                  # Render.com deployment config
β”œβ”€β”€ metrics.jsonl                # Per-request performance log (auto-generated)
β”œβ”€β”€ test_pipeline.py             # Integration test (requires live server)
└── requirements.txt

Setup & Run Locally

Prerequisites

1. Clone & Install

git clone https://github.com/Mahajan-Sachin/HealthReport.git
cd mediscan-ai

conda create -n langgraph_env python=3.11
conda activate langgraph_env
pip install -r requirements.txt

2. Configure Environment

Create a .env file in the project root:

GROQ_API_KEY=your_groq_api_key_here
TAVILY_API_KEY=your_tavily_api_key_here

GENERATOR_MODEL=meta-llama/llama-3.3-70b-versatile
JUDGE_MODEL=qwen/qwen3-32b
CREW_MODEL=groq/meta-llama/llama-4-scout-17b-16e-instruct

3. Build the RAG Database

python -c "from backend.ingest import ingest_documents; ingest_documents()"

4. Start the Server

python -m uvicorn backend.main:app --host 0.0.0.0 --port 8000 --reload

Open http://localhost:8000 in your browser.


API Endpoints

Method Endpoint Description
POST /analyze/text Analyze pasted lab report text
POST /analyze/pdf Upload and analyze a lab report PDF
GET /report/{report_id} Fetch full structured report JSON
GET /download/{report_id} Download report as PDF
GET /metrics View last 20 request performance metrics
GET /health Server health check

Example Request

curl -X POST http://localhost:8000/analyze/text \
  -H "Content-Type: application/json" \
  -d '{
    "report_text": "Hemoglobin: 9.2 g/dL [L]\nTotal Cholesterol: 238 mg/dL [H]",
    "patient_name": "Test Patient",
    "patient_age": 42,
    "patient_sex": "male"
  }'

Metrics & Observability

Every request is automatically logged to metrics.jsonl. View via:

GET /metrics
{
  "total_requests_logged": 5,
  "averages": { "total_seconds": 43.3, "tests_found": 14 },
  "requests": [{
    "timestamp": "2026-06-20T01:20:57",
    "total_seconds": 43.33,
    "node_timings": {
      "extract": 1.88,
      "rag": 0.02,
      "calculate": 0.0,
      "research": 13.95,
      "crew": 14.59,
      "judge": 12.88
    },
    "tests_found": 16,
    "abnormal_count": 14,
    "judge_iterations": 2,
    "status": "success"
  }]
}

Key insight: extract + rag + calculate = ~2s (4% of total time). research + crew + judge = ~41s (96%). The LLM nodes dominate β€” future optimization target is parallel execution of research and crew.


Running Tests

# Unit tests only (no API keys needed, runs in ~3 seconds)
python -m pytest tests/ -v

# Integration test (requires live server + real API keys)
python test_pipeline.py
Test Suite Tests What It Covers
test_calculator.py 8 eGFR formula, Friedewald LDL, Non-HDL, BUN ratio, edge cases
test_pdf.py 8 PDF generation, Unicode safety, markdown stripping

CI/CD

  • CI: GitHub Actions runs all unit tests on every push to main/dev and on PRs
  • CD: Render auto-deploys on every merge to main
Push to main
    β”‚
    β”œβ”€β”€ GitHub Actions CI
    β”‚     └── python -m pytest tests/ -v   ← must pass
    β”‚
    └── Render Auto-Deploy
          └── pip install + uvicorn start

Deploy to Render

  1. Push this repo to GitHub
  2. Go to render.com β†’ New Web Service β†’ Connect repo
  3. Add secrets in Render dashboard: GROQ_API_KEY, TAVILY_API_KEY
  4. Deploy β€” render.yaml handles the rest

Design Decisions

Why two separate Groq models? Groq enforces TPM limits per model. Using llama-3.3-70b (12K TPM) for LangGraph nodes and llama-4-scout-17b (30K TPM) for CrewAI separates the workloads across two independent rate limit pools, preventing one from starving the other.

Why no LLM output caching? Lab report values change between visits β€” the same patient with the same name/age could have completely different results after an illness. Caching on patient identity would return stale analysis. The only valid cache is the RAG reference range data (ChromaDB), which doesn't change per-request.

Why Vanilla JS (no React/Next.js)? No build step. No bundler. The frontend is served as static files by FastAPI. Any change to script.js or style.css is live immediately β€” ideal for rapid iteration on a single-page tool.


Limitations

  • Rate limits: Groq free tier limits throughput. Concurrent users will queue at the API level.
  • PDF scans: Scanned/image-based PDFs are not supported (only text-extractable PDFs). OCR (Tesseract) not yet integrated.
  • In-memory report store: Reports are lost on server restart. Acceptable for a public demo tool β€” would need Redis/SQLite for persistent doctor-facing use.
  • Arial font: PDF generation requires Arial TTF (available on Windows). Linux deployments fall back to ASCII-safe mode.

License

MIT β€” free to use, modify, and deploy.


Built with LangGraph + CrewAI + Groq + FastAPI

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages