Spaces:
Running
title: PawMap
emoji: πΎ
colorFrom: green
colorTo: green
sdk: docker
app_file: app.py
pinned: true
license: mit
short_description: Collaborative stray animal mapping with AI
tags:
- stray-animals
- animal-welfare
- maps
- computer-vision
- small-models
- gradio
- build-small-hackathon
- backyard-ai
- leaflet
- cosine-similarity
models:
- nvidia/nemotron-3-nano-omni-30b-a3b-reasoning
- sentence-transformers/all-MiniLM-L6-v2
- meta-llama/Llama-3.2-11B-Vision-Instruct
PawMap πΎ β Collaborative stray animal mapping with AI
Take a photo of the stray animal you just spotted. The AI identifies species, breed and color β and checks if it's already been registered before.
Over time, the map tells each animal's story: where it shows up, who helped, whether it's doing okay.
Built for the Build Small Hackathon 2026 Β· Backyard AI track π‘
Try it: live Space Β· Traces: dataset on the Hub
The Problem
BrasΓlia, DF β the capital of Brazil β has thousands of stray dogs and cats scattered across its residential wings, parking lots and green areas. Independent rescuers know each animal by nickname, by street, by habit. But that knowledge lives in WhatsApp groups, in individual memory, nowhere persistent.
The friend who inspired this app has been feeding a colony of cats near the Asa Norte commercial strip for years. She knows exactly which ones have been neutered, which ones have a history of injury, which one vanished last month. But when someone new wants to help β or when she needs backing to request food donations β there's nothing to show. No map, no timeline, no proof that a specific animal has been living on that block for two years.
PawMap is that record. Anyone takes a photo of a stray animal with their phone. The AI identifies it, GPS pins the location, and the app checks whether that animal has been seen before β linking all sightings to its profile. The map is public. The animal's trail becomes visible. Anyone who wants to help knows exactly where to go.
How it works
There are two AI-powered flows: registering a sighting and recording help.
Sighting flow
flowchart TD
A["π· Photo from phone"] --> B["π€ Vision AI\nLlama-3.2-11B or Nemotron Omni\n(serverless API)"]
B -->|"is it an animal?"| C{Animal detected?}
C -->|"No"| ERR["β Error message\n'No dog or cat identified'"]
C -->|"Yes"| D["π Structured JSON\nspecies Β· breed Β· color Β· condition Β· marks"]
D --> E["π’ Semantic embedding\nall-MiniLM-L6-v2 Β· 384 dim\n(local, 22M params)"]
E --> F{Cosine similarity\nβ₯ 0.80?}
F -->|"Yes β known animal"| G["β New sighting\nadded to existing animal"]
F -->|"No β new animal"| H["π New animal\nregistered in the database"]
G --> I["πΎ SQLite"]
H --> I
I --> J["πΊοΈ Leaflet map\nprofiles Β· trail Β· gallery"]
Before confirming, the user sees the top 3 most similar animals already in the database β they can edit what the AI detected, give the animal a name, and note its condition. Only then is the sighting saved.
Help flow
When someone wants to help an animal, they can submit a help proof β a photo showing they fed it, treated a wound, or got it to a vet. The AI does two things with that photo:
flowchart TD
A["π· Help proof photo\n(optional)"] --> B["π€ Vision AI\nanalyzes the new photo"]
B --> C["π’ New embedding\ngenerated from description"]
C --> D{Cosine similarity\nagainst registered animal?}
D -->|"Match β₯ 0.80\nsame animal ID"| E["β
AI-verified\nmatch score shown"]
D -->|"No match"| F["β οΈ Unverified\nstill recorded"]
B --> G{Condition improved?}
G -->|"e.g. injured β healthy"| H["π Condition update\nlogged on profile"]
G -->|"same or worse"| I["No change"]
E --> J["πΎ Help event saved\nto sightings table"]
F --> J
H --> J
I --> J
The profile page shows the full help history with photos, help type (fed / treated / rescued / other), AI verification status and any detected condition improvement.
The map uses color to signal urgency: π’ green = dog Β· π orange = cat Β· π΄ red = not seen in +30 days.
What's inside
| Component | Model / Library | Where it runs |
|---|---|---|
| Visual identification | Nemotron Omni 30B via NVIDIA NIM | remote API |
| Vision fallback | Llama-3.2-11B-Vision-Instruct via HF Serverless | remote API |
| Semantic embedding | all-MiniLM-L6-v2 (384 dim) | CPU, local |
| Animal matching | Cosine similarity (threshold 0.80) | CPU, local |
| Database | SQLite | local / persistent |
| Frontend | SPA via gradio.Server + Leaflet.js + Lucide Icons |
browser |
Total parameters running locally: ~22M. The vision model runs via serverless API β nothing heavy on the Space machine. The only local model is MiniLM for embeddings.
Screens
| Screen | Description |
|---|---|
| πΊοΈ Map | Color-coded pins by species/urgency, floating card with "View profile" |
| π· Register | Photo upload + automatic GPS + AI analysis |
| π€ Analysis | Auto-identification with editable fields + top 3 similar animals |
| β Confirm | Sighting summary before saving |
| ποΈ Spotted | List of all registered animals |
| πΎ Profile | Full animal card with gallery, map trail and help history |
Badges
This submission earns the following hackathon bonus quests:
- π¨ Off-Brand β Fully custom interface via
gradio.Server, no default Gradio components visible. SPA frontend with Leaflet.js for the map, Lucide Icons, and custom design. - π‘ Sharing is Caring β Full traces of every sighting (photo β AI analysis β embedding β matching result) are automatically published as a dataset on the Hub via
/admin/push-traces.
Running locally
git clone https://huggingface.co/spaces/build-small-hackathon/viralata-mapper
cd viralata-mapper
pip install -r requirements.txt
# with HuggingFace Serverless
HF_TOKEN=hf_... python app.py
# or with NVIDIA NIM (takes precedence over HF_TOKEN)
NVIDIA_API_KEY=nvapi_... python app.py
# no key β runs in fallback mode without AI identification
python app.py
# open http://localhost:7860
On first run the app seeds the database with demo animals around BrasΓlia so the map isn't empty.
Space configuration
Secrets
| Secret | Description |
|---|---|
HF_TOKEN |
HuggingFace token for Llama-3.2-11B-Vision via Serverless Inference |
NVIDIA_API_KEY |
Alternative: Nemotron Omni via NVIDIA NIM (takes precedence over HF_TOKEN) |
MATCH_THRESHOLD |
Optional. Similarity threshold. Default: 0.80 |
HF_DATASET_ID |
Optional. Hub dataset for trace publishing (e.g. org/dataset-name) |
Without a Vision AI key the app runs in fallback mode β registration and matching still work, but automatic breed/color/condition identification is disabled.
Persistent Storage
Set up a Persistent Storage Bucket in the Space and mount it at /data/ so photos and the database survive restarts. Without it, all data is wiped on each deploy.
Repository structure
.
βββ app.py # Entrypoint β FastAPI routes + Gradio Server
βββ requirements.txt
βββ Dockerfile
βββ index.html # SPA frontend
βββ static/
β βββ app.js # Client logic (map, camera, registration flow)
β βββ style.css
β βββ lottie/ # Loading animations
βββ core/
β βββ ai.py # Vision AI (HF or NVIDIA NIM) + embeddings
β βββ database.py # SQLite β animals and sightings
β βββ matcher.py # Cosine similarity for animal matching
β βββ seed.py # Demo data for the initial map (BrasΓlia, DF)
β βββ tracer.py # Trace logging + push to HF Hub
βββ db/
β βββ schema.sql # Database schema
βββ data/ # Runtime β SQLite database + photos + traces
βββ viralata.db
βββ photos/
βββ traces.jsonl
Limitations
- Vision AI via API β breed identification requires
HF_TOKENorNVIDIA_API_KEY. Without a key, registrations use generic data (breed "SRD / Domestic Shorthair"). - GPS on mobile β accuracy depends on the device. Indoors or with weak signal, coordinates may be imprecise.
- Matching is not foolproof β the 0.80 threshold is conservative to avoid false positives, but two very similar animals (e.g. two caramel SRDs) may get grouped together. The user reviews the candidates before confirming and can correct.
- Portuguese / English only β the interface is in Portuguese; the AI generates descriptions in English for embedding consistency.
Credits
- Meta β Llama 3.2 11B Vision Instruct (Llama 3.2 Community License).
- NVIDIA β Nemotron Omni 30B via NVIDIA NIM.
- Hugging Face β
sentence-transformers/all-MiniLM-L6-v2, Serverless Inference, Space hosting. - Leaflet.js β interactive map.
- Gradio β
gradio.Serverfor the custom frontend. - Lucide Icons β UI icons.
License
MIT for the application code. Models follow their own licenses β see the Meta (Llama 3.2) and NVIDIA (Nemotron Omni) model cards for full terms.
Built for BrasΓlia, DF β capital of Brazil β and any city that wants to map its stray animals. πΎ