A privacy-focused, all-local photo organization and search application. Pensieve allows you to search your entire photo collection entirely on-device, without cloud uploads. This app allows image-to-image similarity search and text-to-image search.
This app makes use of React and Typescript for frontend and Python with Fastapi for the backend. For the image-to-image similarity search, we use Google's SigLIP model. The embeddings are saved in FAISS(siglip_index.faiss) and they have metadata stored in JSON format to list the file paths for each image. The text-to-image model runs using CLIP. The embeddings are stored in FAISS(clip_index.faiss). Both of these are open-source modles and run locally on the user's machine and can easily run on CPU.
- Python 3.10+ with the ability to create virtual environments
- Node.js 18+ (Vite dev server) and npm
- git (for cloning)
cd backendpython -m venv .venv && source .venv/bin/activatepip install --upgrade pip && pip install -r requirements.txt- Point Pensieve at your library:
export IMAGE_DIR="/absolute/path/to/your/photos" - Pre-download models (optional but avoids first-request lag):
python download_models.py - Build indexes (run once per new library):
python pipeline.pyfor image-to-image embeddings (SigLIP →siglip_index.faiss)python clip_search.pyto populate the CLIP text index (clip_index.faiss)
- Start the API:
fastapi run app.py
cd frontendnpm installnpm run devand open the printed URL (defaulthttp://localhost:5173)
- Re-run
python backend/pipeline.pyand the CLIP indexing step whenever you add or delete photos. - The
/scanadmin route updates metadata and embeddings without wiping existing vectors. - FAISS index files live alongside the backend (
siglip_index.faiss,clip_index.faiss,faces*.index) so back them up with your photos.
Text-To-Image Search
Image-To-Image Search
I really wanted to use mps in this project on my Mac but it causes lots of issues with FAISS