Pulse is a full-stack clinical decision-support demo for aortic and endovascular surgery. It reimagines the original CardioSurg-AI-Assistant (Streamlit + ChromaDB) on a modern production-grade stack: a Next.js 15 dashboard, a FastAPI intelligence service, a RAG pipeline over Quiver (the author's own vector DB), and a LangGraph multi-agent copilot powered by Groq.
The project exists to show what a senior-level, full-stack, AI-native clinical tool looks like when built with the right foundations — not as a clinical product.
| Before (prototype) | Pulse v1.0 |
|---|---|
| Streamlit chat | Next.js 15 dashboard — full clinical UI |
| ChromaDB | Quiver — author's own vector DB |
| Minimal LangGraph stub | Stateful multi-agent LangGraph graph |
| Random synthetic patients | 200 clinically-correlated synthetic patients |
| No clinical calculators | 6 validated calculators + IFU-fit engine |
| No auth | JWT + role-based access (4 roles) |
| No PDF | Medical-grade PDF report with AI narrative |
| No streaming | Token-by-token SSE streaming copilot |
Generated by
task screenshotsagainst the running seeded stack.
| Overview | Risk & Suitability | Notes | AI Summary |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
||
![]() |
![]() |
| RCRI form | RCRI result | NEWS2 result | GAS result |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
| Monitoring | Devices |
|---|---|
![]() |
![]() |
(generated on demand per patient — download via the AI Summary tab)
| Users | Audit Log |
|---|---|
![]() |
![]() |
200 synthetic aortic-surgery patients with: full anatomy (aortic dimensions, morphology), comorbidities, medications, labs, vitals timelines, clinical notes, attending physician, and current clinical phase (pre-op / intra-op / post-op).
All calculators are deterministic, unit-tested, and never approximated by the LLM:
| Calculator | Domain |
|---|---|
| RCRI | Cardiac risk for non-cardiac surgery |
| CHA₂DS₂-VASc | Stroke risk in atrial fibrillation |
| HAS-BLED | Bleeding risk in anticoagulation |
| NEWS2 | Early warning score — post-op deterioration |
| GAS | Glasgow Aneurysm Score — AAA operative risk |
| EuroSCORE II | Cardiac surgery operative mortality |
| IFU-fit engine | Device suitability for EVAR/TEVAR |
- Streaming SSE chat — token-by-token output via
ChatGroq.astream(), patient-context-aware - LangGraph multi-agent — stateful
StateGraphwithretrieve → generatenodes and Redis checkpoints - RAG over Quiver — hybrid dense search across two collections (guidelines + literature), with cross-encoder reranking (
ms-marco-MiniLM-L-6-v2) - Source citations — every response names the guidelines and papers it drew on
- Guardrails — mandatory disclaimer on every response, out-of-scope refusal
Triggered per-patient, the LangGraph pipeline builds a structured clinical narrative from the patient record and knowledge base, rendered as:
- An inline summary card in the dashboard
- A downloadable medical-grade PDF: indigo header band with Pulse logo, patient info table, AI narrative, colour-coded risk scores, cited sources, and confidentiality footer
Vitals time-series charts with NEWS2 colour bands, alert thresholds, and AI-generated deterioration flags.
Browse and filter all 13 guidelines and literature entries indexed in Quiver. Filterable by type, section, and title.
EVAR/TEVAR device specifications with IFU fit assessment per patient anatomy.
User management (CRUD, role assignment), audit log viewer.
flowchart LR
U[Clinician] -->|HTTPS| W["web · Next.js 15\nApp Router · TypeScript\nTailwind · shadcn/ui"]
W -->|REST + SSE| A["api · FastAPI · Python 3.12\nSQLAlchemy 2 async · Alembic"]
A -->|SQL| P[(Postgres 16)]
A -->|vector search| Q[("Quiver\nvector DB")]
A -->|cache · checkpoints| R[(Redis)]
A -->|LLM inference| G["Groq\nllama-3.3-70b-versatile"]
subgraph AI ["FastAPI · AI plane"]
LG["LangGraph StateGraph\nretrieve → generate"]
RAG["Quiver hybrid search\n+ cross-encoder rerank"]
CALC["Clinical calculators\n(deterministic)"]
PDF["ReportLab PDF\ngenerator"]
end
A --- AI
LG --> RAG --> Q
Five services in docker-compose.yml:
- web — Next.js 15 (App Router, RSC, Server Actions)
- api — FastAPI, async SQLAlchemy, LangGraph, Quiver client
- db — Postgres 16
- quiver — Quiver vector DB (author's own project)
- redis — session checkpoints, rate-limit counters
See docs/architecture.md and the ADRs for decision rationale.
git clone https://github.com/achref-soua/pulse.git
cd pulse
cp .env.example .env
# Optional — add your Groq key for AI features (app runs without it, AI routes return 503):
# GROQ_API_KEY=gsk_...
task up # docker compose up -d --build --wait
task migrate # run Alembic migrations
task seed # populate Postgres + Quiver (≈30 s)Open http://localhost:3000 and sign in:
| Role | Password | |
|---|---|---|
| Surgeon | surgeon@demo.pulse |
demo-surgeon-2024 |
| Anesthetist | anesthetist@demo.pulse |
demo-anesthetist-2024 |
| Nurse | nurse@demo.pulse |
demo-nurse-2024 |
| Admin | admin@demo.pulse |
demo-admin-2024 |
# Install
pnpm install # web + monorepo packages
cd apps/api && uv sync && cd ../.. # Python deps
# Dev servers
pnpm --filter web dev # http://localhost:3000
cd apps/api && uv run uvicorn app.main:app --reload --port 8000
# Tests
task test # all: vitest + pytest
task test:api # pytest (apps/api)
task test:web # vitest (apps/web)
task e2e # Playwright E2E (requires running stack)
# Lint & type-check
task lint # ruff + eslint
task type-check # pyright + tsc
# Screenshots (requires running seeded stack)
BASE_URL=http://localhost:3000 task screenshots
# Wipe and reseed
task reset # docker compose down -v && task up && task migrate && task seed| Variable | Default | Required | Description |
|---|---|---|---|
DATABASE_URL |
postgresql+asyncpg://pulse:pulse@db:5432/pulse |
Yes | Async SQLAlchemy DSN |
QUIVER_URL |
http://quiver:8080 |
Yes | Quiver server base URL |
QUIVER_API_KEY |
dev-quiver-key-change-me |
Yes | Quiver API key |
REDIS_URL |
redis://redis:6379/0 |
Yes | Redis connection URL |
JWT_SECRET |
— | Yes | JWT signing secret (≥ 32 chars) |
GROQ_API_KEY |
— | AI features | Groq API key — leave blank to disable AI routes |
GROQ_MODEL |
llama-3.3-70b-versatile |
No | Primary generation model |
GROQ_ROUTER_MODEL |
llama-3.1-8b-instant |
No | Fast router / intent model |
EMBEDDING_MODEL |
BAAI/bge-small-en-v1.5 |
No | Sentence-transformer embedding model |
RERANK_ENABLED |
true |
No | Enable cross-encoder reranking of RAG candidates |
ENVIRONMENT |
development |
No | development | production |
Full list with comments in .env.example.
All calculators are deterministic, unit-tested against published score definitions, and never delegated to the LLM. See docs/clinical/REFERENCES.md for every cited paper and guideline.
| ADR | Decision |
|---|---|
| 0001 | Next.js 15 + FastAPI + Quiver + LangGraph + Groq |
| 0002 | Quiver over ChromaDB / pgvector / Qdrant |
| 0003 | LangGraph StateGraph for patient summary |
| 0004 | AGPL-3.0 |
| 0005 | Direct ChatGroq.astream() for SSE chat |
| 0006 | bge-small-en-v1.5 embeddings + cross-encoder rerank |
| 0007 | ReportLab for PDF report generation |
| 0008 | JWT via Authorization: Bearer header only |
docker compose up -d --build is the primary deployment target. The compose file includes named volumes for Postgres data and the Quiver index. See docs/architecture.md for service boundaries, health-check configuration, and resource guidance.
AGPL-3.0 — © 2024–2026 Achref Soua
Pulse is an educational demonstration on fully synthetic patient data. It is not a medical device, does not constitute medical advice, and must not be used for clinical decision-making on real patients.



















