Skip to content

Facial Recognition

Lychee can automatically detect faces in your photos, group similar-looking faces together, and let you label them as People. Once people are tagged you can browse “all photos of X” the same way you browse albums or tags, and even build Person Albums — smart albums that match one or more people.

All of the machine-learning work (face detection, embeddings, clustering, selfie matching) runs in a dedicated Lychee-Facial-Recognition microservice, kept separate from the main PHP application so the heavier workload doesn’t run on your gallery server.

  • Auto-scan on upload — newly uploaded photos are automatically queued for face detection once both AI Vision and facial recognition are enabled.
  • Detection — the AI Vision service finds faces in each photo and returns bounding boxes plus an embedding (a numeric “fingerprint”) for each face.
  • Clustering — faces that aren’t yet linked to a person are grouped into clusters of similar-looking faces, so you can label a whole group at once instead of one face at a time.
  • Overlays — when viewing a photo, detected faces are shown as overlays. Press P to toggle their visibility.
  • Person management — create, rename, merge, and delete people from the People page.
  • Assign faces — assign an individual detected face, or a whole face cluster, to a person.
  • Dismiss faces — mark false-positive detections as dismissed so they stop appearing for review; admins (or photo owners, depending on the permission mode) can also purge dismissed faces in bulk.
  • Person Albums — smart albums that automatically include every photo containing one or more chosen people (matched with AND/OR logic), the same way tag-based smart albums work.
  • Searchable people — people can be excluded from search results individually (the ai_vision_face_person_is_searchable_default setting controls the default for newly created people).

Users can link a Person record to their own account (“claiming”), which is useful for letting people find themselves automatically:

  • Manual claim — pick yourself from the People list.
  • Claim by selfie — upload a selfie; Lychee forwards it to the AI Vision service’s matching endpoint and automatically claims the best-matching person if the match confidence is above ai_vision_face_selfie_confidence_threshold (default 0.8). The uploaded selfie itself is discarded immediately after matching — it is never stored.
  • A person can only be claimed by one user at a time, and (unless you’re an admin) you can’t claim a second person once you already have one linked.
  • Whether non-admin users may claim people at all is controlled by the ai_vision_face_allow_user_claim setting; admins can always claim/unclaim/merge regardless.

Who can see and manage faces is controlled by a single setting, ai_vision_face_permission_mode:

Operationpublicprivateprivacy-preservingrestricted (default)
View People pageguestlogged-in usersphoto/album owner + adminadmin only
View face overlaysalbum accesslogged-in usersphoto/album owner + adminphoto/album owner + admin
Create/edit a personlogged-in userslogged-in usersphoto/album owner + adminadmin only
Assign a facelogged-in userslogged-in usersphoto/album owner + adminadmin only
Trigger a scanlogged-in userslogged-in usersphoto/album owner + adminphoto/album owner + admin
Claim a personlogged-in userslogged-in usersphoto/album owner + adminphoto/album owner + admin
Merge peoplelogged-in userslogged-in usersphoto/album owner + adminadmin only
Dismiss a facephoto owner + adminphoto owner + adminphoto/album owner + adminphoto owner + admin
Batch face operationslogged-in userslogged-in usersphoto/album owner + adminadmin only
View people on an albumalbum accesslogged-in usersphoto/album owner + adminphoto/album owner + admin

The feature is controlled by a AI Vision category of Settings, all disabled/conservative by default:

SettingDescriptionDefault
ai_vision_enabledMaster toggle for the whole AI Vision subsystem (also gates NSFW classification).off
ai_vision_face_enabledToggle facial recognition specifically. Requires ai_vision_enabled.off
ai_vision_face_permission_modeSee Permission modes.restricted
ai_vision_face_selfie_confidence_thresholdMinimum match confidence (0.0–1.0) to auto-link via selfie claim.0.8
ai_vision_face_person_is_searchable_defaultDefault searchability for newly created people.on
ai_vision_face_allow_user_claimAllow non-admin users to claim a person.on
ai_vision_face_overlay_enabledMaster toggle for face overlays/bounding boxes in the UI.on
ai_vision_face_overlay_default_visibilityWhether overlays are shown or hidden by default when opening a photo (toggle with P).visible
ai_vision_face_recognition_warningShow the dismissable legal warning on the Face Clusters/Maintenance pages.on

