Back to all projects
Live·Deployed on Vercel

MediScribe: AI Clinical Documentation Assistant

Turns typed or dictated consultation notes into structured medical summaries, action items, and patient-ready letters, in 19 languages, streamed live as they generate.

LLMWhisper ASRMultilingual NLPSaaS

The Dockerized AWS App Runner deployment is intentionally kept offline to avoid ongoing cloud costs. The live demo above runs on the Vercel deployment instead.

Technical Deep Dive
Bearer JWTstream
Browser
Next.js UI + MediaRecorder
Clerk
JWT + subscription gate
FastAPI Backend
consultation / transcribe / translate
GPT-4o-mini
summary + translation (SSE)
Whisper
audio to text
Core serviceThird-party APIData storeClient / UI
For the full detail beyond what fits here, these are standalone interactive diagrams (they open in a new tab, sized for a wide screen):

Architecture

Three API routes carry the product: `/api/consultation` streams a clinical summary, action items, and a patient letter from one consultation note; `/api/transcribe` runs audio dictation through Whisper; `/api/translate` streams the patient letter into any of 19 languages. All three stream their output token-by-token over SSE rather than waiting for a full response.

Every route requires a valid Clerk JWT in the `Authorization` header, verified against Clerk's JWKS, and Clerk also gates access by subscription plan (`Protect plan="premium_subscription"`); this is built as a billable SaaS product, not just an authenticated demo.

The app ships two deployment topologies with full feature parity: on Vercel, a serverless FastAPI function handles all three routes (rewritten via `vercel.json` so `/api`, `/api/transcribe`, and `/api/translate` all resolve to one handler); on AWS, Next.js is exported as static files and served from inside the same FastAPI process as the API routes, so the Docker/App Runner path is a single self-contained container with the identical three endpoints.

  • Whisper handles audio-to-text so dictation and typed notes share the same downstream summary pipeline
  • Translation is generated natively per-language rather than templated, so clinical tone holds up across all 19 supported languages instead of reading like a literal translation
  • No note content is persisted: text goes to OpenAI for generation and nothing is written to a database, by design

Design Decisions

  • Split deployment targets deliberately: Vercel for fast iteration, and a Dockerized FastAPI + AWS App Runner path (min/max instances pinned to 1) for a more traditional always-on deployment sized to run at roughly $5–10/month
  • Collapsed the AWS path to one container specifically to keep the App Runner deployment simple: Next.js is pre-built to static assets at image-build time rather than run as its own Node server, so there's a single process and a single health check to manage
  • Treated patient-data handling as a first-class constraint from the start: subscription gating and JWT verification sit in front of every route, ahead of a formal compliance pass
  • Streams every generated response token-by-token over SSE rather than returning one blocking response, so the app feels responsive even though a full summary takes a few seconds to complete

Problems & Challenges

  • Cross-platform Docker builds needed the explicit `--platform linux/amd64` flag for the AWS path, since a build done natively on Apple Silicon otherwise targets the wrong architecture for App Runner
  • Keeping multilingual output consistent in tone across languages with very different clinical/formal registers (the app supports languages from French and Mandarin to Farsi and Tagalog) rather than optimizing only for English quality
  • Diagnosing an App Runner autoscaling misconfiguration that took a full day to isolate, ultimately traced to autoscaling-config values rather than the application code

Limitations & Improvements

  • Built and explicitly documented as a demonstration, not a certified medical device: a real clinical deployment would need HIPAA-grade controls, audit logging, role-based access control, and formal patient-consent management, none of which exist yet
  • CORS on the AWS path is currently permissive (`allow_origins=["*"]`); scoping this to specific origins is a planned hardening step before wider use
  • No persistence layer means there's no history or resumability across sessions today: adding an opt-in, encrypted store would be the natural next step if the product needed continuity between visits
Stack
Next.js (Pages Router)FastAPIGPT-4o-miniWhisperClerk AuthDockerVercelAWS App Runner