1- #!/usr/bin/env python3
21"""
3- sam_faces/__init__.py — Face recognition and identity memory for AI assistants.
2+ sam-faces — Face recognition and identity memory for AI assistants.
43
5- Enroll known people with reference photos, then automatically identify faces
6- in inbound images — with names, confidence scores, and an llm_context string
7- ready to inject into any LLM prompt. 100% local, no cloud APIs.
4+ This package provides local face recognition capabilities for OpenClaw agents:
5+ - Enroll known people with reference photos
6+ - Identify faces in inbound images with confidence scores
7+ - Generate llm_context strings for enriched image descriptions
8+ - Draw bounding boxes and labels on photos for visualization
9+
10+ All operations run 100% locally via dlib/face_recognition. No cloud APIs.
11+
12+ Schema (SQLite):
13+ people(id, name, created_at)
14+ encodings(id, person_id, vector BLOB, note, added_at, crop_path)
15+ unknown_candidates(id, image_path, face_crop_path, detected_at, resolved, resolved_as)
16+
17+ Authors:
18+ - Sam Cox (https://github.com/jasonacox-sam)
19+ - Jason Cox (https://github.com/jasonacox)
820"""
921
1022__version__ = "1.0.0"
11- __author__ = "Sam Cox <sam@jasonacox.com>"
23+ __author__ = "Sam Cox (https://github.com/jasonacox-sam), Jason Cox (https://github.com/jasonacox)"
24+
25+ # Lazy imports - only load heavy dependencies when needed
26+ # Importing face_recognition at module load time triggers dlib init,
27+ # which can fail if pkg_resources is missing (Python 3.13+ without setuptools)
28+
29+
30+ def _lazy (name ):
31+ """Lazy module loader - imports on first attribute access."""
32+ import importlib
33+
34+ return importlib .import_module (f"sam_faces.{ name } " )
35+
1236
37+ # Database operations are lightweight (SQLite only) - safe to import eagerly
1338from .database import init_db , get_all_encodings , add_person , add_encoding
1439from .database import find_person_by_name , list_people , add_unknown
15- from .identify import identify , DEFAULT_THRESHOLD
16- from .enroll import enroll
40+
41+ # Heavy vision imports are deferred until actually used
42+ identify = None
43+ enroll = None
44+ visualize = None
45+ DEFAULT_THRESHOLD = 0.55
46+
47+
48+ def __getattr__ (name ):
49+ """Lazy load heavy vision modules on first access."""
50+ global identify , enroll , visualize , DEFAULT_THRESHOLD
51+ if name == "identify" :
52+ from .identify import identify as _identify , DEFAULT_THRESHOLD as _thresh
53+
54+ identify = _identify
55+ DEFAULT_THRESHOLD = _thresh
56+ return identify
57+ if name == "enroll" :
58+ from .enroll import enroll as _enroll
59+
60+ enroll = _enroll
61+ return enroll
62+ if name == "visualize" :
63+ from .visualize import visualize as _viz
64+
65+ visualize = _viz
66+ return visualize
67+ if name == "DEFAULT_THRESHOLD" :
68+ from .identify import DEFAULT_THRESHOLD as _thresh
69+
70+ DEFAULT_THRESHOLD = _thresh
71+ return DEFAULT_THRESHOLD
72+ raise AttributeError (f"module { __name__ !r} has no attribute { name !r} " )
73+
1774
1875__all__ = [
1976 "init_db" ,
2582 "add_unknown" ,
2683 "identify" ,
2784 "enroll" ,
85+ "visualize" ,
2886 "DEFAULT_THRESHOLD" ,
2987 "__version__" ,
30- ]
88+ ]
0 commit comments