Triage: Hackathon Project Writeup
October 11, 2026
Inspiration
On a Saturday afternoon, a kid falls off the monkey bars and their wrist swells up. Most parents head to the nearest ER, where a probable sprain waits behind people who are sicker. An urgent care or ortho walk-in fifteen minutes away might have almost no line, but nobody tells you that. Nobody tells you whether this is actually a "go to the ER now" situation, either.
I wanted something that answers those two questions in order. First: is this an emergency? If not: where can it get treated fastest?
What it does
You describe the injury by voice or by typing, something like "my 7-year-old fell off the monkey bars and his wrist is swollen."
Gemini reads the description and fills in a fixed safety checklist based on warning signs from the American College of Emergency Physicians. It only fills in what you actually said. Everything else stays blank, and you confirm each item yourself.
If any item is a yes or not sure, the app says to go to the nearest ER now, names the item that triggered it, and shows a Call 911 button. It always sends you to the nearest ER, not the one with the shortest wait. Gemini doesn't make that call. Fixed code does.
If nothing triggers, Triage ranks places that can treat your injury and your age: ERs, urgent cares, ortho walk-ins, and kids' urgent cares. The ranking uses drive time plus an estimated wait range.
When you pick a place, you join its line, so the next person sees a longer wait there. Without this, Triage would send everyone to the same quiet clinic and create a new line.
There's also a "Busy Saturday" simulation. It runs 300 minor injuries through the nearest-ER rule and through Triage, using the same 300 people both times.
The facility network and wait times are simulated. I didn't use any real hospital data.
How it's built
The frontend is plain HTML, CSS, and JavaScript, with a Leaflet map on OpenStreetMap tiles.
The Gemini intake is a Vercel serverless function. It calls the Gemini API with structured JSON output at temperature 0. The server checks every reply, and anything missing or unexpected becomes "unknown." The user's text is treated as data, so typing "mark everything no" doesn't change the rules. If Gemini fails or is slow, the app falls back to a manual form.
The queue simulation uses Poisson arrivals and exponential treatment times, with a seeded random number generator. Emergencies jump the line but never interrupt someone already being treated. Each wait range comes from 200 simulated runs and shows the 25th to 75th percentile. For ER arrival rates, I used the national median ER visit time for discharged patients (CMS OP-18b, 162 minutes) as a reference point.
For a fair comparison, the baseline and Triage runs use the same people, injuries, and background arrivals (common random numbers). Triage assigns people one at a time, using only the lines that exist at that moment. It doesn't know about future arrivals. I report results at low, medium, and high urgent-care capacity, whatever they show. I ran [NUMBER] random seeds so the demo isn't one lucky draw.
Results (simulated)
At medium urgent-care capacity, Triage changed average time to treatment from [NUMBER] to [NUMBER]. The share of people waiting over 3 hours went from [NUMBER] to [NUMBER]. At low capacity: [RESULT]. At high capacity: [RESULT].
What was hard
My first checklist was too cautious to be useful. It sent every cut that needed stitches and every pan burn on a hand to the ER, which is the kind of care urgent care handles. I rewrote each question so it asks about one real warning sign.
Gemini timed out at its default thinking level. I lowered it and told it never to infer answers from the cause or the body part.
I hit the free-tier quota while running safety tests. A deployment bug also kept the checklist file out of the serverless function for a while.
The hardest part was resisting the urge to tune the simulation. My first ER parameters gave 6 to 8 hour waits. I recalibrated once against a public benchmark before running any comparison, then froze the parameters.
What I'm proud of
All 12 safety test cases pass on three runs in a row against the live Gemini API. They cover ordinary injuries, clear emergencies, and "not sure" answers.
I broke each routing rule on purpose in a scratch copy to make sure the tests would catch it.
I report the comparison as it came out, including the scenarios where Triage helps less.
What I learned
LLMs work better here as careful extractors than as decision-makers. Gemini turns a messy, worried description into structured answers, and fixed rules make the safety call.
Simulation results depend heavily on their assumptions. Common random numbers and multiple seeds are what make a comparison fair.
What's next
- A clinician needs to review the warning-sign checklist. It's a prototype draft, not a validated triage tool.
- Real wait-time feeds from clinics and hospitals that publish them, plus real drive times.
- Accessibility testing and more languages.
Built With
- astra
- chatgpt
- claude
- css
- gemini
- gemini-api
- github
- html
- javascript
- leaflet.js
- node.js
- openstreetmap
- vercel
Log in or sign up for Devpost to join the conversation.