pawmap / README.md
sara.mesquita
adds readme and context
c33e98e
metadata
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_TOKEN or NVIDIA_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.Server for 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. 🐾