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
- claude-api-(anthropic)
- clerk
- css-modules
- fastapi
- github-actions
- google-maps
- google-places
- javascript
- next.js
- pdfplumber
- postgresql
- python
- railway
- react
- recharts
- sqlalchemy
- supabase
- vercel
Log in or sign up for Devpost to join the conversation.