Automated WhatsApp photo & video backup with intelligent face recognition
Never miss a moment with your loved ones — DMAF watches your WhatsApp groups,
recognizes the faces you care about in photos and videos, and backs them up to Google Photos automatically.
Set it up once. After that: zero LLM tokens, minimal cloud costs, fully autonomous.
OpenClaw 🦞 • Features • Quick Start • How It Works • Configuration • Backends • Contributing
DMAF is designed to be set up and operated entirely by an AI agent. If you use OpenClaw, you can go from zero to a working pipeline with a single prompt.
Install the DMAF skill from ClaWHub (or copy deploy/openclaw-skill/ to your skills directory), then just say:
"Set up DMAF for me. My GCP project ID is
[your-project]and my WhatsApp is already connected to OpenClaw."
Your agent will walk through the full setup: GCP project, service account, GCS buckets, reference photos, config, the media sync cron, and the Cloud Scheduler — reading deploy/setup-secrets.md as its guide.
💡 After setup: zero LLM tokens. The ongoing pipeline is a system cron + Cloud Run job — pure infrastructure, no AI calls, no ongoing API cost.
Also friendly for:
- 🤖 Coding agents (Claude Code, Copilot, Cursor) —
AGENTS.mdgives full architecture context, test patterns, and common pitfalls - 🦾 MCP clients (Claude Desktop, Claude Code, Cursor, Windsurf) — install the MCP server and your AI can
trigger_scan(),get_status(),add_person()and more — no gcloud knowledge needed
|
|
|
|
|
|
- Install the DMAF skill:
clawhub install dmaf— or browse it at clawhub.ai/skills/dmaf - Make sure your WhatsApp channel is linked in OpenClaw
- Say to your agent:
Set up DMAF for me. My GCP project ID is [your-project-id] and my WhatsApp
is already connected to OpenClaw. Walk me through everything.
Your agent reads deploy/setup-secrets.md and deploy/openclaw-integration.md to guide you step by step.
✅ Zero ongoing tokens. Once setup is done, DMAF runs entirely on a system cron + Cloud Run — no LLM involved, no AI API costs — only the minimal GCP infrastructure you already pay for.
- Python 3.10 or higher
- Google Cloud project with Photos Library API enabled
- WhatsApp media access via one of:
- OpenClaw integration (iPhone/Android) — ⭐ Recommended, see
deploy/openclaw-integration.md - WhatsApp Desktop + rclone — Cross-platform
- Android direct sync — FolderSync Pro, Syncthing
- OpenClaw integration (iPhone/Android) — ⭐ Recommended, see
git clone https://github.com/yhyatt/DMAF.git
cd DMAF
python -m venv .venv && source .venv/bin/activate
# Choose your face recognition backend:
pip install -e ".[auraface]" # ⭐ Apache 2.0 — commercial OK, zero false positives
pip install -e ".[insightface]" # High accuracy, non-commercial only
pip install -e ".[face-recognition]" # CPU-optimized, easiest setup-
Add reference photos of the people to recognize:
data/known_people/ ├── Alice/ │ ├── photo1.jpg │ └── photo2.jpg └── Bob/ └── photo1.jpg -
Configure:
cp config.example.yaml config.yaml # Edit config.yaml — set watch_dirs and recognition backend -
Run:
dmaf --config config.yaml # Or: python -m dmaf --config config.yaml -
Cloud deployment (GCS + Cloud Run, runs on a schedule, scales to zero): → Follow
deploy/setup-secrets.md
graph LR
A[📱 WhatsApp Groups] -->|OpenClaw captures| B[💾 GCS Staging Bucket]
B -->|Cloud Scheduler hourly| C[☁️ Cloud Run Job]
C --> D{🔍 Face Found?}
D -->|Yes — photo or video| E[📸 Upload to Google Photos]
D -->|No match| F[⏭️ Skip]
E --> G[🗄️ Firestore Dedup]
F --> G
G -->|path + content SHA256| H[🚫 Never Reprocess]
- Capture — OpenClaw intercepts WhatsApp group media and saves it locally; a system cron (zero LLM tokens) uploads it to GCS every 30 min
- Schedule — Cloud Scheduler triggers the Cloud Run job hourly — no agent, no AI cost
- Load — Reference photos downloaded from GCS bucket at job startup
- Detect — Each file is scanned: images once, videos sampled at 1–2fps with early exit on first match
- Upload — Matched photos and full video clips are uploaded to Google Photos
- Deduplicate — Two-layer check: (1) path-based Firestore lookup catches already-seen GCS paths; (2) content SHA-256 check catches the same photo arriving via multiple groups or sync paths — face recognition is skipped entirely for known content
watch_dirs:
- "gs://your-project-whatsapp-media/" # GCS staging bucket (cloud)
- "/path/to/WhatsApp/Images" # Local directory (dev)
known_people_gcs_uri: "gs://your-project-known-people"
recognition:
backend: "auraface" # auraface | insightface | face_recognition
tolerance: 0.5 # 0.0 (strictest) → 1.0 (loosest)
min_face_size_pixels: 20
google_photos_album_name: "Family Faces" # recommended: keeps DMAF uploads separate from camera-roll backup
alerting:
enabled: true
timezone: "America/New_York" # IANA name — used in alert email timestamps
recipients: ["you@example.com"]Full annotated template: config.example.yaml | Cloud template: config.cloud.example.yaml
| Feature | AuraFace ⭐ | InsightFace | face_recognition (dlib) |
|---|---|---|---|
| License | ✅ Apache 2.0 (commercial OK) | MIT | |
| False Positive Rate | ✅ 0.0% 🛡️ | 1.87% | ~11% |
| Accuracy (TPR) | 80–85% | 82.5% | 92.5% |
| Speed | ⚡ Fast (12× vs dlib) | ⚡ Fastest | 🐢 Slow |
| GPU Support | ✅ CUDA | ✅ CUDA | ❌ CPU only |
| Best For | 🏆 Production | Research | Development |
Use AuraFace for production — zero false positives means zero privacy violations. Commercial license, no restrictions.
Adding a new backend is simple:
# src/dmaf/face_recognition/your_backend.py
def load_known_faces(known_root: str, **params): ...
def best_match(known_faces, test_image, **params): ...Register in factory.py and you're done. See existing backends for examples.
DMAF/
├── src/dmaf/
│ ├── __main__.py # CLI entrypoint + Uploader (on_match / on_match_video)
│ ├── config.py # Pydantic settings — all fields with defaults + docs
│ ├── watcher.py # Core scan loop + file processing helpers
│ ├── video_processor.py # iter_frames generator, find_face_in_video (early exit)
│ ├── gcs_watcher.py # GCS helpers: list, download, cleanup
│ ├── database.py # SQLite (local) + Firestore (cloud) dedup backends
│ ├── known_refresh.py # Auto-refresh training images
│ ├── alerting/ # Email alert batching and templates
│ └── face_recognition/ # Backend factory: AuraFace, InsightFace, dlib
├── deploy/
│ ├── setup-secrets.md # 🔑 All credentials setup, start here
│ ├── openclaw-integration.md # 🦞 OpenClaw media sync guide
│ ├── openclaw-skill/ # 🦞 Installable OpenClaw skill (ClaWHub)
│ ├── mcp-setup.md # 🔌 MCP server setup (Claude Desktop / Code / Cursor)
│ └── README.md # GCP deployment walkthrough
├── tests/ # pytest — mirrors src/dmaf structure
├── AGENTS.md # 🤖 Coding agent guide (Claude, Copilot, Cursor)
├── config.example.yaml # Annotated config template (local dev)
└── config.cloud.example.yaml # Annotated config template (cloud deployment)
pip install -e ".[dev,all]"
pre-commit install # ruff + mypy before every commit
pytest tests/ -v # Run tests
mypy src/dmaf # Type check
ruff check src/ tests/ # LintSee AGENTS.md for architecture decisions, mock patterns, and CI rules.
- Phase A: Core bug fixes (RGB/BGR, caching, retry logic) ✅
- Phase B: Project restructuring (src layout, Pydantic) ✅
- Phase C: Unit tests (286 tests, 75%+ coverage) ✅
- Phase D: Face recognition benchmarking & LOOCV validation ✅
- Phase D+: Advanced detection tuning & FPR analysis ✅
- Phase E: CI/CD (GitHub Actions, automated testing) ✅
- Phase F-prep: Observability & auto-refresh (alerts, score tracking, AuraFace) ✅
- Phase F: Cloud deployment (GCS + Cloud Run + Firestore) ✅
- Phase G: Documentation, OpenClaw skill, open-source ready ✅
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License — see LICENSE for details.
- AuraFace — Apache 2.0 face recognition model
- InsightFace — Deep learning face analysis
- face_recognition — dlib-based recognition
- OpenClaw — AI agent platform with WhatsApp integration
- Google Photos Library API
- Watchdog — File system monitoring
Made with 🦀 by yhyatt