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-small for 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 /chat and /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:MM weekly 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_text type, which changed how queries are constructed entirely.
  • Bedrock toolResult format — Bedrock's converse API requires toolResult.content[].json to 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_data was 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 so st.cache_data never stores None.
  • 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_org and source_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_text field 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-populate animals from 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)
Share this project:

Updates