WhatsApp Fire-Reporting
Wildfire reporting over the app people already have open. A stateful WhatsApp bot walks a witness through the four things responders actually need: where, how big, who is at risk, what it looks like, and hands dispatch a structured report with real coordinates on the end of it. It took first place in the Student Track.
Interactive demo
A real reporting conversation, replayed turn by turn
Starttrigger word
Location+ geocode
Severityspread + risk
Confirmread back
Dispatchhand off
Session idle · state: START
At a glance
- Result
- 🏆 First place, Student Track
- My role
- Conversation flow + dispatch backend
- Stack
- n8n · Twilio · FastAPI
- Awarded by
- EU-funded MEDAIGENCY certificate ↗
The state machine
Why "yes" means different things at different steps
Code
The endpoint my teammates depended on
state/interpret.js
the same word, read per state
export function interpret(message, state) {
const text = message.body.trim().toLowerCase();
switch (state) {
case "SEVERITY":
// here "no" answers "is anyone trapped?"
return { casualties: text === "no" ? "none" : "reported" };
case "CONFIRM":
// here the same "no" means the summary is wrong, reopen it
return text === "yes" ? { next: "DISPATCH" } : { next: "SEVERITY" };
default:
return { next: "LOCATION" };
}
}
workflows/geocode_webhook.js
a stable contract, including failure
export async function handler(req) {
const { pin, text } = req.body;
// a shared pin is already coordinates; typed text has to be resolved
if (pin) return ok(pin.lat, pin.lng, 1.0);
const hit = await geocode(text, { region: "lb" });
// never hand dispatch a confident-looking wrong pin
if (!hit || hit.confidence < 0.6) {
return { status: "needs_confirmation", query: text };
}
return ok(hit.lat, hit.lng, hit.confidence);
}
It became a shared dependency mid-hackathon, so the low-confidence case had to be an explicit response rather than a guess.
Inside the repo
Structure
- □A1.jsonexported n8n conversation workflow
- □app.pyFastAPI “Emergency Dispatch Coordinator”
- □server.jswebhook relay
- □whatsapp.htmlconversation UI mock for the demo
- □custom_dashboard.htmlresponder dashboard
- □fire_stations.jsonstation locations for dispatch
- □dispatch_plan.jsongenerated dispatch output
- □requirements.txt / package.jsonpython + node deps
Skills, in context
Where each one actually showed up
n8n
Every inbound message is its own run, so multi-turn state needed an explicit session store keyed on the sender.
Twilio
WhatsApp transport: a shared pin and a typed address arrive shaped differently and had to normalise.
Webhooks
The geocoding endpoint above, including its defined low-confidence response.
Conversation design
Location asked first: an abandoned report is still useful with coordinates, useless without.
Next project
Driver-Aggressiveness Index