Inspiration
In January 2025, the Palisades and Eaton fires overwhelmed LA's emergency phone lines. LAPD's after-action report counts 160+ evacuation-assistance calls in the Palisades fire. Many came from family members who couldn't reach the people they loved, and call-takers grouped them by hand. A later review for the Governor found that "calls came in faster than dispatch could manage or assign them."
Even on a normal day the line is short-staffed. In 2024, LAPD answered only 57% of 911 calls within 15 seconds; the standard is 90%. A caller who needs an interpreter waits 49 seconds on average for one to join.
The time a caller spends on hold is wasted. And when a call-taker finally picks up, they start from zero: where are you, what happened, who's hurt? We wanted that waiting time to become intake time, without letting an AI decide who gets help.
The same thing happens on an ordinary Tuesday. A building management line gets ten calls about one leak, and the person on duty spends the day typing addresses.
What it does
DIZA answers every call in the caller's language, pins each place on a live map, ranks who needs a person first, and phones the right teammate. On a normal day it serves a building; on a surge night it serves a 911 floor.
- Answers immediately, in English or Spanish, and tells the caller a person is coming.
- Collects the basics: location, callback number, what happened, who's hurt, and any hazards or access needs.
- Puts every place on the map. If one caller says "my grandmother fell at Western and 6th, and my neighbor fell at 11th and Broadway in Santa Monica," that becomes two cards with two pins.
- Groups duplicates without hiding them. Twenty callers about one freeway crash become one incident, and each call keeps its own record.
- Ranks with rules, and shows why. Each card lists its reasons ("fall, can't get up, elderly", "3 independent callers").
- Calls the right person. An offer phones the on-duty teammate with the right skill, language and area. They answer "yes" or "no" by voice. A "no" or a timeout moves to their backup.
- Building mode: "Unit 4A, water leaking from my bathroom ceiling" becomes a ticket. The maintenance person's phone rings, they accept, and the ticket moves to In progress by itself.
What DIZA never does: dispatch, send public alerts, decide who gets help, or close an emergency. A person takes every P0. Independent callers are counted, not trusted, and in drill mode transfers only reach teammates. The AI listens and asks. Rules rank. People decide.
How we built it
- Voice: Retell AI agents with custom functions (
submit_report,route_to_human,flag_urgent,lookup_info) and outbound calls that brief the teammate on an assignment. Every function call is signature-checked and idempotent, because Retell retries. - Backend: FastAPI + SQLite. Reports, requests, offers, attempts and the audit log are all persisted, so offer timeouts resume after a restart.
- Ranking: a plain rule score, with every term shown on screen. In simplified form:
$$ \text{score} = B_{P} + \sum_{w \,\in\, \text{danger words}} d_w + 10\cdot\min(v, 2) + 10\cdot[\,n \ge 3\,] + \min\big(15,\ 5(c-1)\big) $$
where $B_P$ is the severity base ($P0{=}100,\ P1{=}70,\ P2{=}40,\ P3{=}10$), $d_w$ comes from the caller's own words (trapped $+40$, not breathing $+35$, weapon $+30$, bleeding $+20$), $v$ counts vulnerability flags, $n$ is the number of people involved, and $c$ is the number of independent callers (distinct phone numbers, not just more rows). P0 is always pinned to the top.
- Second reader: a multilingual danger-word list, including sound-alikes speech-to-text gets wrong ("has a kite" → knife). It can raise a card's priority until a person reviews it, and it never lowers one.
- Location: the US Census geocoder for addresses and OpenStreetMap Nominatim for landmarks, LA County first. Reports of the same kind within 250 m and 10 minutes join one incident.
- Dashboard: React + Vite + MapLibre, with
/opsfor 911 operations,/buildingfor building management and a supporter inbox. The interface is in English, Español and 中文, and there's an offline LA basemap built from US Census TIGER data. - Global: one setting,
DIZA_COUNTRY, sets the emergency number, map area and default language. - Hosting: Railway, in drill mode.
Challenges we ran into
- Geocoding real speech. A caller said "Tulsa", and we pinned an LA street named Tulsa. LA County also has many corners with the same name. Now a town the caller names beats a local street with the same name, and a corner without a city goes to "place on map" instead of getting a confident wrong pin.
- One call, many places. Callers list places in one breath. We had to split "Kansas City, Wichita, and Tulsa" into three cards without splitting "11th and Broadway" or "Santa Monica, CA."
- Keeping the AI out of decisions. It was tempting to let the model set priority. Instead, the model only extracts and the rules decide, so every rank can be explained and audited.
- Nobody stuck "busy." Teammates kept getting marked busy after their calls ended. A sweep now frees anyone without a live call, accepted job or pending offer.
- A deploy outage on the last day, caused by one malformed environment variable rather than code.
- Accessibility: our first severity colours failed a colour-blind check. We switched to a one-hue scale and always print P0–P3 next to the colour.
Accomplishments that we're proud of
- It works on real calls. In our live drill, DIZA handled 44 of 49 calls without an operator and went from pickup to a ranked card on the operator's screen in a median of 25 seconds.
- A real phone call becomes a real phone call. A caller speaks, a card and a pin appear, and a teammate's phone rings and accepts by voice. No one types anything.
- Every rank explains itself. No black box decides who gets help first; each reason is on screen.
- Nothing gets hidden. Merged reports stay listed, merges can be undone, and reports we couldn't place are listed rather than dropped.
- One system, two customers. The same agent, map and team handle a leaking ceiling on Tuesday and a mass-casualty surge at night.
- Ready for other countries from day one. A tourist calling from a +86 number in LA still hears 911, while a deployment in China would say 119, 120 or 110 for each service.
- 124 automated backend tests covering duplicate submissions, assignment contention, timeouts and backups, and Retell failing closed.
What we learned
- 911 call-takers don't need a robot that takes their job. LAPD's own plan says AI "will be a tool for PSRs … not an automated call-taking service." That became our design rule.
- The NENA standard requires a location to be read back to verify it. Location is the hardest and most important field.
- Corroboration should be counted, not trusted. Three callers make an incident more likely to be real, but a flood of fake calls is a real threat, so we never use corroboration to filter.
- The emergency number follows where the line runs, not the caller's phone.
- The same pipeline (answer, extract, locate, rank, call a human) works for a leaking ceiling and for a mass-casualty surge. Building it for both made each version better.
What's next for DIZA
- A pilot with one LA-area communications center or a campus department, funded through FEMA UASI/EMPG, with NSF SBIR for the R&D.
- A location link by text, so a caller can tap it to share their exact GPS position.
- More languages: Korean, Vietnamese, Farsi, Armenian and Tagalog for the dashboard and verified calls (the danger-word lists already cover them).
- Real deployments per country: local carriers, in-country models and hosting where privacy law requires it, and per-country offline maps.
Try it: call +1 978-915-3497 (drill mode; nothing reaches real 911) and watch the call appear at https://diza-production.up.railway.app/ops
Built With
- census-tiger
- claude-code
- fastapi
- i18n
- javascript
- llm
- maplibre
- nominatim
- openstreetmap
- python
- railway
- react
- rest-api
- retell-ai
- sqlite
- us-census-geocoder
- vite
- voice-ai
- webhooks
Log in or sign up for Devpost to join the conversation.