AI News HubLIVE
In-site rewrite5 min read

AI Powered Photo Gallery Without the Cloud

Best Photo Picker is a local-first, open-source photo curation tool that uses AI to score photos on sharpness, lighting, faces, and composition. It runs entirely on your machine with no cloud uploads, supports smart deduplication, face recognition, and temporal diversity, and offers a web UI and native macOS app.

SourceHacker News AIAuthor: anonu

Uh oh!

There was an error while loading. Please reload this page.

Notifications You must be signed in to change notification settings

Fork 0

Star 1

BranchesTags

Open more actions menu

Folders and files

NameName

Last commit message

Last commit date

Latest commit

History

2 Commits

2 Commits

.githooks

.githooks

.github

.github

bpp

bpp

desktop

desktop

docs

docs

examples/plugin_example

examples/plugin_example

scripts

scripts

tests-e2e

tests-e2e

tests-js

tests-js

tests

tests

.dockerignore

.dockerignore

.eslint-globals.json

.eslint-globals.json

.gitattributes

.gitattributes

.gitignore

.gitignore

.pre-commit-config.yaml

.pre-commit-config.yaml

.prettierignore

.prettierignore

.prettierrc.json

.prettierrc.json

CHANGELOG.md

CHANGELOG.md

CODE_OF_CONDUCT.md

CODE_OF_CONDUCT.md

CONTRIBUTING.md

CONTRIBUTING.md

Dockerfile

Dockerfile

LICENSE

LICENSE

MANIFEST.in

MANIFEST.in

MODEL_POLICY.md

MODEL_POLICY.md

NOTICE.txt

NOTICE.txt

README.md

README.md

SECURITY.md

SECURITY.md

bpp-server.spec

bpp-server.spec

eslint.config.js

eslint.config.js

launch.command.template

launch.command.template

package-lock.json

package-lock.json

package.json

package.json

playwright.config.mjs

playwright.config.mjs

pyproject.toml

pyproject.toml

sample_config.yaml

sample_config.yaml

tsconfig.json

tsconfig.json

vitest.config.mjs

vitest.config.mjs

Repository files navigation

Drowning in 15,000 family photos? Apple Photos and Google Photos bury your best shots in their feed. Best Photo Picker runs entirely on your machine, scores every photo on sharpness, lighting, faces, and composition, and lets you curate the perfect 50 in minutes — no cloud, no subscription, no compromise.

It's the only photo tool that auto-scores your whole library for curation without uploading anything, then clusters near-duplicates and lets you boost specific people so the final pick favors the faces that matter — your kid, for the grandparents.

Try it in 30 seconds — no photos needed:

pip install "bppicker[web]" && bpp demo

Generates a sample library, runs the full UI locally, and quits cleanly when you close the tab. Nothing leaves your machine.

By Arkalogy — a PM-directed, AI-built product; the architectural decisions are captured in docs/adr/. Why & how it was built →

For an annotated walkthrough of the full workflow — import → adjust → pick → export — plus the side surfaces (faces, calendar, map, duplicates), see docs/quickstart-gallery.md.

📣 Found a bug or have a feature idea? Open an issue · Start a discussion · Contributing guide. Security issues: please use private vulnerability reporting, not a public issue.

Why Best Photo Picker?

Best Photo Picker Apple Photos Google Photos Lightroom digiKam

Local-first / runs offline ✅ ⚠️ iCloud-coupled ❌ cloud ⚠️ cloud sync ✅

Auto-scores photos for picking ✅ ❌ ⚠️ "Memories" ⚠️ flags only ❌

Boost picks by named person ✅ ⚠️ ⚠️ ❌ ❌

Near-duplicate deduplication ✅ ⚠️ ⚠️ ❌ ✅

Free + open source ✅ MIT ❌ ❌ ❌ $120/yr ✅ GPL

No account / no subscription ✅ ❌ ❌ ❌ ✅

Optional LAN sharing w/ device pairing ✅ ❌ ❌ ❌ ❌

If you live in the Apple/Google ecosystem and your collection fits their feeds, those tools work great. bpp exists for the case they're bad at: you have thousands of photos of a specific subject — your kid, your dog, last summer's trip — and you want to find the actual best fifty without uploading anything anywhere.

