-
-
No stream in the photo? The AI says so and suggests nothing (13/13 in tests)
-
The overall rating is always the citizen's call; the AI is blocked in code
-
Quests and a coverage map send people where data is missing; team-only leaderboards
-
FHIR R4 export, validated against the OneAquaHealth profiles: 0 errors, 0 warnings
-
48-hour alerts show the measured value, the threshold and its source
-
StreamLens: the AI suggests, the citizen decides
Track alignment: Primary Track 1 – Citizen Science UX. Also contributes to Track 3 (AI-supported assessment), Track 2 (data-to-insight), Track 6 (resilience & early warning), Track 5 (community & gamification) and Track 7 (digital health standards – FHIR R4).
Inspiration
Urban streams are where nature and city health meet. The OneAquaHealth policy brief reports pharmaceuticals at 91% of monitored urban stream sites and links ecological decline to human health. Citizens could extend monitoring far beyond what scientists can visit, but today's assessment is long, full of expert vocabulary, and gives nothing back. People come once and don't return, and the data that does arrive is inconsistent. We wanted a tool that makes a first assessment easy, makes the data trustworthy, and gives people a reason to come back, without letting AI take over the citizen's judgement.
What it does
StreamLens is one loop: observe → understand & act → return.
① Observe: photo-first guided assessment. Pick one of the 106 real OneAquaHealth research sites (Benevento, Coimbra, Ghent, Oslo, Toulouse) and take an upstream and a downstream photo. If the citizen opts in, an AI vision model pre-fills the app's own questions as suggestion chips, each with a confidence level and a plain-language reason. The citizen accepts, rejects or changes every chip; nothing is recorded until they say so. If a photo doesn't show a watercourse, the AI says so and suggests nothing. Every expert term can be tapped for a plain explanation. It works offline and syncs later, in 6 languages (EN, PT, IT, FR, NL, NO; four machine-translated, awaiting native review).
The AI never sets the overall rating. Good/Moderate/Poor is always the citizen's call, enforced in code in three separate places.
② Understand & act. Each site gets a health card built only from citizen-confirmed answers. A rule engine combines Open-Meteo forecasts with recent reports to raise 48-hour alerts (possible sewer overflow, mosquito-breeding conditions, debris/flood watch). Each alert shows the measured value, the threshold and the source of that threshold, and never claims a diagnosis. Observed problems link to 25 measures from the OneAquaHealth rehabilitation catalogue (D2.4, CC-BY-4.0), each with a section and page reference and human-health co-benefits. A city overview gives municipal staff a sortable table and CSV export.
③ Return: gamification that improves the science. Quests come from real data gaps: a site nobody has visited in 30+ days, a check right after heavy rain, a missing season, a second opinion. Points reward photo quality, completed quests and agreement between visitors, never volume. Leaderboards are team-only, because an individual ranking would reward made-up data. A coverage map shows where monitoring is missing, and a wellbeing mirror shows how people feel at healthy vs degraded streams (community view only for groups of 10+, never presented as a health measure).
Standards. Every confirmed observation exports as a FHIR R4 Bundle (Location, Observations, Provenance recording who confirmed it and which AI model suggested it).
Who it's for: citizen scientists and school groups; OneAquaHealth researchers (consistent data with provenance); municipal water and health officers (alerts, measures, city overview, FHIR).
How we built it
- Frontend: React + TypeScript + Vite as an offline-first PWA (Tailwind, Leaflet/OpenStreetMap, IndexedDB outbox, i18next).
- Backend: FastAPI + SQLModel on PostgreSQL (Neon); Render + Vercel on free tiers.
- AI: Google Gemini with structured JSON output. Every suggested code is checked against the question catalogue, and anything unrecognised is dropped, never shown. The prompt is versioned and loaded at runtime; a mock provider with a visible badge takes over if the AI is unavailable or over quota.
- Data: the OneAquaHealth/ENORA site API, the OneAquaHealth rehabilitation catalogue (page references checked automatically against the PDF), Open-Meteo forecasts and history.
- Evaluation: our own harness scoring agreement, "not sure" rate, dropped codes, calibration, latency and cost per prompt version, with committed reports.
- Standards: the official HL7 validator + SUSHI, compiling the OneAquaHealth IG profiles from their FSH source.
- Quality: 279 backend + 22 frontend automated tests; Lighthouse mobile on the live site: 94 performance, 100 accessibility, 100 best practices, 100 SEO.
- Privacy: AI help is opt-in; the manual path sends no photos to the AI; photo metadata (including GPS) is stripped; no names reach the server; photos aren't stored on the hosted demo.
Challenges we ran into
- Keeping the AI honest was harder than making it work. Our evaluation caught a bug where fallback (mock) answers were being scored as the model's, which would have reported a false error rate. It also proved one of our own assumptions wrong: we thought a still photo couldn't judge water flow, but it was one of the best-performing questions, so we reinstated it.
- Moving AI models: two Gemini models were retired or overloaded mid-build, so we added timeouts, one retry and a loud, labelled fallback instead of silent failure.
- Standards without a published package: the OneAquaHealth FHIR IG build was offline during the hackathon, so we compiled the profiles from source, validated against them, and proved the check was real by deliberately breaking a bundle.
- Honest demos: some alerts need rain that wasn't forecast, so demo forecasts are planted and clearly badged "DEMO FORECAST" rather than passed off as real.
Accomplishments that we're proud of
- The AI knows when to say nothing: it stayed silent on 13 of 13 test photos with no stream.
- 0 invented answer codes across 187 suggestions, and 90% agreement (exact) / 92% (set-overlap) with an independent AI labeller. We report it as agreement, not accuracy, because no expert labels exist yet.
- FHIR R4: 0 errors, 0 warnings against the OneAquaHealth IG profiles.
- Every alert threshold and every restoration measure traces back to a source, and where a threshold is our own judgement, it says so.
- A live, deployed, accessible (Lighthouse accessibility 100) app that a judge can try in four minutes with bundled sample photos.
What we learned
- Responsible AI is mostly engineering: guardrails in code, measured behaviour and honest reporting matter more than a clever prompt.
- Test your own assumptions with data. Our evaluation changed our design twice.
- Gamification can harm citizen-science data if it rewards volume. Rewarding quality, agreement and filling real gaps aligns fun with scientific value.
- Standards like FHIR are what let a small tool plug into real health and environmental systems.
What's next for StreamLens
- Expert-in-the-loop: label photos with OneAquaHealth ecologists for a true accuracy measure, and add a review queue for flagged observations.
- Pilot with one school group in a partner city and measure time, errors and return visits.
- Integrate, don't replace: hand over the question mapping and FHIR export to the OneAquaHealth app team, and use its identity system instead of our own.
- Scale: about $0.004 per two-photo AI-assisted assessment (~$40 per 10,000/month); native-speaker review of translations; move off free tiers.
Known limits (honest): free-tier hosting (first load may take up to ~45 s if idle), demo data and demo forecasts are clearly labelled, no user accounts yet, translations awaiting native review, evaluation uses a small web-photo sample.
Built With
- fastapi
- google-gemini
- hl7-fhir
- indexeddb
- leaflet.js
- neon
- open-meteo
- openstreetmap
- postgresql
- pwa
- python
- react
- render
- sqlmodel
- tailwindcss
- typescript
- vite
Log in or sign up for Devpost to join the conversation.