face / app.py
huy00001's picture
Update app.py
19d3e3d verified
import os
import json
import base64
import secrets
import numpy as np
import cv2
from deepface import DeepFace
from pymongo import MongoClient
import gradio as gr
# ========================
# MongoDB connection
# ========================
mongo_uri = "mongodb+srv://huyh01480_db_user:zxvAwzAhr8yk3lWe@cluster0.n8pboqq.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0"
client = MongoClient(mongo_uri)
db = client["userdb"]
users_col = db["users"]
# ========================
# Helper functions
# ========================
def convert_numpy(obj):
if isinstance(obj, dict):
return {k: convert_numpy(v) for k, v in obj.items()}
elif isinstance(obj, list):
return [convert_numpy(i) for i in obj]
elif isinstance(obj, (np.float32, np.float64)):
return float(obj)
elif isinstance(obj, (np.int32, np.int64)):
return int(obj)
else:
return obj
# ========================
# Internal API functions
# ========================
def register_internal(data):
username = data.get('username')
password = data.get('password')
img_data = data.get('img')
fullName = data.get('fullName')
email = data.get('email')
phone = data.get('phone')
gender = data.get('gender')
if not username or not password or not img_data:
return {'error': 'username, password và ảnh là bắt buộc'}, 400
img_str = img_data.split(",")[1] if "," in img_data else img_data
try:
decoded = base64.b64decode(img_str)
nparr = np.frombuffer(decoded, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
if img is None:
return {'error': 'Ảnh không thể đọc được'}, 400
except Exception:
return {'error': 'Ảnh không hợp lệ'}, 400
try:
DeepFace.extract_faces(img, enforce_detection=True)
except Exception:
return {'error': 'Ảnh không có khuôn mặt hợp lệ'}, 400
if users_col.find_one({"userName": username}):
return {'error': 'Tên người dùng đã tồn tại'}, 409
user_info = {
"userName": username,
"password": password,
"img": img_str,
"fullName": fullName,
"email": email,
"phone": phone,
"gender": gender,
}
users_col.insert_one(user_info)
return {'message': 'Đăng ký thành công!', 'user': username}, 201
def login_internal(data):
username = data.get('username')
password = data.get('password')
img_data = data.get('img')
if not username or not password or not img_data:
return {'error': 'username, password và ảnh là bắt buộc'}, 400
img_str = img_data.split(",")[1] if "," in img_data else img_data
user = users_col.find_one({"userName": username, "password": password})
if not user:
return {'error': 'Username hoặc password sai'}, 401
try:
nparr_input = np.frombuffer(base64.b64decode(img_str), np.uint8)
img_input = cv2.imdecode(nparr_input, cv2.IMREAD_COLOR)
nparr_db = np.frombuffer(base64.b64decode(user['img']), np.uint8)
img_db = cv2.imdecode(nparr_db, cv2.IMREAD_COLOR)
result = DeepFace.verify(img_input, img_db, enforce_detection=True)
except Exception as e:
return {'error': f'Lỗi khi nhận diện khuôn mặt: {e}'}, 400
distance = result.get("distance", 1)
similarity = max(0, (1 - distance)) * 100
similarity = round(similarity, 2)
if result['verified']:
token = secrets.token_hex(16)
user_info = {k: user[k] for k in ["userName", "fullName", "email", "phone", "gender", "img"]}
return {'message': 'Login thành công!', 'token': token, 'similarity': similarity, 'user': user_info}, 200
else:
return {'error': 'Khuôn mặt không trùng khớp', 'similarity': similarity}, 401
def analyze_internal(data):
img_data = data.get('img')
if not img_data:
return {'error': 'Ảnh là bắt buộc'}, 400
img_str = img_data.split(",")[1] if "," in img_data else img_data
try:
nparr = np.frombuffer(base64.b64decode(img_str), np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
result = DeepFace.analyze(img, actions=['age','gender','emotion','race'], enforce_detection=True)
result = convert_numpy(result)
return {'result': result}, 200
except Exception as e:
return {'error': f'Lỗi khi phân tích khuôn mặt: {e}'}, 400
def compare_internal(data):
img1_data = data.get("img1")
img2_data = data.get("img2")
if not img1_data or not img2_data:
return {'error': 'Cần 2 ảnh base64 để so sánh'}, 400
try:
nparr1 = np.frombuffer(base64.b64decode(img1_data.split(",")[1] if "," in img1_data else img1_data), np.uint8)
img1 = cv2.imdecode(nparr1, cv2.IMREAD_COLOR)
nparr2 = np.frombuffer(base64.b64decode(img2_data.split(",")[1] if "," in img2_data else img2_data), np.uint8)
img2 = cv2.imdecode(nparr2, cv2.IMREAD_COLOR)
result = DeepFace.verify(img1, img2, enforce_detection=True)
distance = result.get("distance", 1)
similarity = max(0, (1 - distance)) * 100
similarity = round(similarity, 2)
return {"verified": result.get("verified", False), "distance": distance, "similarity": similarity}, 200
except Exception as e:
return {'error': str(e)}, 500
# ========================
# Gradio wrapper
# ========================
def gradio_handler(json_str, action="login"):
try:
data = json.loads(json_str)
except Exception:
return json.dumps({'error': 'Invalid JSON input'})
if action == "register":
res, status = register_internal(data)
elif action == "login":
res, status = login_internal(data)
elif action == "analyze":
res, status = analyze_internal(data)
elif action == "compare":
res, status = compare_internal(data)
else:
res = {'error': 'Unknown action'}
return json.dumps(res)
iface = gr.Interface(
fn=gradio_handler,
inputs=[gr.Textbox(label="JSON input"), gr.Dropdown(["register","login","analyze","compare"], label="Action")],
outputs="textbox",
live=False
)
iface.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))