Skip to main content

An app to organize photos

Project description

Yaffo - Photo Organizer

A Flask-based photo organization tool that uses EXIF metadata, face recognition, and duplicate detection to automatically organize and index photos.

Features

  • Photo Organization: Automatically organize and index photos by date using EXIF metadata
  • Face Detection & Recognition: Detect, group, and tag faces by person using InsightFace (SCRFD detection + ArcFace embeddings, on ONNX Runtime)
  • Duplicate Detection: Find duplicate photos using perceptual hashing
  • EXIF Metadata: Extract and display photo metadata
  • Location Support: Geocoding, reverse-geocoding, and time-correlation geotagging from neighboring photos
  • Auto-Labeling: Offline zero-shot classification (CLIP) tags photos against a user vocabulary
  • Automations: Scheduled and event-driven background behaviors (system-built and AI-generated)
  • AI Page Builder: Build custom pages from AI-generated, sandboxed widgets over your own photo data

Prerequisites

Quick Start

1. Clone and Setup

git clone <repository-url>
cd yaffo

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install -e .

2. Install Git Hooks

./hooks/install.sh

This installs pre-commit hooks that prevent accidental commit of API keys and secrets.

3. Configure the Data Directory

YAFFO_DATA_DIR is the root for the app's own state — the SQLite databases (yaffo.db, yaffo-queue.db), generated thumbnails, logs, and temp/trash. It defaults to the OS user-data dir (e.g. ~/Library/Application Support/yaffo on macOS); set it to override:

export YAFFO_DATA_DIR=/path/to/data

Your actual photo (media) directories are configured separately, in the app's Settings page — they aren't a fixed subfolder. The file sync / watcher scans the configured media dirs and indexes what it finds.

4. Run the Application

# Start the Flask web app
flask run

# In a separate terminal, start the background task host (spawn worker pool)
python -m yaffo.taskq.host

# Or launch the whole local stack (Flask + task host + watcher) at once
inv app-local

The app will be available at http://127.0.0.1:5000

Project Structure

yaffo/
├── yaffo/                    # Main application
│   ├── app.py               # Flask app factory
│   ├── common.py            # Configuration and paths
│   ├── db/                  # Database models and repositories
│   ├── routes/              # API endpoints
│   ├── templates/           # Jinja2 templates
│   ├── static/              # CSS, JavaScript
│   ├── utils/               # Utility functions
│   ├── background_tasks/    # Background task definitions
│   ├── taskq/               # SQLite-backed task queue + spawn worker host
│   ├── site_agents/         # AI page builder: agent, model clients, tools, schemas
│   └── scripts/             # CLI tools + db/ (init_db, dev migrations)
├── tests/                   # Python unit tests
├── yaffo_ui_tests/          # Playwright UI tests
├── hooks/                   # Git hooks
├── docs/                    # Design references (taskq, automations, page builder, video)
└── resources/               # ExifTool binaries + bundled face models

Development

Running Tests

# Python unit tests
pytest

# UI tests (requires app running)
cd yaffo_ui_tests
npm install
npm test

# UI tests in isolated environment
npm run test:isolated

Database

The app uses SQLite. The database file is stored at {YAFFO_DATA_DIR}/yaffo.db.

To reset the database:

rm /path/to/data/yaffo.db
flask run  # Will recreate on startup

Background Tasks

Background tasks (photo indexing, face detection, etc.) run on a small purpose-built queue (yaffo/taskq): a SQLite-durable queue plus a host process that supervises a pool of spawn-started worker children, so CPU-bound native ML inference (InsightFace/ONNX Runtime) runs in parallel, isolated, and crash-contained. See docs/development/task-queue.md.

# Start the task host with 4 workers, recycling each after 200 tasks
python -m yaffo.taskq.host --workers 4 --recycle 200

# Or via invoke
inv start-tasks --workers=4

Tests drive tasks synchronously by setting task_queue.immediate = True.

UI Testing

The project includes an AI-augmented UI testing framework. See yaffo_ui_tests/README.md for details.

cd yaffo_ui_tests

# Install dependencies
npm install
npx playwright install

# Run tests against running app
npm test

# Run tests in isolated environment (recommended)
npm run test:isolated

Environment Variables

Variable Description Default
YAFFO_DATA_DIR Root for app state (DBs, thumbnails, logs, temp) OS user-data dir (e.g. ~/Library/Application Support/yaffo); inv sets ~/Pictures for dev
FLASK_APP Flask application module yaffo.app:create_app
FLASK_ENV Flask environment development
ANTHROPIC_API_KEY Anthropic API key for the AI Page Builder and AI-generated automations. Optional override — the key is normally stored in the OS keychain (set via Settings); the env var wins when present (headless/CI). (unset; keychain used)

Git Hooks

The project includes pre-commit hooks to prevent accidental commit of secrets:

# Install hooks (run once after cloning)
./hooks/install.sh

The pre-commit hook scans for:

  • Anthropic API keys (sk-ant-...)
  • OpenAI API keys (sk-...)
  • Generic API key patterns

Licenses

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

yaffo-0.0.11.tar.gz (24.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

yaffo-0.0.11-py3-none-any.whl (24.4 kB view details)

Uploaded Python 3

File details

Details for the file yaffo-0.0.11.tar.gz.

File metadata

  • Download URL: yaffo-0.0.11.tar.gz
  • Upload date:
  • Size: 24.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for yaffo-0.0.11.tar.gz
Algorithm Hash digest
SHA256 6277e55fcaacc720af25382dab4c475bfb22ebb5bca13fc46e31f1a674be8230
MD5 4736a03f2b6fd2378e8681ab7026aaa0
BLAKE2b-256 f4bc853c9ed1f1eb6cb5679b19c11558dcbdc7d2194567f16663eb247c562468

See more details on using hashes here.

Provenance

The following attestation bundles were made for yaffo-0.0.11.tar.gz:

Publisher: release.yml on Jason-Turan0/yaffo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file yaffo-0.0.11-py3-none-any.whl.

File metadata

  • Download URL: yaffo-0.0.11-py3-none-any.whl
  • Upload date:
  • Size: 24.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for yaffo-0.0.11-py3-none-any.whl
Algorithm Hash digest
SHA256 fa13a06d258e1db8939a8767938e41f670330520ca94653f589d5ddd4e9b3c0f
MD5 cd4ffed6154ecfbc6dc8d1eba2dcbc03
BLAKE2b-256 63c9ca4626f9adca44ddedcf8d78dfc07fb955d2e867c175bd4481d745451fdf

See more details on using hashes here.

Provenance

The following attestation bundles were made for yaffo-0.0.11-py3-none-any.whl:

Publisher: release.yml on Jason-Turan0/yaffo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page