Dr-Swopt 1 week ago
commit
e6df6ad535
7 changed files with 274 additions and 0 deletions
  1. 68 0
      .gitignore
  2. BIN
      data/employees/ragnar.jpg
  3. 14 0
      grpc_client.py
  4. 87 0
      grpc_server.py
  5. 19 0
      proto/face_recognition.proto
  6. 86 0
      requirements.txt
  7. BIN
      sample_image.jpg

+ 68 - 0
.gitignore

@@ -0,0 +1,68 @@
+# -----------------------------------
+# Python
+# -----------------------------------
+__pycache__/
+*.py[cod]
+*.egg-info/
+*.egg
+*.pyo
+*.pyd
+*.pdb
+
+# Virtual environment
+venv/
+env/
+.venv/
+
+# Jupyter / Notebook
+.ipynb_checkpoints/
+
+# Byte-compiled
+*.so
+
+# -----------------------------------
+# DeepFace / OpenCV / Temp Files
+# -----------------------------------
+temp_upload.jpg
+temp/
+output/
+*.log
+*.cache
+cache/
+models/
+weights/
+
+# -----------------------------------
+# gRPC generated files
+# -----------------------------------
+face_recognition_pb2.py
+face_recognition_pb2_grpc.py
+
+# (Optional) If you want to commit proto only
+# !face_recognition.proto
+
+# -----------------------------------
+# OS specific
+# -----------------------------------
+.DS_Store
+Thumbs.db
+
+# -----------------------------------
+# IDE
+# -----------------------------------
+.vscode/
+.idea/
+
+# -----------------------------------
+# Deployment / Build artifacts
+# -----------------------------------
+dist/
+build/
+*.spec
+
+# -----------------------------------
+# Python backups
+# -----------------------------------
+*.bak
+*.tmp
+*~

BIN
data/employees/ragnar.jpg


+ 14 - 0
grpc_client.py

@@ -0,0 +1,14 @@
+import grpc
+import face_recognition_pb2
+import face_recognition_pb2_grpc
+
+with open("sample.jpg", "rb") as f:
+    image_bytes = f.read()
+
+channel = grpc.insecure_channel("localhost:50051")
+stub = face_recognition_pb2_grpc.FaceRecognitionServiceStub(channel)
+
+response = stub.Recognize(face_recognition_pb2.FaceRequest(image=image_bytes))
+
+print("Name:", response.name)
+print("Confidence:", response.confidence)

+ 87 - 0
grpc_server.py

@@ -0,0 +1,87 @@
+import grpc
+from concurrent import futures
+import time
+import os
+from deepface import DeepFace
+import pandas as pd
+
+import face_recognition_pb2
+import face_recognition_pb2_grpc
+
+
+EMPLOYEE_DB_PATH = "data/employees"
+
+
+class FaceRecognitionServicer(face_recognition_pb2_grpc.FaceRecognitionServiceServicer):
+
+    def Recognize(self, request, context):
+        print("[INFO] Received request...")
+
+        # Save temp image
+        temp_path = "temp_upload.jpg"
+        with open(temp_path, "wb") as f:
+            f.write(request.image)
+
+        try:
+            print("[INFO] Running DeepFace search...")
+
+            result = DeepFace.find(
+                img_path=temp_path,
+                db_path=EMPLOYEE_DB_PATH,
+                enforce_detection=False
+            )
+
+            # result is a list of pandas DataFrames for each model;
+            # we only use first result
+            if isinstance(result, list):
+                result = result[0]
+
+            if result is None or len(result) == 0:
+                print("[INFO] No match found.")
+                return face_recognition_pb2.FaceResponse(
+                    name="Unknown",
+                    confidence=0.0
+                )
+
+            # Pick best match
+            best_row = result.iloc[0]
+            matched_image_path = best_row["identity"]
+            name = os.path.splitext(os.path.basename(matched_image_path))[0]
+
+            # DeepFace gives "distance" values, convert roughly to confidence
+            distance = best_row.get("VGG-Face_cosine", 0.3)
+            confidence = float(max(0.0, 1.0 - distance))
+
+            print(f"[INFO] Match: {name}, confidence: {confidence:.2f}")
+
+            return face_recognition_pb2.FaceResponse(
+                name=name,
+                confidence=confidence
+            )
+
+        except Exception as e:
+            print("[ERROR] DeepFace failed:", e)
+            return face_recognition_pb2.FaceResponse(
+                name="Error",
+                confidence=0.0
+            )
+
+        finally:
+            if os.path.exists(temp_path):
+                os.remove(temp_path)
+
+
+def serve():
+    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+    face_recognition_pb2_grpc.add_FaceRecognitionServiceServicer_to_server(
+        FaceRecognitionServicer(), server
+    )
+
+    server.add_insecure_port("[::]:50051")
+    server.start()
+    print("[INFO] gRPC Face Recognition server running on port 50051")
+    server.wait_for_termination()
+
+
+if __name__ == "__main__":
+    serve()

