Inspiration
Every year, thousands of stray and abandoned animals in Bengaluru go unnoticed — not because people don't care, but because finding the right help fast is hard. When someone spots an injured dog at midnight, they shouldn't have to Google through 10 tabs to find an open vet nearby. We built Pet-Rescue-Bangalore to make that moment frictionless.
What it does
Pet-Rescue-Bangalore is a conversational AI coordinator that handles three scenarios in one chat interface:
- Emergencies — User describes an injured or sick animal; the assistant instantly surfaces the nearest open emergency vets (with real-time open/closed status), on-call rescuers covering that area, and a step-by-step first-aid protocol — all with one-tap WhatsApp contact buttons.
- Adoption — User describes what they're looking for ("calm dog, good with toddlers"); the assistant runs a hybrid semantic + keyword search across 33 real listings and returns the best matches with photos, source org links, and a color-coded map.
- Protocols — General animal care and rescue guidance retrieved via semantic search over a curated protocol library.
The same agent works on both a Streamlit web UI and WhatsApp (via Twilio webhook), with channel-aware response formatting.
How we built it
- Elasticsearch on Elastic Cloud as the data backbone — 5 indices (animals, vets, rescuers, protocols, raw_listings) with geo_point fields for location-aware queries.
- Elastic Inference Service (EIS) with
jina-embeddings-v5-text-smallfor zero-friction semantic embeddings — documents are embedded automatically on index, no separate embedding pipeline needed. - Hybrid search combining BM25 multi_match + semantic query fused via Reciprocal Rank Fusion (RRF) for adoption queries.
- Claude Sonnet (via AWS Bedrock) as the reasoning agent — multi-turn conversation with a strict 7-rule system prompt to prevent hallucinated phone numbers, addresses, or org names.
- FastAPI backend with
/chatand/whatsapp(TwiML) endpoints. - Streamlit frontend with a live folium map, animal cards, vet/rescuer cards with WhatsApp deep links, and demo prompt buttons.
- Real-time open/closed logic — post-filters vets and rescuers against current Asia/Kolkata time using their stored
HH:MM-HH:MMweekly schedules.
Challenges we ran into
- EIS vs. direct Jina API — the original plan used direct Jina REST calls with dense_vector fields. Switching to EIS required redesigning index mappings to use
semantic_texttype, which changed how queries are constructed entirely. - Bedrock toolResult format — Bedrock's
converseAPI requirestoolResult.content[].jsonto be a JSON object, never an array. List results from tool functions had to be wrapped as{"results": [...]}before returning. - Streamlit cache + health badge —
@st.cache_datawas caching failed health checks for 30 seconds, so the "backend unreachable" banner persisted even after the backend came up. Fixed by making the cached inner function raise on failure sost.cache_datanever storesNone. - f-string backslash limitation — Python < 3.12 disallows backslash escapes inside f-strings; the folium map legend HTML broke silently. Fixed by building the HTML in a list comprehension outside the f-string.
Accomplishments that we're proud of
- A fully working end-to-end agentic loop — from natural language input to parallel tool calls to a rendered map with real data — running locally with no mocked components.
- Zero hallucination guarantee enforced at the prompt level: the agent is instructed to never invent names, phone numbers, or addresses, and every animal result must cite
source_organdsource_url. - Dual-channel support (web + WhatsApp) from a single agent codebase, with channel-aware formatting.
- The open/closed vet filter working correctly in real-time across time zones using only stored schedule strings — no external calendar API.
What we learned
- Elastic's
semantic_textfield type paired with EIS removes almost all embedding boilerplate — it's genuinely the right abstraction for RAG on Elasticsearch. - RRF is remarkably effective as a fusion strategy; even simple rank fusion outperforms either BM25 or vector search alone for mixed natural-language + structured queries.
- Strict system prompts are load-bearing safety infrastructure, not optional polish. Defining exactly what the agent must and must not do — especially around fabricating contact info — is critical for a tool people might use in a real emergency.
- Building for WhatsApp forces good response design discipline: if a reply doesn't fit in 6 short lines, it's too long for any channel.
What's next for Pet-Rescue-Bangalore
- Live crawler pipeline — Scrapling-based crawler feeding
raw_listings, with a Bedrock structuring step to auto-populateanimalsfrom scraped pages. - NGO dashboard — a simple admin UI for rescue orgs to update their animal listings and availability directly.
- Proactive alerts — WhatsApp opt-in notifications when a matching animal is listed (e.g., "notify me if a Beagle under 1 year shows up").
- Multi-city expansion — the architecture is city-agnostic; adding Chennai or Hyderabad is a data + prompt change, not a code change.
Built With
- aws-bedrock-(claude-sonnet)
- aws-sdk-(boto3)
- elastic-inference-service-(eis)
- elasticsearch-(elastic-cloud)
- fastapi
- folium
- jina-embeddings-v5
- streamlit
- twilio-(whatsapp)
Log in or sign up for Devpost to join the conversation.