Inspiration
During a war, dozens of humanitarian reports come out every week. ReliefWeb posted more than 15 English-language updates on Sudan in just four days before this hackathon. The people trying to help, such as small NGOs, diaspora organizations, journalists and students, can't read them all. Small organizations also have to turn those reports into regular updates for their donors and members, which takes staff time they rarely have.
A general chatbot answers instantly, but it rarely shows where a claim came from or how old it is, and it may drift into military speculation or safety advice it can't back up. We wanted something fast and checkable: every sentence traceable to a dated report from an established aid agency.
What it does
- A world map highlights countries at war, using the UCDP/PRIO Armed Conflict Dataset v26.1, not our own judgment.
- Click Sudan or Ukraine to zoom in and open a briefing: 4 to 6 short points on displacement, food, health, aid access and who is most affected, written by IBM Bob. Every point cites its source, with the publisher and date.
- Ask a question ("Is anyone starving?"). If no report covers it, the app says so instead of guessing.
- What's new · 7 days compares this week's reports with the 45 days before: newly affected areas, displacement, access, needs and funding. Each change cites the new report and, when a figure was updated, the earlier one too.
- Weekly update draft: a small NGO or diaspora group picks its audience (donors or members) and gets a one-page, sourced situation update to edit, copy into an email, or save as a PDF.
- Country profiles give key figures, each backed by an exact quote from its source.
- Official links, labelled "not generated by AI," replace any safety advice. The app never gives evacuation guidance.
How we built it
- Collect.
fetch_reports.pypulls recent reports from ReliefWeb's public country feeds. A transparent filter keeps needs-focused reports from established agencies (OCHA, UNHCR, WFP, ICRC, UN Women and others) and drops meeting minutes, admin notices and battle-event data. Every report is also saved to an archive with the date we first saw it, which powers the 7-day comparison. - Retrieve. Reports are split into passages and embedded with a small local model (
BAAI/bge-small-en-v1.5via fastembed), so questions match passages by meaning. If the best match is too weak, the app answers "the reports don't cover this" without calling the AI. - Generate. IBM Bob (
bob run, Inference-scoped key) writes only from the retrieved, numbered passages and must cite one on every sentence. Bob runs in an empty temporary folder with all tools, MCP and subagents disabled. - Validate. Code drops any sentence without a valid citation. "What's new" items must cite a report from the last 7 days. In the weekly update, a headline containing numbers is replaced, since a headline can't carry a citation. If Bob is unavailable, the app shows labelled source excerpts instead.
- Verify. Key figures come from the country profiles, not the AI.
verify_profiles.pychecks every profile quote against its source: all 29 of 29 matched word for word, and none is older than a year.
Stack: Python and FastAPI backend, d3 + topojson map (Natural Earth borders), IBM Bob, fastembed, pytest (20 tests).
Responsible AI
- Transparency: every claim cited and dated; a badge shows whether text is AI-written or excerpted.
- Safety: no safety or evacuation advice, ever.
- Fairness: conflict status comes from UCDP's published definitions; disputed territory names are hidden and borders follow Natural Earth.
- Privacy: no accounts; questions aren't stored; an organization's name on the weekly update is printed only and never sent to the AI.
- Human in control: the weekly update is a draft. Every block is editable, and the footer says it was AI-assisted.
- Honesty about gaps: a "Not covered" line says what the sources don't address.
Evaluation
TODO: For each country we asked five questions (food, displacement, health, aid access, women and children) and checked every AI point against its cited source: 5 of 5 points supported.
We also tested the weekly update's length: 8 of 8 generated drafts printed on a single A4 page.
Challenges we ran into
- We pivoted mid-event. Our first idea, a civic complaint router, already existed as a product.
- The ReliefWeb API needs an approved app name, so we switched to its public RSS feeds.
- The newest reports were often minutes or military updates, which pushed us to build the quality filter.
- Bob Shell's output format needed custom parsing before AI mode worked.
- Our first country profile was written from memory with 2024 figures. We rebuilt it with quoted, dated sources and an automatic checker.
- "What changed this week" is easy to get wrong. We instruct Bob to treat restated older figures as background and never to compare figures that measure different things.
What we learned
- Grounding an AI matters less than proving it is grounded: citations only build trust if code checks them.
- Saying "the sources don't cover this" is a feature, not a failure.
- Choosing sources is itself a judgment, so we made that filter visible and explainable.
- The most useful output wasn't an answer but a draft a person can check, edit and send.
Use of AI tools
- IBM Bob writes the briefings, weekly comparisons and update drafts at runtime.
- Claude (Anthropic) helped with planning, the first backend draft, the report filter and documentation.
- TODO: list what the IBM Bob IDE helped with, or delete this line if unused.
We reviewed and tested all code and can explain every part.
Limitations and next steps
- Full briefings for 2 countries today; next, every UCDP-listed war.
- The report archive only started this week, so "What's new" has little history to compare against yet; it improves with daily fetches.
- English only; next, multilingual retrieval and summaries.
- Profiles are curated by hand; next, AI-drafted profiles that a person approves.
- Test the weekly update with real NGOs and diaspora groups, and measure the time it saves.
Log in or sign up for Devpost to join the conversation.