import sys import tempfile import grpc from concurrent import futures import os from deepface import DeepFace sys.path.insert(0, os.path.join(os.path.dirname(__file__), "proto")) from proto import face_recognition_pb2, face_recognition_pb2_grpc EMPLOYEE_DB_PATH = "data/employees" class FaceRecognitionServicer(face_recognition_pb2_grpc.FaceRecognitionServiceServicer): def Recognize(self, request, context): print("[INFO] Received recognition request...") temp_file = None try: # Save incoming image to a temporary file with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp: temp_file = tmp.name tmp.write(request.image) print("[INFO] Running DeepFace search...") result = DeepFace.find( img_path=temp_file, db_path=EMPLOYEE_DB_PATH, detector_backend="opencv", enforce_detection=False ) 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, image=b"" ) best_row = result.iloc[0] matched_image_path = best_row["identity"] name = os.path.splitext(os.path.basename(matched_image_path))[0] # Convert distance to rough confidence distance = best_row.get("VGG-Face_cosine", 0.3) confidence = float(max(0.0, 1.0 - distance)) # Read matched image bytes with open(matched_image_path, "rb") as f: matched_image_bytes = f.read() print(f"[INFO] Match: {name}, confidence: {confidence:.2f}") return face_recognition_pb2.FaceResponse( name=name, confidence=confidence, image=matched_image_bytes ) except Exception as e: print("[ERROR] DeepFace failed:", e) return face_recognition_pb2.FaceResponse( name="Error", confidence=0.0, image=b"" ) finally: if temp_file and os.path.exists(temp_file): try: os.remove(temp_file) except Exception as cleanup_error: print( f"[WARN] Could not delete temp file {temp_file}: {cleanup_error}") def EnrollFace(self, request, context): """ Handles enrollment of a new employee. Saves the uploaded image in EMPLOYEE_DB_PATH with the employee's name. """ try: name = request.name image_bytes = request.image if not name or not image_bytes: return face_recognition_pb2.EnrollFaceResponse( success=False, message="Name or image missing" ) os.makedirs(EMPLOYEE_DB_PATH, exist_ok=True) file_path = os.path.join(EMPLOYEE_DB_PATH, f"{name}.jpg") with open(file_path, "wb") as f: f.write(image_bytes) print(f"[INFO] Enrolled employee: {name}, saved at {file_path}") return face_recognition_pb2.EnrollFaceResponse( success=True, message="Enrollment successful" ) except Exception as e: print(f"[ERROR] Enrollment failed: {e}") return face_recognition_pb2.EnrollFaceResponse( success=False, message=str(e) ) def GetAllEmployees(self, request, context): try: employee_files = [ f for f in os.listdir(EMPLOYEE_DB_PATH) if f.lower().endswith((".jpg", ".png", ".jpeg")) ] employees = [] for file in employee_files: path = os.path.join(EMPLOYEE_DB_PATH, file) name = os.path.splitext(file)[0] with open(path, "rb") as f: image_bytes = f.read() employees.append(face_recognition_pb2.Employee( name=name, image=image_bytes )) return face_recognition_pb2.EmployeeListResponse( employees=employees ) except Exception as e: print("[ERROR] Failed to list employees:", e) return face_recognition_pb2.EmployeeListResponse(employees=[]) def DeleteEmployee(self, request, context): try: found = False for file in os.listdir(EMPLOYEE_DB_PATH): if os.path.splitext(file)[0] == request.name: os.remove(os.path.join(EMPLOYEE_DB_PATH, file)) found = True break message = "Deleted successfully" if found else "Employee not found" return face_recognition_pb2.DeleteEmployeeResponse( success=found, message=message ) except Exception as e: print("[ERROR] Failed to delete employee:", e) return face_recognition_pb2.DeleteEmployeeResponse( success=False, message=str(e) ) 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__": os.makedirs(EMPLOYEE_DB_PATH, exist_ok=True) serve()