The family photo archive runs on Immich — self-hosted, AI-powered, with automatic album generation going back to 2008.
All photos are stored on the local NAS over NFS — around 180 GB of data. The Immich server (vm01img) itself has no local photo storage; it only holds the application and database. This means the VM can be rebuilt at any time without touching the photo files.
The PostgreSQL database holds metadata, EXIF data, face embeddings, and CLIP vectors — around 1.2 GB for 80,000+ photos. It is backed up daily via a separate Ansible job.
Face recognition runs on the AI servers (AI1 or AI2), not on the Immich VM itself. CLIP-based semantic search allows finding photos by describing what's in them — "sunset at the lake" or "birthday cake" — without any manual tagging.
The archive is accessible at photos.alpacai.org with SSL, shared between family members via Immich's built-in sharing.
A custom Python script processes the entire photo archive and generates albums automatically — going back to 2008. It runs in four modules, each with its own logic, and uses two local AI models for decision-making.
Based on Swiss school holiday weeks (ISO weeks), the script identifies holiday periods and checks whether the family was at home or travelling — using GPS data when available, or visual analysis when not. Titles are generated in German with regional precision ("Sommerferien in der Toskana").
Each family member's birthday is checked against the archive. The AI distinguishes a birthday party from a coincidental holiday. In the birth year of each child, it also detects the birth itself and extends the album to include the following days at the hospital.
Christmas (24–26 December), New Year's Eve, and Swiss National Day (1 August) are checked separately. A minimum of 15 photos is required for an album to be created.
For every remaining day with 15 or more photos, the AI analyses a sample of 8 images and decides: is this a notable event or just daily life? Recognisable landmarks are identified automatically (Eiffel Tower → Paris, Europapark roller coaster → Europapark).
When an album would exceed 150 photos, a vision model (moondream) scores each image from 1 to 5 — sharpness, composition, faces visible — and selects the best ones. Group photos, individual portraits, and landscapes are weighted differently depending on the album type.
Already-processed periods are tracked locally, so the script can be re-run at any time without creating duplicates. Albums already covering a period block later modules from creating overlapping ones.