+ 19 - 0
proto/face_recognition.proto

@@ -0,0 +1,19 @@
+syntax = "proto3";
+
+package facerecognition;
+
+// The request message containing the image bytes
+message FaceRequest {
+  bytes image = 1;
+}
+
+// The response message containing recognition results
+message FaceResponse {
+  string name = 1;
+  float confidence = 2;
+}
+
+// The Face Recognition Service
+service FaceRecognitionService {
+  rpc Recognize(FaceRequest) returns (FaceResponse);
+}

+ 86 - 0
requirements.txt

@@ -0,0 +1,86 @@
+absl-py==2.3.1
+annotated-doc==0.0.4
+annotated-types==0.7.0
+anyio==4.12.0
+astunparse==1.6.3
+atomicwrites==1.4.1
+attrs==25.4.0
+beautifulsoup4==4.14.3
+blinker==1.9.0
+certifi==2025.11.12
+charset-normalizer==3.4.4
+click==8.3.1
+cmake==4.2.0
+colorama==0.4.6
+deepface==0.0.96
+fastapi==0.123.0
+filelock==3.20.0
+fire==0.7.1
+Flask==3.1.2
+flask-cors==6.0.1
+flatbuffers==25.9.23
+gast==0.7.0
+gdown==5.2.0
+google-pasta==0.2.0
+grpcio==1.76.0
+grpcio-tools==1.76.0
+gunicorn==23.0.0
+h11==0.16.0
+h5py==3.15.1
+idna==3.11
+iniconfig==2.3.0
+itsdangerous==2.2.0
+Jinja2==3.1.6
+joblib==1.5.2
+keras==3.12.0
+libclang==18.1.1
+lightecc==0.0.3
+lightphe==0.0.19
+lz4==4.4.5
+Markdown==3.10
+markdown-it-py==4.0.0
+MarkupSafe==3.0.3
+mdurl==0.1.2
+ml_dtypes==0.5.4
+mpmath==1.3.0
+mtcnn==1.0.0
+namex==0.1.0
+numpy==2.2.6
+opencv-python==4.12.0.88
+opt_einsum==3.4.0
+optree==0.18.0
+packaging==25.0
+pandas==2.3.3
+pillow==12.0.0
+pluggy==1.6.0
+protobuf==6.33.1
+py==1.11.0
+pydantic==2.12.5
+pydantic_core==2.41.5
+Pygments==2.19.2
+PySocks==1.7.1
+pytest==7.1.2
+python-dateutil==2.9.0.post0
+pytz==2025.2
+requests==2.32.5
+retina-face==0.0.17
+rich==14.2.0
+setuptools==80.9.0
+six==1.17.0
+soupsieve==2.8
+starlette==0.50.0
+sympy==1.14.0
+tensorboard==2.20.0
+tensorboard-data-server==0.7.2
+tensorflow==2.20.0
+termcolor==3.2.0
+tomli==2.3.0
+tqdm==4.67.1
+typing-inspection==0.4.2
+typing_extensions==4.15.0
+tzdata==2025.2
+urllib3==2.5.0
+uvicorn==0.38.0
+Werkzeug==3.1.4
+wheel==0.45.1
+wrapt==2.0.1

BIN
sample_image.jpg