Features

Quality scoring — sharpness, exposure, face detection (YuNet + SCRFD + BlazeFace + MediaPipe + dlib), composition

Smart deduplication — perceptual hashing (dHash + aHash) and CLIP semantic similarity

Temporal diversity — per-day caps and monthly coverage for balanced selection

Face recognition — automatic clustering, per-person smart albums, merge, dismiss, reassign, drag-to-fix mis-detected bboxes

Library management — import by copying to managed library with SHA-256 dedup

Album system — manual + 19 smart album types (person, time, score, duplicates, pets, etc.)

Interactive web UI — real-time slider tuning, photo grid, lightbox, compare view, batch operations

Desktop app — native macOS app via Tauri v2 (wraps the web UI in a native window)

Soft delete — 30-day recovery, Recently Deleted album

Demo mode — try instantly with generated sample photos

Privacy — local-first, no telemetry, no analytics. The few network calls bpp makes (model downloads on first analyze, OpenStreetMap tiles when you open the Map view, update checks against GitHub Releases, optional LAN sharing, optional pip install of extra features) are all enumerated below and individually disclosable; nothing about your library is ever sent.

Quick Start

Install

Requires Python 3.11 (3.12+ is not yet supported — it's pinned to match the desktop sidecar). On macOS, Homebrew ships a newer Python by default; install 3.11 with brew install [email protected] or pyenv, or use the no-Python desktop app below.

Recommended — pipx keeps bpp in its own environment and makes updating one command:

pipx install "bppicker[web]"

Update to the latest release later:

pipx upgrade bppicker

Plain pip works too:

pip install "bppicker[web]"

Optional: face recognition

pip install "bppicker[web,faces]"

Optional: HEIC support

pip install "bppicker[heic]"

Most ML-powered features (face recognition, NudeNet, RAW import, HEIC, AI inpainting) install on demand from Settings → Advanced → ML Models in the running app, or you can pre-install everything at once with pip install "bppicker[heic,faces,raw,nudity,inpaint]".

Desktop app (macOS, Apple Silicon)

Prefer a dock icon over a terminal? Each release ships a standalone Mac app. No Python, no terminal:

Download BestPhotoPicker-macOS-arm64.dmg (always the latest release).

Double-click the .dmg and drag Best Photo Picker into Applications.

Open it from Applications or Spotlight.

The app is signed with an Apple Developer ID and notarized by Apple, so it opens on double-click — no security warning. To update, download the newer .dmg the same way; your photo library and settings live outside the app and carry over untouched.

Apple Silicon (M1/M2/M3 and later) only. On an Intel Mac, or on Windows/Linux, use the pipx install "bppicker[web]" path above.

Try the Demo

bpp demo

Generates sample photos and launches the web UI — no configuration needed.

Library Mode (Recommended)

Start the photo management server (default library: ~/Pictures/BestPhotoPicker)

bpp serve

Or specify a custom library path

bpp serve --library ~/Photos/2024

Open http://127.0.0.1:5001 in your browser. Import folders, adjust scoring weights with sliders, and export your curated selection.

CLI Mode (Batch Processing)

One-shot: analyze + select best 50 photos

bpp run --input ~/Photos/MyKid --k 50 --out ~/curated --gallery

Or step-by-step:

bpp analyze --input ~/Photos/MyKid --out ~/workdir bpp select --workdir ~/workdir --k 50 --out ~/curated --gallery

How It Works

Import → Analyze → Score → Deduplicate → Select → Export

Import: photos copied to managed library with SHA-256 dedup

Analyze: parallel feature extraction (blur, exposure, faces, composition) cached in SQLite

Score: weighted combination of sub-scores, tunable in real-time via sliders

Deduplicate: perceptual hash clustering removes burst duplicates; optional CLIP semantic dedup

Select: greedy selection with per-day caps and monthly coverage for temporal diversity

Export: copy/hardlink/symlink selected photos with optional HTML gallery

Web UI

Feature Description

Photo grid Thumbnail grid with score badges, zoom control, sort & filter

Lightbox Full-size viewer with keyboard navigation

Sliders Real-time weight tuning (blur, exposure, face, composition)

BPP Picks Sidebar sub-item picks best K photos across the full library; toolbar chip filters picks in the current album/view

Albums Manual and smart albums (by time, score, person)

Faces Auto-clustered face detection with merge, dismiss, and per-person albums

Batch ops Multi-select with Cmd/Ctrl-click, bulk include/exclude/favorite

Import Drag folders or archives into the library

Export Copy or link selected photos to an output directory

Tuning Knobs

Parameter Default Description

blur_weight 0.30 Weight for sharpness in aggregate score

exposure_weight 0.20 Weight for exposure quality

face_weight 0.35 Weight for face detection & framing

composition_weight 0.15 Weight for composition (rule of thirds)

max_long_side 1024 Downscale images to this before analysis

hash_distance_threshold 10 dHash Hamming distance for "same" image

time_window_seconds 15 Cluster burst photos within this window

max_per_day 3 Max selected photos per calendar day

min_per_month 1 Try to include at least 1 per month

Hardware

bpp runs all ML inference on CPU by default. ONNX-based models (SCRFD face detection, CLIP semantic search, YOLOv11n pet detection) can opt into hardware acceleration through the BPP_ONNX_PROVIDERS env var:

Apple Silicon (M1/M2/M3) — use the Apple Neural Engine via CoreML

BPP_ONNX_PROVIDERS="CoreMLExecutionProvider,CPUExecutionProvider" \ bpp serve --library ~/Pictures/BestPhotoPicker

NVIDIA GPU (Linux) — install onnxruntime-gpu first

pip uninstall -y onnxruntime && pip install onnxruntime-gpu BPP_ONNX_PROVIDERS="CUDAExecutionProvider,CPUExecutionProvider" \ bpp serve --library ~/Pictures/BestPhotoPicker

Windows DirectML

BPP_ONNX_PROVIDERS="DmlExecutionProvider,CPUExecutionProvider" \ bpp serve --library ~/Pictures/BestPhotoPicker

CPU is always appended as the final fallback so a missing provider in your wheel falls through cleanly with a warning rather than crashing. Ordering matters — providers are tried in the order listed.

Tested vs supported

Surface Tested in CI Supported Notes

macOS arm64 (M1/M2/M3) — CPU yes (dev box) yes Primary dev target. Tauri desktop app ships only this.

Linux x86_64 — CPU yes (ubuntu-latest) yes Default for PyPI install.

Linux arm64 — CPU no yes Docker image builds; runtime not exercised in CI.

Windows — CPU no yes Code path exists; never run end-to-end. Reports welcome via GitHub issues.

macOS arm64 — CoreMLExecutionProvider (ANE) no yes Code path exists. Expected 5-10× face inference speedup; correctness depends on the specific ONNX graph and ONNX Runtime version.

Linux x86_64 — CUDAExecutionProvider no yes Requires pip install onnxruntime-gpu (replaces base onnxruntime). Free-tier CI doesn't have a GPU runner.

Windows — DmlExecutionProvider no yes Same caveat as Windows CPU — code path exists, no end-to-end run.

"Supported" means the code path accepts the configuration and shouldn't crash; report bugs via GitHub Issues if it does. "Tested in CI" means we run the full test suite on every push for that surface. Anything between the two is on the user's risk surface — your hardware, your driver stack, your call. We'd love to expand the tested column as users report working setups; PRs welcome that add matrix entries to .github/workflows/ci.yml.

Throughput tuning

Face extraction is single-threaded per subprocess by default (_face_extract_workers=1). On a 6,000-photo library that's ~50 min on Apple Silicon (roughly 0.5 s/photo). Two config knobs let operators trade RAM for time:

settings table or YAML config

_face_extract_workers: 4 # number of parallel workers _face_extract_pool: process # "process" | "thread"

Recommended combos:

Setup workers pool Expected throughput Peak RAM

Default (safe everywhere) 1 thread 1× baseline (~50 min / 6k photos) ~700 MB

Power user, 16+ GB RAM 4 process ~3-4× (~13 min / 6k photos) ~3 GB

Measured on Apple M-series; results vary by photo resolution and system load.

The process pool is the only memory-safe parallel option — there

[truncated for AI cost control]

AI Powered Photo Gallery Without the Cloud | AI News Hub