What Inspired Me

I got a medical bill last year and genuinely had no idea what I was paying for. Line items like "Facility Fee - $320" or "Surgical Tray - $25" meant nothing to me. I paid it without questioning anything — and later found out I probably shouldn't have.

That frustration stuck with me. 80% of Americans struggle to understand their medical bills, and $300 billion is lost every year to billing errors. Most people just pay whatever the hospital sends because they don't have the tools or knowledge to push back.

I wanted to build something that actually fixes that.


What I Built

MedVoice is an AI-powered medical bill navigator. You upload a PDF or photo of your bill, and within seconds you get:

  • A plain-English breakdown of every charge
  • Red flags and potential billing errors highlighted
  • A professional insurance appeal letter generated on demand
  • An AI chat assistant to answer follow-up questions about your specific bill
  • A dashboard tracking your spending over time
  • A map to find and compare nearby medical providers

It supports 8 languages — English, Spanish, Chinese, Vietnamese, Korean, Filipino, Arabic, and French — because medical billing confusion isn't limited to English speakers.


How I Built It

The stack is a full-stack web application:

Backend: Python + FastAPI handles all the heavy lifting. When a bill is uploaded, pdfplumber extracts the raw text from PDFs, or Claude's vision API reads image files directly. That text gets sent to the Claude API with a structured prompt that returns a JSON breakdown of charges, red flags, and advice. SQLAlchemy persists the results to a PostgreSQL database hosted on Supabase.

Frontend: Next.js with CSS Modules. Clerk handles authentication with Google OAuth. Recharts powers the analytics dashboard. The Google Maps and Places API drives the provider search feature. Motion handles page animations.

Infrastructure: Backend deployed on Railway, frontend on Vercel, database on Supabase. GitHub Actions runs CI/CD checks on every push — if the build fails, it doesn't deploy.

The whole thing was built independently over about 6 weeks while taking a full course load as a junior CS student.


Challenges I Faced

Getting Claude to return consistent JSON was harder than expected. Medical bills come in wildly different formats — some are scanned images, some are digital PDFs, some have tables, some are just walls of text. Getting the prompt right so Claude always returned a parseable structure took a lot of iteration.

Database connection timeouts from Supabase were a pain in production. The connection would drop after idle periods and crash the server. Fixed it by adding pool_pre_ping=True and pool_recycle=300 to SQLAlchemy's engine config.

CORS in production bit me multiple times. Local development worked perfectly, but the deployed frontend kept getting blocked by the backend until I properly configured the allowed origins for both the Vercel preview and production URLs.

The appeal letter feature required careful prompt engineering. A generic prompt produced generic letters. I had to structure the prompt to reference the specific flagged charges, use formal legal language, and format it as a ready-to-send document — not a template the user still had to fill out.


What I Learned

  • How to design a system where AI failures degrade gracefully rather than breaking the user experience
  • The difference between building something that works locally and something that works reliably in production
  • How connection pooling works and why it matters for serverless-style deployments
  • That prompt engineering is a real skill — small wording changes produce dramatically different outputs
  • How to set up a proper CI/CD pipeline so I never accidentally deploy broken code to production again

Built With

Share this project:

Updates