AnnSankavi commited on
Commit
840c040
·
1 Parent(s): cad1f3d

Upload face API

Browse files
Files changed (9) hide show
  1. .dockerignore +4 -0
  2. .env +14 -0
  3. Dockerfile +13 -0
  4. README.md +122 -12
  5. cmake_check.txt +3 -0
  6. install_log.txt +112 -0
  7. main.py +282 -0
  8. requirements.txt +9 -0
  9. start-face-api.bat +10 -0
.dockerignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ venv
2
+ __pycache__
3
+ .env
4
+ *.pyc
.env ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Face Verification API Configuration
2
+ # Copy this file to .env and adjust values as needed
3
+
4
+ # Face matching threshold (0.0 to 1.0)
5
+ # Lower = stricter matching, Higher = more lenient
6
+ # Default 0.6 is recommended for balance between security and usability
7
+ FACE_MATCH_THRESHOLD=0.6
8
+
9
+ # CORS allowed origins (comma-separated)
10
+ # Use * for development, restrict in production
11
+ ALLOWED_ORIGINS=*
12
+
13
+ # Server port
14
+ PORT=8000
Dockerfile ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ RUN apt-get update && apt-get install -y \
4
+ build-essential cmake \
5
+ && rm -rf /var/lib/apt/lists/*
6
+
7
+ WORKDIR /app
8
+ COPY . /app
9
+
10
+ RUN pip install --upgrade pip && pip install -r requirements.txt
11
+
12
+ ENV PORT=7860
13
+ CMD ["python", "main.py"]
README.md CHANGED
@@ -1,12 +1,122 @@
1
- ---
2
- title: Face Api
3
- emoji: 📊
4
- colorFrom: indigo
5
- colorTo: purple
6
- sdk: docker
7
- pinned: false
8
- license: apache-2.0
9
- short_description: Face api
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Face Verification API
2
+
3
+ A self-hosted Python backend for face enrollment and authentication, replacing FaceIO.
4
+
5
+ ## Prerequisites
6
+
7
+ - Python 3.9+
8
+ - pip (Python package manager)
9
+ - CMake and dlib dependencies (required for face_recognition)
10
+
11
+ ### Windows Setup
12
+
13
+ 1. Install Visual Studio Build Tools with C++ development tools
14
+ 2. Install CMake: `winget install cmake`
15
+
16
+ ### Linux/Mac Setup
17
+
18
+ ```bash
19
+ # Ubuntu/Debian
20
+ sudo apt-get install build-essential cmake
21
+
22
+ # macOS
23
+ brew install cmake
24
+ ```
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ cd services/face-api
30
+
31
+ # Create virtual environment
32
+ python -m venv venv
33
+
34
+ # Activate virtual environment
35
+ # Windows:
36
+ venv\Scripts\activate
37
+ # Linux/Mac:
38
+ source venv/bin/activate
39
+
40
+ # Install dependencies
41
+ pip install -r requirements.txt
42
+ ```
43
+
44
+ ## Configuration
45
+
46
+ Copy `.env.example` to `.env` and adjust settings:
47
+
48
+ ```bash
49
+ cp .env.example .env
50
+ ```
51
+
52
+ Configuration options:
53
+ - `FACE_MATCH_THRESHOLD`: Face matching strictness (0.6 recommended)
54
+ - `ALLOWED_ORIGINS`: CORS origins (comma-separated)
55
+ - `PORT`: Server port (default: 8000)
56
+
57
+ ## Running the Server
58
+
59
+ ```bash
60
+ # Development with auto-reload
61
+ python -m uvicorn main:app --reload --host 0.0.0.0 --port 8000
62
+
63
+ # Production
64
+ python main.py
65
+ ```
66
+
67
+ ## API Endpoints
68
+
69
+ ### Health Check
70
+ ```
71
+ GET /health
72
+ ```
73
+
74
+ ### Enroll Face
75
+ ```
76
+ POST /enroll
77
+ Content-Type: application/json
78
+
79
+ {
80
+ "image_base64": "base64_encoded_image",
81
+ "user_id": "user_uuid",
82
+ "metadata": {} // optional
83
+ }
84
+ ```
85
+
86
+ Response:
87
+ ```json
88
+ {
89
+ "success": true,
90
+ "face_id": "face_user_uuid_timestamp",
91
+ "face_embedding": [128 float values],
92
+ "message": "Face enrolled successfully"
93
+ }
94
+ ```
95
+
96
+ ### Verify Face
97
+ ```
98
+ POST /verify
99
+ Content-Type: application/json
100
+
101
+ {
102
+ "image_base64": "base64_encoded_image",
103
+ "stored_embedding": [128 float values],
104
+ "user_id": "user_uuid" // optional
105
+ }
106
+ ```
107
+
108
+ Response:
109
+ ```json
110
+ {
111
+ "success": true,
112
+ "match": true,
113
+ "confidence": 0.85,
114
+ "message": "Face verified successfully"
115
+ }
116
+ ```
117
+
118
+ ## Testing
119
+
120
+ ```bash
121
+ curl http://localhost:8000/health
122
+ ```
cmake_check.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ cmake version 3.31.6-msvc6
2
+
3
+ CMake suite maintained and supported by Kitware (kitware.com/cmake).
install_log.txt ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Using pip 25.0.1 from C:\Users\Malar\Desktop\add\attendance-app\services\face-api\venv\Lib\site-packages\pip (python 3.12)
2
+ Collecting dlib
3
+ Using cached dlib-20.0.0.tar.gz (3.3 MB)
4
+ Installing build dependencies: started
5
+ Running command pip subprocess to install build dependencies
6
+ Using pip 25.0.1 from C:\Users\Malar\Desktop\add\attendance-app\services\face-api\venv\Lib\site-packages\pip (python 3.12)
7
+ Collecting setuptools
8
+ Obtaining dependency information for setuptools from https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl.metadata
9
+ Using cached setuptools-80.9.0-py3-none-any.whl.metadata (6.6 kB)
10
+ Collecting wheel
11
+ Obtaining dependency information for wheel from https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl.metadata
12
+ Using cached wheel-0.45.1-py3-none-any.whl.metadata (2.3 kB)
13
+ Using cached setuptools-80.9.0-py3-none-any.whl (1.2 MB)
14
+ Using cached wheel-0.45.1-py3-none-any.whl (72 kB)
15
+ Installing collected packages: wheel, setuptools
16
+ Creating C:\Users\Malar\AppData\Local\Temp\pip-build-env-6ojhd8_o\overlay\Scripts
17
+ Successfully installed setuptools-80.9.0 wheel-0.45.1
18
+ Installing build dependencies: finished with status 'done'
19
+ Getting requirements to build wheel: started
20
+ Running command Getting requirements to build wheel
21
+ running egg_info
22
+ writing tools/python\dlib.egg-info\PKG-INFO
23
+ writing dependency_links to tools/python\dlib.egg-info\dependency_links.txt
24
+ writing top-level names to tools/python\dlib.egg-info\top_level.txt
25
+ reading manifest file 'tools/python\dlib.egg-info\SOURCES.txt'
26
+ reading manifest template 'MANIFEST.in'
27
+ no previously-included directories found matching 'tools\python\build*'
28
+ no previously-included directories found matching 'dlib\cmake_utils\*\build*'
29
+ no previously-included directories found matching 'dlib\test'
30
+ warning: no previously-included files matching '*.pyc' found anywhere in distribution
31
+ adding license file 'LICENSE.txt'
32
+ writing manifest file 'tools/python\dlib.egg-info\SOURCES.txt'
33
+ Getting requirements to build wheel: finished with status 'done'
34
+ Preparing metadata (pyproject.toml): started
35
+ Running command Preparing metadata (pyproject.toml)
36
+ running dist_info
37
+ creating C:\Users\Malar\AppData\Local\Temp\pip-modern-metadata-sqp11mfi\dlib.egg-info
38
+ writing C:\Users\Malar\AppData\Local\Temp\pip-modern-metadata-sqp11mfi\dlib.egg-info\PKG-INFO
39
+ writing dependency_links to C:\Users\Malar\AppData\Local\Temp\pip-modern-metadata-sqp11mfi\dlib.egg-info\dependency_links.txt
40
+ writing top-level names to C:\Users\Malar\AppData\Local\Temp\pip-modern-metadata-sqp11mfi\dlib.egg-info\top_level.txt
41
+ writing manifest file 'C:\Users\Malar\AppData\Local\Temp\pip-modern-metadata-sqp11mfi\dlib.egg-info\SOURCES.txt'
42
+ reading manifest file 'C:\Users\Malar\AppData\Local\Temp\pip-modern-metadata-sqp11mfi\dlib.egg-info\SOURCES.txt'
43
+ reading manifest template 'MANIFEST.in'
44
+ no previously-included directories found matching 'tools\python\build*'
45
+ no previously-included directories found matching 'dlib\cmake_utils\*\build*'
46
+ no previously-included directories found matching 'dlib\test'
47
+ warning: no previously-included files matching '*.pyc' found anywhere in distribution
48
+ adding license file 'LICENSE.txt'
49
+ writing manifest file 'C:\Users\Malar\AppData\Local\Temp\pip-modern-metadata-sqp11mfi\dlib.egg-info\SOURCES.txt'
50
+ creating 'C:\Users\Malar\AppData\Local\Temp\pip-modern-metadata-sqp11mfi\dlib-20.0.0.dist-info'
51
+ Preparing metadata (pyproject.toml): finished with status 'done'
52
+ Building wheels for collected packages: dlib
53
+ Building wheel for dlib (pyproject.toml): started
54
+ Running command Building wheel for dlib (pyproject.toml)
55
+ running bdist_wheel
56
+ running build
57
+ running build_ext
58
+
59
+ ================================================================================
60
+ ================================================================================
61
+ ================================================================================
62
+
63
+ CMake is not installed on your system!
64
+
65
+ Or it is possible some broken copy of cmake is installed on your system.
66
+ It is unfortunately very common for python package managers to include
67
+ broken copies of cmake. So if the error above this refers to some file
68
+ path to a cmake file inside a python or anaconda or miniconda path then you
69
+ should delete that broken copy of cmake from your computer.
70
+
71
+ Instead, please get an official copy of cmake from one of these known good
72
+ sources of an official cmake:
73
+ - cmake.org (this is how windows users should get cmake)
74
+ - apt install cmake (for Ubuntu or Debian based systems)
75
+ - yum install cmake (for Redhat or CenOS based systems)
76
+
77
+ On a linux machine you can run `which cmake` to see what cmake you are
78
+ actually using. If it tells you it's some cmake from any kind of python
79
+ packager delete it and install an official cmake.
80
+
81
+ More generally, cmake is not installed if when you open a terminal window
82
+ and type
83
+ cmake --version
84
+ you get an error. So you can use that as a very basic test to see if you
85
+ have cmake installed. That is, if cmake --version doesn't run from the
86
+ same terminal window from which you are reading this error message, then
87
+ you have not installed cmake. Windows users should take note that they
88
+ need to tell the cmake installer to add cmake to their PATH. Since you
89
+ can't run commands that are not in your PATH. This is how the PATH works
90
+ on Linux as well, but failing to add cmake to the PATH is a particularly
91
+ common problem on windows and rarely a problem on Linux.
92
+
93
+ ================================================================================
94
+ ================================================================================
95
+ ================================================================================
96
+ error: subprocess-exited-with-error
97
+
98
+ Building wheel for dlib (pyproject.toml) did not run successfully.
99
+ exit code: 1
100
+
101
+ See above for output.
102
+
103
+ note: This error originates from a subprocess, and is likely not a problem with pip.
104
+ full command: 'C:\Users\Malar\Desktop\add\attendance-app\services\face-api\venv\Scripts\python.exe' 'C:\Users\Malar\Desktop\add\attendance-app\services\face-api\venv\Lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\_in_process.py' build_wheel 'C:\Users\Malar\AppData\Local\Temp\tmp_pksdet5'
105
+ cwd: C:\Users\Malar\AppData\Local\Temp\pip-install-0v9s1j6y\dlib_5c30ebd48f0e49868e1123af08a37856
106
+ Building wheel for dlib (pyproject.toml): finished with status 'error'
107
+ ERROR: Failed building wheel for dlib
108
+ Failed to build dlib
109
+
110
+ [notice] A new release of pip is available: 25.0.1 -> 25.3
111
+ [notice] To update, run: python.exe -m pip install --upgrade pip
112
+ ERROR: Failed to build installable wheels for some pyproject.toml based projects (dlib)
main.py ADDED
@@ -0,0 +1,282 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Face Verification API - Python backend for face enrollment and authentication.
3
+ Replaces FaceIO with a self-hosted solution using face_recognition library.
4
+ """
5
+
6
+ import base64
7
+ import io
8
+ import os
9
+ import json
10
+ from typing import Optional, List
11
+ from contextlib import asynccontextmanager
12
+
13
+ import numpy as np
14
+ import face_recognition
15
+ from PIL import Image
16
+ from fastapi import FastAPI, HTTPException
17
+ from fastapi.middleware.cors import CORSMiddleware
18
+ from pydantic import BaseModel
19
+ from dotenv import load_dotenv
20
+
21
+ # Load environment variables
22
+ load_dotenv()
23
+
24
+ # Configuration
25
+ FACE_MATCH_THRESHOLD = float(os.getenv("FACE_MATCH_THRESHOLD", "0.6"))
26
+ ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "*").split(",")
27
+
28
+
29
+ @asynccontextmanager
30
+ async def lifespan(app: FastAPI):
31
+ """Application lifespan handler."""
32
+ print("🚀 Face Verification API starting...")
33
+ print(f" Match threshold: {FACE_MATCH_THRESHOLD}")
34
+ yield
35
+ print("👋 Face Verification API shutting down...")
36
+
37
+
38
+ app = FastAPI(
39
+ title="Face Verification API",
40
+ description="Self-hosted face enrollment and authentication service",
41
+ version="1.0.0",
42
+ lifespan=lifespan
43
+ )
44
+
45
+ # Configure CORS
46
+ app.add_middleware(
47
+ CORSMiddleware,
48
+ allow_origins=ALLOWED_ORIGINS if ALLOWED_ORIGINS[0] != "*" else ["*"],
49
+ allow_credentials=True,
50
+ allow_methods=["*"],
51
+ allow_headers=["*"],
52
+ )
53
+
54
+
55
+ # Request/Response Models
56
+ class EnrollRequest(BaseModel):
57
+ """Request model for face enrollment."""
58
+ image_base64: str
59
+ user_id: str
60
+ metadata: Optional[dict] = None
61
+
62
+
63
+ class EnrollResponse(BaseModel):
64
+ """Response model for face enrollment."""
65
+ success: bool
66
+ face_id: str
67
+ face_embedding: List[float]
68
+ message: str
69
+
70
+
71
+ class VerifyRequest(BaseModel):
72
+ """Request model for face verification."""
73
+ image_base64: str
74
+ stored_embedding: List[float]
75
+ user_id: Optional[str] = None
76
+
77
+
78
+ class VerifyResponse(BaseModel):
79
+ """Response model for face verification."""
80
+ success: bool
81
+ match: bool
82
+ confidence: float
83
+ message: str
84
+
85
+
86
+ class HealthResponse(BaseModel):
87
+ """Response model for health check."""
88
+ status: str
89
+ version: str
90
+
91
+
92
+ def decode_base64_image(base64_string: str) -> np.ndarray:
93
+ """
94
+ Decode a base64 image string to a numpy array for face_recognition.
95
+ Supports both raw base64 and data URI format.
96
+ """
97
+ # Remove data URI prefix(es) if present
98
+ # Handle cases like "data:image/jpeg;base64,data:image/png;base64,..."
99
+ if "," in base64_string:
100
+ base64_string = base64_string.split(",")[-1]
101
+
102
+ # Clean up the string and fix padding
103
+ base64_string = base64_string.strip()
104
+ padding = len(base64_string) % 4
105
+ if padding > 0:
106
+ base64_string += "=" * (4 - padding)
107
+
108
+ try:
109
+ image_bytes = base64.b64decode(base64_string)
110
+ image = Image.open(io.BytesIO(image_bytes))
111
+
112
+ # Convert to RGB if necessary (face_recognition requires RGB)
113
+ if image.mode != "RGB":
114
+ image = image.convert("RGB")
115
+
116
+ return np.array(image)
117
+ except Exception as e:
118
+ raise HTTPException(
119
+ status_code=400,
120
+ detail=f"Invalid image data: {str(e)}"
121
+ )
122
+
123
+
124
+ def extract_face_encoding(image: np.ndarray) -> np.ndarray:
125
+ """
126
+ Extract face encoding from an image.
127
+ Returns the 128-dimensional face encoding.
128
+ """
129
+ # Detect face locations
130
+ face_locations = face_recognition.face_locations(image, model="hog")
131
+
132
+ if len(face_locations) == 0:
133
+ raise HTTPException(
134
+ status_code=400,
135
+ detail="No face detected in the image. Please ensure your face is clearly visible."
136
+ )
137
+
138
+ if len(face_locations) > 1:
139
+ raise HTTPException(
140
+ status_code=400,
141
+ detail="Multiple faces detected. Please ensure only one face is visible."
142
+ )
143
+
144
+ # Extract face encoding
145
+ face_encodings = face_recognition.face_encodings(image, face_locations)
146
+
147
+ if len(face_encodings) == 0:
148
+ raise HTTPException(
149
+ status_code=400,
150
+ detail="Could not extract face features. Please try again with better lighting."
151
+ )
152
+
153
+ return face_encodings[0]
154
+
155
+
156
+ def compare_faces(stored_embedding: List[float], new_embedding: np.ndarray) -> tuple:
157
+ """
158
+ Compare two face embeddings and return match result and confidence.
159
+ """
160
+ stored_array = np.array(stored_embedding)
161
+
162
+ # Calculate face distance (lower = more similar)
163
+ face_distance = face_recognition.face_distance([stored_array], new_embedding)[0]
164
+
165
+ # Convert distance to confidence (invert so higher = more confident match)
166
+ confidence = 1.0 - face_distance
167
+
168
+ # Check if faces match based on threshold
169
+ is_match = face_distance <= FACE_MATCH_THRESHOLD
170
+
171
+ return is_match, float(confidence)
172
+
173
+
174
+ @app.get("/health", response_model=HealthResponse)
175
+ async def health_check():
176
+ """Health check endpoint."""
177
+ return HealthResponse(
178
+ status="healthy",
179
+ version="1.0.0"
180
+ )
181
+
182
+
183
+ @app.post("/enroll", response_model=EnrollResponse)
184
+ async def enroll_face(request: EnrollRequest):
185
+ """
186
+ Enroll a new face - extract and return face embedding for storage.
187
+
188
+ The embedding should be stored in the database by the client app.
189
+ """
190
+ try:
191
+ # Decode image
192
+ image = decode_base64_image(request.image_base64)
193
+
194
+ # Extract face encoding
195
+ face_encoding = extract_face_encoding(image)
196
+
197
+ # Generate a simple face ID (timestamp-based)
198
+ import time
199
+ face_id = f"face_{request.user_id}_{int(time.time() * 1000)}"
200
+
201
+ # Convert encoding to list for JSON serialization
202
+ embedding_list = face_encoding.tolist()
203
+
204
+ return EnrollResponse(
205
+ success=True,
206
+ face_id=face_id,
207
+ face_embedding=embedding_list,
208
+ message="Face enrolled successfully. Store the embedding securely."
209
+ )
210
+
211
+ except HTTPException:
212
+ raise
213
+ except Exception as e:
214
+ raise HTTPException(
215
+ status_code=500,
216
+ detail=f"Face enrollment failed: {str(e)}"
217
+ )
218
+
219
+
220
+ @app.post("/verify", response_model=VerifyResponse)
221
+ async def verify_face(request: VerifyRequest):
222
+ """
223
+ Verify a face against a stored embedding.
224
+
225
+ Returns whether the faces match and the confidence score.
226
+ """
227
+ try:
228
+ # Validate stored embedding
229
+ if not request.stored_embedding or len(request.stored_embedding) != 128:
230
+ raise HTTPException(
231
+ status_code=400,
232
+ detail="Invalid stored embedding. Expected 128-dimensional vector."
233
+ )
234
+
235
+ # Decode image
236
+ image = decode_base64_image(request.image_base64)
237
+
238
+ # Extract face encoding from new image
239
+ face_encoding = extract_face_encoding(image)
240
+
241
+ # Compare faces
242
+ is_match, confidence = compare_faces(request.stored_embedding, face_encoding)
243
+
244
+ if is_match:
245
+ message = f"Face verified successfully (confidence: {confidence:.1%})"
246
+ else:
247
+ message = f"Face verification failed - faces do not match (confidence: {confidence:.1%})"
248
+
249
+ return VerifyResponse(
250
+ success=True,
251
+ match=is_match,
252
+ confidence=confidence,
253
+ message=message
254
+ )
255
+
256
+ except HTTPException:
257
+ raise
258
+ except Exception as e:
259
+ raise HTTPException(
260
+ status_code=500,
261
+ detail=f"Face verification failed: {str(e)}"
262
+ )
263
+
264
+
265
+ @app.get("/")
266
+ async def root():
267
+ """Root endpoint with API info."""
268
+ return {
269
+ "name": "Face Verification API",
270
+ "version": "1.0.0",
271
+ "endpoints": {
272
+ "/health": "Health check",
273
+ "/enroll": "Enroll a new face (POST)",
274
+ "/verify": "Verify a face against stored embedding (POST)"
275
+ }
276
+ }
277
+
278
+
279
+ if __name__ == "__main__":
280
+ import uvicorn
281
+ port = int(os.getenv("PORT", "8000"))
282
+ uvicorn.run(app, host="0.0.0.0", port=port)
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ fastapi>=0.109.0
2
+ uvicorn>=0.27.0
3
+ # face_recognition>=1.3.0 (Installed manually with --no-deps to use dlib-bin)
4
+ face_recognition_models>=0.3.0
5
+ numpy>=1.24.0
6
+ python-multipart>=0.0.6
7
+ httpx>=0.26.0
8
+ python-dotenv>=1.0.0
9
+ pillow>=10.0.0
start-face-api.bat ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ @echo off
2
+ echo Starting Face API server...
3
+ cd /d "%~dp0"
4
+ if not exist "venv\Scripts\python.exe" (
5
+ echo Virtual environment not found. Please run set up first.
6
+ pause
7
+ exit /b
8
+ )
9
+ "venv\Scripts\python.exe" -m uvicorn main:app --reload --host 0.0.0.0 --port 8000
10
+ pause