Facial recognition requires running the Lychee-Facial-Recognition service (FastAPI + DeepFace) alongside Lychee, then pointing Lychee at it via the AI_VISION_FACE_URL and AI_VISION_FACE_API_KEY environment variables — see AI Vision in the configuration reference. The diagnostics page reports whether the service is reachable and correctly configured.

The service is configured independently, via its own .env file (copy .env.example to .env). All of its variables are prefixed VISION_FACE_; missing required variables produce a formatted error at startup instead of a raw traceback.

VariableDescription
VISION_FACE_LYCHEE_API_URLLychee base URL used for callbacks (no trailing slash).
VISION_FACE_API_KEYShared API key — validated on inbound requests from Lychee and sent on outbound callbacks. Must match AI_VISION_FACE_API_KEY in Lychee’s own .env.
VariableDefaultDescription
VISION_FACE_VERIFY_SSLtrueVerify SSL certificates on Lychee callbacks. Set to false for self-signed certs.
VISION_FACE_SKIP_LYCHEE_CHECKfalseSkip the Lychee connectivity check at startup (useful for local dev).
VariableDefaultDescription
VISION_FACE_MODEL_NAMEArcFaceDeepFace recognition model.
VISION_FACE_DETECTOR_BACKENDretinafaceDeepFace detector backend (retinaface, mtcnn, opencv, ssd).
VISION_FACE_MODEL_ROOT/root/.deepfaceRoot directory for DeepFace model weights (DEEPFACE_HOME).
VariableDefaultDescription
VISION_FACE_DETECTION_THRESHOLD0.5Bounding-box confidence filter.
VISION_FACE_MATCH_THRESHOLD0.5Cosine-similarity cutoff for selfie matching and suggestions.
VISION_FACE_RESCAN_IOU_THRESHOLD0.5IoU threshold for bounding-box matching on re-scan.
VISION_FACE_MAX_FACES_PER_PHOTO10Maximum faces included in a callback payload.
VISION_FACE_MIN_FACE_SIZE_PIXELS0Minimum face size in pixels; 0 disables this filter.
VISION_FACE_BLUR_THRESHOLD0.5Laplacian variance threshold; blurry faces below this are discarded.
VISION_FACE_CLUSTER_EPS0.6DBSCAN epsilon (max cosine distance) used for face clustering.
VariableDefaultDescription
VISION_FACE_STORAGE_BACKENDsqlitesqlite or pgvector.
VISION_FACE_STORAGE_PATH/data/embeddingsSQLite database directory.
VISION_FACE_PG_HOSTlocalhostPostgreSQL host (pgvector backend only).
VISION_FACE_PG_PORT5432PostgreSQL port.
VISION_FACE_PG_DATABASEai_visionPostgreSQL database.
VISION_FACE_PG_USERai_visionPostgreSQL user.
VISION_FACE_PG_PASSWORDemptyPostgreSQL password.
VISION_FACE_PHOTOS_PATH/data/photosShared volume mount where the service reads photo files from. Mount Lychee’s LYCHEE_UPLOADS directory here, read-only.

Detection and clustering jobs are processed asynchronously via a persistent queue shared across all worker processes. Requests that arrive when the queue is full receive 429 Too Many Requests.

VariableDefaultDescription
VISION_FACE_QUEUE_BACKENDdatabasedatabase (uses VISION_FACE_STORAGE_BACKEND) or redis.
VISION_FACE_QUEUE_MAX_SIZE100Maximum number of pending jobs.
VISION_FACE_REDIS_HOSTlocalhostRedis host (redis backend only).
VISION_FACE_REDIS_PORT6379Redis port.
VISION_FACE_REDIS_PASSWORDemptyRedis password.
VISION_FACE_REDIS_DB0Redis logical database index.
VariableDefaultDescription
VISION_FACE_THREAD_POOL_SIZE1Inference threads; also sets the number of queue worker tasks.
VISION_FACE_WORKERS1Uvicorn worker processes.
Terminal window
docker run --rm \
--env-file .env \
-v /path/to/lychee/public/uploads:/data/photos:ro \
-v ai-vision-embeddings:/data/embeddings \
-p 8000:8000 \
lychee-ai-vision

The container exposes interactive API docs at /docs and a health check at /health once running.

CommandDescription
php artisan lychee:scan-facesEnqueue all unscanned photos for face detection. Use --album={id} to limit to the direct photos of one album.
php artisan lychee:rescan-failed-facesRe-enqueue photos whose scan previously failed. Add --stuck-pending (with --older-than=<minutes>, default 60) to also reset scans stuck in “pending” back to unscanned.