facekey 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ * text=auto eol=lf
2
+ *.png binary
3
+ *.jpg binary
4
+ *.onnx binary
@@ -0,0 +1,30 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .installed.cfg
9
+
10
+ # Virtual envs
11
+ .venv/
12
+ venv/
13
+ env/
14
+
15
+ # Tooling
16
+ .pytest_cache/
17
+ .ruff_cache/
18
+ .mypy_cache/
19
+ .coverage
20
+ htmlcov/
21
+
22
+ # Editors / OS
23
+ .vscode/
24
+ .idea/
25
+ .DS_Store
26
+ Thumbs.db
27
+
28
+ # facekey local data (enrolled templates, downloaded model cache)
29
+ .facekey/
30
+ *.facekey.json
facekey-0.0.1/LICENSE ADDED
@@ -0,0 +1,36 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Adm145
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ NOTE ON BUNDLED MODEL WEIGHTS
26
+
27
+ This MIT license covers the facekey source code only. facekey downloads and
28
+ uses third-party model weights at runtime, which carry their own licenses:
29
+
30
+ * InsightFace "buffalo_l" / "buffalo_s" recognition and detection models are
31
+ released by their authors for NON-COMMERCIAL RESEARCH USE ONLY. Commercial
32
+ use requires a separate license from InsightFace
33
+ (recognition-oss-pack@insightface.ai). See EMBEDDER LICENSING in README.md.
34
+
35
+ You are responsible for complying with the license of whichever model backend
36
+ you choose to run.
facekey-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,174 @@
1
+ Metadata-Version: 2.5
2
+ Name: facekey
3
+ Version: 0.0.1
4
+ Summary: Face-ID-style unlock for your app: enroll a face from several angles, then authenticate against a live camera frame.
5
+ Project-URL: Homepage, https://github.com/Adm145/facekey
6
+ Project-URL: Issues, https://github.com/Adm145/facekey/issues
7
+ Author: Adm145
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: authentication,biometrics,face id,face recognition,face unlock,insightface,liveness
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Image Recognition
20
+ Classifier: Topic :: Security
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: insightface>=0.7.3
23
+ Requires-Dist: numpy>=1.21
24
+ Requires-Dist: onnxruntime>=1.15
25
+ Requires-Dist: opencv-python-headless>=4.7
26
+ Requires-Dist: platformdirs>=3.0
27
+ Provides-Extra: camera
28
+ Requires-Dist: opencv-python>=4.7; extra == 'camera'
29
+ Provides-Extra: crypto
30
+ Requires-Dist: cryptography>=41; extra == 'crypto'
31
+ Provides-Extra: dev
32
+ Requires-Dist: build>=1.0; extra == 'dev'
33
+ Requires-Dist: pytest>=7; extra == 'dev'
34
+ Requires-Dist: ruff>=0.4; extra == 'dev'
35
+ Provides-Extra: gpu
36
+ Requires-Dist: onnxruntime-gpu>=1.15; extra == 'gpu'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # facekey
40
+
41
+ > ⚠️ **Alpha — the API will change.** Pin an exact version if you depend on it.
42
+
43
+ Face-ID-style unlock for your Python app. Enroll a face from a few angles, then
44
+ on each unlock grab a frame from the camera, compare it to the enrolled
45
+ template, and grant access on a match.
46
+
47
+ ```python
48
+ from facekey import FaceLock
49
+
50
+ lock = FaceLock() # single enrolled face, stored under a per-user data dir
51
+
52
+ # one-time enrollment (needs a camera; pip install "facekey[camera]")
53
+ lock.run_enrollment(camera=0, on_prompt=print)
54
+
55
+ # later, guard something
56
+ if lock.unlock(camera=0, timeout=5):
57
+ reveal_secret()
58
+ else:
59
+ fall_back_to_password()
60
+ ```
61
+
62
+ No camera in your process? Feed frames yourself — that's the real API; the
63
+ camera helper is a thin convenience on top:
64
+
65
+ ```python
66
+ import numpy as np
67
+ from facekey import FaceLock
68
+
69
+ lock = FaceLock()
70
+
71
+ session = lock.enroll()
72
+ while session.needs: # ["frontal", "left", "right", "up", "down"]
73
+ frame = my_capture() # H x W x 3 BGR ndarray, or JPEG/PNG bytes
74
+ result = session.capture(frame)
75
+ print(result.reason, "still need:", session.needs)
76
+ session.commit()
77
+
78
+ auth = lock.authenticate(my_capture())
79
+ print(auth.granted, auth.score, auth.liveness)
80
+ ```
81
+
82
+ ## This is not a security boundary
83
+
84
+ facekey uses an ordinary RGB camera. There is no infrared or depth sensing like
85
+ a phone's Face ID. Passive liveness catches a casual printed photo or a phone
86
+ screen held up to the lens, but it is beatable by replay video, masks, and
87
+ deepfakes.
88
+
89
+ Treat it as a **convenience factor**, not a lock:
90
+
91
+ - Never make it the *only* thing standing between someone and sensitive data.
92
+ - Always ship a PIN / password fallback.
93
+ - Store only embeddings, never the enrollment images (facekey does this).
94
+ - Let people delete their template (`lock.remove()`).
95
+ - Get explicit consent before enrolling anyone. Face templates are biometric
96
+ data and are regulated (EU GDPR Art. 9, Illinois BIPA, others). Consent,
97
+ retention limits, and deletion are your responsibility.
98
+
99
+ ## Install
100
+
101
+ ```bash
102
+ pip install facekey # core: frame-in, decision-out
103
+ pip install "facekey[camera]" # + OpenCV highgui for the camera helper / preview
104
+ pip install "facekey[gpu]" # + onnxruntime-gpu
105
+ pip install "facekey[crypto]" # + encryption at rest for stored templates
106
+ ```
107
+
108
+ First use downloads the InsightFace model pack (~300 MB) into a local cache.
109
+ Do it ahead of time with:
110
+
111
+ ```bash
112
+ facekey download-models
113
+ ```
114
+
115
+ `insightface` may build from source on some platforms; you need a C/C++
116
+ toolchain if no wheel is available for your Python/OS.
117
+
118
+ ## EMBEDDER LICENSING — read before shipping commercially
119
+
120
+ The default recognition backend is InsightFace **`buffalo_l`**. Its *code* is
121
+ MIT, but its *pretrained weights* are released **for non-commercial research use
122
+ only** (the training datasets forbid commercial use). Commercial use needs a
123
+ license from InsightFace: `recognition-oss-pack@insightface.ai`.
124
+
125
+ facekey emits a `FaceKeyLicenseWarning` the first time the default backend
126
+ loads. To use facekey in a commercial product without that license, supply a
127
+ differently-licensed embedder:
128
+
129
+ ```python
130
+ from facekey import FaceLock
131
+ from facekey.embedders import Embedder # implement this protocol over your own model
132
+
133
+ lock = FaceLock(embedder=MyPermissiveArcFace())
134
+ ```
135
+
136
+ Suppress the warning (once you understand the terms) with
137
+ `FACEKEY_SUPPRESS_LICENSE_WARNING=1` in the environment.
138
+
139
+ ## API sketch
140
+
141
+ | Call | Purpose |
142
+ |---|---|
143
+ | `FaceLock(store=None, *, threshold=0.45, liveness=True, model="buffalo_l", max_enrollees=1, gpu=False)` | Construct a lock. `store`: `None` → per-user data dir, a path, or a `Store` instance. |
144
+ | `lock.enroll(label="default") -> EnrollmentSession` | Start guided multi-angle enrollment. |
145
+ | `session.capture(frame) -> CaptureResult` / `session.needs` / `session.commit()` | Feed frames until every pose bucket is covered, then persist. |
146
+ | `lock.authenticate(frame, enrollee=None) -> AuthResult` | 1:1 verify. `enrollee` optional while only one face is enrolled. |
147
+ | `lock.identify(frame) -> AuthResult` | 1:N — best match across all enrolled faces. |
148
+ | `lock.unlock(camera=0, timeout=5) -> bool` | Camera helper: grab frames until match or timeout. |
149
+ | `lock.run_enrollment(camera=0, on_prompt=print)` | Camera helper: drives the "turn your head" flow. |
150
+ | `lock.enrolled()` / `lock.is_enrolled()` / `lock.remove(label="default")` | Manage templates. |
151
+
152
+ `max_enrollees` is `1` today. The store, matching, and `identify()` are already
153
+ multi-face internally — raise the cap (up to a handful) when you want a shared
154
+ device.
155
+
156
+ ## Tuning the threshold
157
+
158
+ `threshold` is cosine similarity on L2-normalized embeddings; higher is
159
+ stricter. `0.45` is a deliberately conservative default for an auth use case.
160
+ Lower it if legitimate users are rejected too often (higher false-accept rate),
161
+ raise it to make impostor matches harder (higher false-reject rate). Measure on
162
+ your own camera and lighting before trusting a number.
163
+
164
+ ## Status
165
+
166
+ Alpha. `matching`, `stores`, `enrollment`, `models`, `errors` are implemented;
167
+ `embedders.insightface`, `liveness`, and `camera` are minimal and expected to
168
+ change. Passive liveness currently ships a lightweight texture heuristic
169
+ (`HeuristicLiveness`); a MiniFASNet backend is the planned upgrade.
170
+
171
+ ## License
172
+
173
+ MIT for the source (see `LICENSE`). Model weights carry their own terms — see
174
+ EMBEDDER LICENSING above.
@@ -0,0 +1,136 @@
1
+ # facekey
2
+
3
+ > ⚠️ **Alpha — the API will change.** Pin an exact version if you depend on it.
4
+
5
+ Face-ID-style unlock for your Python app. Enroll a face from a few angles, then
6
+ on each unlock grab a frame from the camera, compare it to the enrolled
7
+ template, and grant access on a match.
8
+
9
+ ```python
10
+ from facekey import FaceLock
11
+
12
+ lock = FaceLock() # single enrolled face, stored under a per-user data dir
13
+
14
+ # one-time enrollment (needs a camera; pip install "facekey[camera]")
15
+ lock.run_enrollment(camera=0, on_prompt=print)
16
+
17
+ # later, guard something
18
+ if lock.unlock(camera=0, timeout=5):
19
+ reveal_secret()
20
+ else:
21
+ fall_back_to_password()
22
+ ```
23
+
24
+ No camera in your process? Feed frames yourself — that's the real API; the
25
+ camera helper is a thin convenience on top:
26
+
27
+ ```python
28
+ import numpy as np
29
+ from facekey import FaceLock
30
+
31
+ lock = FaceLock()
32
+
33
+ session = lock.enroll()
34
+ while session.needs: # ["frontal", "left", "right", "up", "down"]
35
+ frame = my_capture() # H x W x 3 BGR ndarray, or JPEG/PNG bytes
36
+ result = session.capture(frame)
37
+ print(result.reason, "still need:", session.needs)
38
+ session.commit()
39
+
40
+ auth = lock.authenticate(my_capture())
41
+ print(auth.granted, auth.score, auth.liveness)
42
+ ```
43
+
44
+ ## This is not a security boundary
45
+
46
+ facekey uses an ordinary RGB camera. There is no infrared or depth sensing like
47
+ a phone's Face ID. Passive liveness catches a casual printed photo or a phone
48
+ screen held up to the lens, but it is beatable by replay video, masks, and
49
+ deepfakes.
50
+
51
+ Treat it as a **convenience factor**, not a lock:
52
+
53
+ - Never make it the *only* thing standing between someone and sensitive data.
54
+ - Always ship a PIN / password fallback.
55
+ - Store only embeddings, never the enrollment images (facekey does this).
56
+ - Let people delete their template (`lock.remove()`).
57
+ - Get explicit consent before enrolling anyone. Face templates are biometric
58
+ data and are regulated (EU GDPR Art. 9, Illinois BIPA, others). Consent,
59
+ retention limits, and deletion are your responsibility.
60
+
61
+ ## Install
62
+
63
+ ```bash
64
+ pip install facekey # core: frame-in, decision-out
65
+ pip install "facekey[camera]" # + OpenCV highgui for the camera helper / preview
66
+ pip install "facekey[gpu]" # + onnxruntime-gpu
67
+ pip install "facekey[crypto]" # + encryption at rest for stored templates
68
+ ```
69
+
70
+ First use downloads the InsightFace model pack (~300 MB) into a local cache.
71
+ Do it ahead of time with:
72
+
73
+ ```bash
74
+ facekey download-models
75
+ ```
76
+
77
+ `insightface` may build from source on some platforms; you need a C/C++
78
+ toolchain if no wheel is available for your Python/OS.
79
+
80
+ ## EMBEDDER LICENSING — read before shipping commercially
81
+
82
+ The default recognition backend is InsightFace **`buffalo_l`**. Its *code* is
83
+ MIT, but its *pretrained weights* are released **for non-commercial research use
84
+ only** (the training datasets forbid commercial use). Commercial use needs a
85
+ license from InsightFace: `recognition-oss-pack@insightface.ai`.
86
+
87
+ facekey emits a `FaceKeyLicenseWarning` the first time the default backend
88
+ loads. To use facekey in a commercial product without that license, supply a
89
+ differently-licensed embedder:
90
+
91
+ ```python
92
+ from facekey import FaceLock
93
+ from facekey.embedders import Embedder # implement this protocol over your own model
94
+
95
+ lock = FaceLock(embedder=MyPermissiveArcFace())
96
+ ```
97
+
98
+ Suppress the warning (once you understand the terms) with
99
+ `FACEKEY_SUPPRESS_LICENSE_WARNING=1` in the environment.
100
+
101
+ ## API sketch
102
+
103
+ | Call | Purpose |
104
+ |---|---|
105
+ | `FaceLock(store=None, *, threshold=0.45, liveness=True, model="buffalo_l", max_enrollees=1, gpu=False)` | Construct a lock. `store`: `None` → per-user data dir, a path, or a `Store` instance. |
106
+ | `lock.enroll(label="default") -> EnrollmentSession` | Start guided multi-angle enrollment. |
107
+ | `session.capture(frame) -> CaptureResult` / `session.needs` / `session.commit()` | Feed frames until every pose bucket is covered, then persist. |
108
+ | `lock.authenticate(frame, enrollee=None) -> AuthResult` | 1:1 verify. `enrollee` optional while only one face is enrolled. |
109
+ | `lock.identify(frame) -> AuthResult` | 1:N — best match across all enrolled faces. |
110
+ | `lock.unlock(camera=0, timeout=5) -> bool` | Camera helper: grab frames until match or timeout. |
111
+ | `lock.run_enrollment(camera=0, on_prompt=print)` | Camera helper: drives the "turn your head" flow. |
112
+ | `lock.enrolled()` / `lock.is_enrolled()` / `lock.remove(label="default")` | Manage templates. |
113
+
114
+ `max_enrollees` is `1` today. The store, matching, and `identify()` are already
115
+ multi-face internally — raise the cap (up to a handful) when you want a shared
116
+ device.
117
+
118
+ ## Tuning the threshold
119
+
120
+ `threshold` is cosine similarity on L2-normalized embeddings; higher is
121
+ stricter. `0.45` is a deliberately conservative default for an auth use case.
122
+ Lower it if legitimate users are rejected too often (higher false-accept rate),
123
+ raise it to make impostor matches harder (higher false-reject rate). Measure on
124
+ your own camera and lighting before trusting a number.
125
+
126
+ ## Status
127
+
128
+ Alpha. `matching`, `stores`, `enrollment`, `models`, `errors` are implemented;
129
+ `embedders.insightface`, `liveness`, and `camera` are minimal and expected to
130
+ change. Passive liveness currently ships a lightweight texture heuristic
131
+ (`HeuristicLiveness`); a MiniFASNet backend is the planned upgrade.
132
+
133
+ ## License
134
+
135
+ MIT for the source (see `LICENSE`). Model weights carry their own terms — see
136
+ EMBEDDER LICENSING above.
@@ -0,0 +1,29 @@
1
+ """Enroll once, then gate a secret behind a face unlock.
2
+
3
+ pip install "facekey[camera]"
4
+ python examples/desktop_unlock.py
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from facekey import FaceLock
10
+
11
+ SECRET = "the launch codes are 0000"
12
+
13
+
14
+ def main() -> None:
15
+ lock = FaceLock() # stores the template under your per-user data dir
16
+
17
+ if not lock.is_enrolled():
18
+ print("No face on file - starting enrollment.")
19
+ lock.run_enrollment(camera=0, on_prompt=print)
20
+
21
+ print("\nLook at the camera to unlock...")
22
+ if lock.unlock(camera=0, timeout=6):
23
+ print("Unlocked:", SECRET)
24
+ else:
25
+ print("Denied. Fall back to a password here.")
26
+
27
+
28
+ if __name__ == "__main__":
29
+ main()
@@ -0,0 +1,67 @@
1
+ """Face unlock over HTTP: the browser captures frames, this server matches them.
2
+
3
+ pip install facekey fastapi "uvicorn[standard]" python-multipart
4
+ uvicorn examples.web_fastapi:app --reload
5
+
6
+ POST a still image (multipart field ``frame``) to:
7
+ /enroll/capture until the response shows no remaining ``needs``
8
+ /enroll/commit to persist
9
+ /authenticate to check a face
10
+
11
+ This keeps the frame-based API server-side; no camera on the host is involved.
12
+ Enrollment state is held in memory here for brevity - use a real session store
13
+ in production.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from fastapi import FastAPI, File, UploadFile
19
+
20
+ from facekey import FaceLock
21
+ from facekey.errors import FaceKeyError
22
+
23
+ app = FastAPI(title="facekey web example")
24
+ lock = FaceLock()
25
+ _session = {"obj": None}
26
+
27
+
28
+ @app.post("/enroll/capture")
29
+ async def enroll_capture(frame: UploadFile = File(...)):
30
+ if _session["obj"] is None:
31
+ _session["obj"] = lock.enroll()
32
+ result = _session["obj"].capture(await frame.read())
33
+ return {
34
+ "accepted": result.accepted,
35
+ "reason": result.reason,
36
+ "bucket": result.bucket.value if result.bucket else None,
37
+ "needs": result.needs,
38
+ "progress": result.progress,
39
+ }
40
+
41
+
42
+ @app.post("/enroll/commit")
43
+ async def enroll_commit():
44
+ session = _session["obj"]
45
+ if session is None:
46
+ return {"error": "no enrollment in progress"}
47
+ try:
48
+ template = session.commit()
49
+ except FaceKeyError as exc:
50
+ return {"error": str(exc)}
51
+ lock.store.put(template)
52
+ _session["obj"] = None
53
+ return {"enrolled": template.label, "poses": sorted(template.embeddings)}
54
+
55
+
56
+ @app.post("/authenticate")
57
+ async def authenticate(frame: UploadFile = File(...)):
58
+ try:
59
+ result = lock.authenticate(await frame.read())
60
+ except FaceKeyError as exc:
61
+ return {"granted": False, "reason": str(exc)}
62
+ return {
63
+ "granted": result.granted,
64
+ "score": result.score,
65
+ "liveness": result.liveness,
66
+ "reason": result.reason,
67
+ }
@@ -0,0 +1,73 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "facekey"
7
+ version = "0.0.1"
8
+ description = "Face-ID-style unlock for your app: enroll a face from several angles, then authenticate against a live camera frame."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Adm145" }]
13
+ keywords = [
14
+ "face recognition",
15
+ "face unlock",
16
+ "face id",
17
+ "authentication",
18
+ "biometrics",
19
+ "liveness",
20
+ "insightface",
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 3 - Alpha",
24
+ "Intended Audience :: Developers",
25
+ "License :: OSI Approved :: MIT License",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3.9",
28
+ "Programming Language :: Python :: 3.10",
29
+ "Programming Language :: Python :: 3.11",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Topic :: Scientific/Engineering :: Image Recognition",
32
+ "Topic :: Security",
33
+ ]
34
+ dependencies = [
35
+ "numpy>=1.21",
36
+ "opencv-python-headless>=4.7",
37
+ "insightface>=0.7.3",
38
+ "onnxruntime>=1.15",
39
+ "platformdirs>=3.0",
40
+ ]
41
+
42
+ [project.optional-dependencies]
43
+ # Full OpenCV build: adds the highgui preview window used by the camera helper.
44
+ # The base install already has cv2.VideoCapture via opencv-python-headless.
45
+ camera = ["opencv-python>=4.7"]
46
+ gpu = ["onnxruntime-gpu>=1.15"]
47
+ crypto = ["cryptography>=41"]
48
+ dev = ["pytest>=7", "ruff>=0.4", "build>=1.0"]
49
+
50
+ [project.scripts]
51
+ facekey = "facekey.cli:main"
52
+
53
+ [project.urls]
54
+ Homepage = "https://github.com/Adm145/facekey"
55
+ Issues = "https://github.com/Adm145/facekey/issues"
56
+
57
+ [tool.hatch.build.targets.wheel]
58
+ packages = ["src/facekey"]
59
+
60
+ [tool.ruff]
61
+ line-length = 100
62
+ target-version = "py39"
63
+
64
+ [tool.ruff.lint]
65
+ select = ["E", "F", "I", "UP", "B"]
66
+
67
+ [tool.pytest.ini_options]
68
+ testpaths = ["tests"]
69
+ pythonpath = ["src"]
70
+ filterwarnings = [
71
+ "ignore::facekey.errors.FaceKeyLicenseWarning",
72
+ "ignore::facekey.errors.WeakLivenessWarning",
73
+ ]
@@ -0,0 +1,71 @@
1
+ """facekey - Face-ID-style unlock for your app.
2
+
3
+ See the README for the security caveats and model licensing. Quick start::
4
+
5
+ from facekey import FaceLock
6
+
7
+ lock = FaceLock()
8
+ lock.run_enrollment(camera=0, on_prompt=print)
9
+ if lock.unlock(camera=0, timeout=5):
10
+ ...
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from .core import FaceLock, __version__
16
+ from .embedders import Embedder, get_embedder, register
17
+ from .enrollment import EnrollmentSession
18
+ from .errors import (
19
+ EnrollmentIncomplete,
20
+ FaceKeyError,
21
+ FaceKeyLicenseWarning,
22
+ LivenessCheckFailed,
23
+ LowQualityFrame,
24
+ ModelDownloadError,
25
+ MultipleFacesDetected,
26
+ NoFaceDetected,
27
+ NotEnrolled,
28
+ StoreFull,
29
+ WeakLivenessWarning,
30
+ )
31
+ from .liveness import HeuristicLiveness, LivenessChecker, NullLiveness
32
+ from .matching import DEFAULT_THRESHOLD, cosine_similarity
33
+ from .models import AuthResult, CaptureResult, FaceObservation, FaceTemplate, PoseBucket
34
+ from .stores import FileStore, SQLiteStore, Store
35
+
36
+ __all__ = [
37
+ "__version__",
38
+ "FaceLock",
39
+ "EnrollmentSession",
40
+ "AuthResult",
41
+ "CaptureResult",
42
+ "FaceObservation",
43
+ "FaceTemplate",
44
+ "PoseBucket",
45
+ "DEFAULT_THRESHOLD",
46
+ "cosine_similarity",
47
+ # embedders
48
+ "Embedder",
49
+ "get_embedder",
50
+ "register",
51
+ # liveness
52
+ "LivenessChecker",
53
+ "HeuristicLiveness",
54
+ "NullLiveness",
55
+ # stores
56
+ "Store",
57
+ "FileStore",
58
+ "SQLiteStore",
59
+ # errors / warnings
60
+ "FaceKeyError",
61
+ "NoFaceDetected",
62
+ "MultipleFacesDetected",
63
+ "LowQualityFrame",
64
+ "LivenessCheckFailed",
65
+ "NotEnrolled",
66
+ "EnrollmentIncomplete",
67
+ "StoreFull",
68
+ "ModelDownloadError",
69
+ "FaceKeyLicenseWarning",
70
+ "WeakLivenessWarning",
71
+ ]
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())