Inspiration

A regional climate advisory saying "heavy rainfall expected over the Shabelle basin" is meteorologically correct and operationally useless to the person who actually needs to act on it. Turning that into "who is affected, in what language, told to do what, by when" today means a disaster-management officer manually reading the advisory, guessing at affected districts and population, drafting an SMS, translating it (often without a professional translator on hand), checking it fits a text message, getting sign-off, finding the right phone numbers, and sending it under time pressure, often for multiple hazards and languages at once. Each step is slow and easy to get wrong on its own; done manually and repeatedly, it's why hyper-local, multilingual, well-targeted warnings often arrive late or not at all, even when the underlying forecast was timely and accurate. We wanted to close that gap without ever letting an AI system get between a real hazard and the truth of what people are told about it.

What it does

AlertBridge AI takes a hazard alert (flood, heavy rainfall, drought, or heat) and turns it into a localized, multilingual, human-approved SMS warning in minutes:

  • Intersects the warning area with administrative boundaries, settlements, health facilities, schools, and roads to estimate exposed population and rank affected districts by an explainable priority score.
  • Drafts an audience-specific SMS from verified structured facts only, via a real AI provider or a deterministic template that works with zero AI key.
  • Translates it into Somali, Swahili, or Amharic, flagged for mandatory human review.
  • Validates that the message mentions the hazard, location, timing, and an approved protective action, and blocks anything else.
  • Requires a human reviewer, in a role distinct from whoever drafted it, to explicitly confirm facts, targeting, actions, and translation before anything can be sent.
  • Targets recipients by geography, audience, and language, and sends via Africa's Talking (sandbox/live) or a safe mock provider.
  • Reports delivery rate, cost, and population reached on an analytics dashboard.

How I built it

React 18 + TypeScript + Vite + Tailwind on the frontend; FastAPI + SQLAlchemy + Alembic on the backend, with GeoPandas/Shapely/PyProj running the geospatial intersection and priority-score math identically on SQLite (zero-config local dev) or Postgres/PostGIS (production). The AI layer is pluggable (mock, OpenAI, Azure OpenAI, or any OpenAI-compatible endpoint) but architecturally constrained: it only ever receives a structured, pre-verified field set, never the raw alert text, never anything it could invent facts from. A strict system prompt, Pydantic schema validation, and an independent guard that cross-checks every claimed protective action against an admin-approved library gate for every AI response; any failure at any layer automatically falls back to a deterministic, zero-hallucination template. We deployed the whole stack on Render (FastAPI as a Docker web service, the React app as a static site, managed Postgres) and wired the AI layer to Hugging Face's free inference router as a genuinely no-cost real-AI option.

Challenges I ran into

Getting from "works on my machine" to "works in production" surfaced problems that my own test suite never could, because they were differences between SQLite and Postgres, or between a deterministic template and a real language model:

  • Render's managed Postgres hands out a postgres:// URL, but only psycopg v3 was installed; SQLAlchemy defaults that scheme to the (absent) psycopg2 driver, so the API crashed on boot until we normalized the URL scheme.
  • An unrelated-looking "CORS error" in the browser turned out to be a middleware-ordering bug: our rate limiter was registered after CORSMiddleware, so it wrapped it instead of being wrapped by it, and any 500 response it touched went out with no CORS headers at all — the browser reported it as a CORS failure instead of the real 500.
  • The analytics endpoint worked perfectly in every local test and then threw TypeError: can't subtract offset-naive and offset-aware datetimes the moment it ran against Postgres — SQLite silently returns naive datetimes regardless of column type, Postgres honors them, and one of our models had a timezone-aware timestamp column while a related one didn't.
  • The free hosting tier doesn't support one-off jobs or non-interactive SSH, so seeding the database had to move from "run once after deploy" to "run idempotently on every boot."
  • Wiring up a real AI provider surfaced its own subtlety: not every "OpenAI-compatible" free model actually honors structured JSON-schema output. We tested several before finding one that reliably followed our schema without burning thousands of tokens on ignored reasoning — and even then, the model's more natural phrasing of a multi-county location list ("Busia, Siaya, Kakamega Counties") tripped a validation rule that had only ever seen a deterministic template's exact wording before. Real AI text is more human than a template, and our guardrails had to become a little more human too.

Accomplishments that I'm proud of

The whole pipeline runs with zero external API keys by default and produces the same safe, structured output whether the AI layer is a mock template or a real language model; nothing about the safety guarantees changes based on what's configured. We're proud of the three-layer AI safety design (constrained input, schema validation, independent action-approval guard) actually holding up once real, less-predictable AI text started flowing through it in production, and of catching every one of the bugs above through genuine end-to-end dogfooding rather than shipping them. The result is a fully deployed, live application where a warning genuinely flows from hazard alert through geospatial exposure, AI drafting, translation, role-separated human approval, simulated SMS dispatch, and back out as measurable analytics with 48 automated backend tests passing throughout.

What I learned

Dev/prod parity gaps hide in database-specific behavior, not just missing environment variables. SQLite's forgiving handling of time zones and driver schemes let two real bugs sail through every local run. "OpenAI-compatible" is a spectrum, not a guarantee: structured-output support has to be verified empirically against each provider and model, not assumed from the API shape. And robust AI safety comes from architecture: what facts the model is allowed to see, and what an independent layer checks afterward, not from how carefully the prompt is worded. We also learned that constraints (a free hosting tier with no job runner) often force a simpler, more resilient design than the one we would have reached for by default.

What's next for AlertBridge AI

Swapping in real administrative boundaries and WorldPop-weighted population data in place of the synthetic demonstration datasets; a professional linguist pass on the Somali, Swahili, and Amharic templates and machine translations; field-testing live Africa's Talking dispatch and additional AI providers under real network conditions; PDF alert briefings for offline distribution; and, most importantly, a pilot partnership with a national meteorological agency or disaster-management authority to validate the exposure methodology and protective-action library against real operational needs rather than a synthetic scenario.

Built With

Share this project:

Updates

Submission history