abcxyz / app.py
huy00001's picture
Update app.py
22c0f65 verified
from flask import Flask, request, jsonify
from flask_cors import CORS
import base64
import secrets
from deepface import DeepFace
import cv2
import numpy as np
from pymongo import MongoClient
app = Flask(__name__)
CORS(app)
# ========================
# KẾT NỐI MONGODB
# ========================
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"] # database
users_col = db["users"] # collection tương đương bảng user
# ========================
# REGISTER USER
# ========================
from deepface import DeepFace
import cv2
import numpy as np
import base64
@app.route('/api/register', methods=['POST'])
def register():
data = request.json
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')
# Kiểm tra dữ liệu bắt buộc
if not username or not password or not img_data:
return jsonify({'error': 'username, password và ảnh là bắt buộc'}), 400
img_str = img_data.split(",")[1] if "," in img_data else img_data
# Kiểm tra Base64 hợp lệ
try:
decoded = base64.b64decode(img_str)
except Exception:
return jsonify({'error': 'Ảnh không hợp lệ, phải là Base64'}), 400
# Chuyển base64 → ảnh OpenCV
try:
nparr = np.frombuffer(decoded, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
if img is None:
return jsonify({'error': 'Ảnh không thể đọc được'}), 400
except Exception:
return jsonify({'error': 'Không thể xử lý ảnh'}), 400
# ===== KIỂM TRA ẢNH CÓ MẶT KHÔNG =====
try:
DeepFace.extract_faces(img, enforce_detection=True)
except Exception:
return jsonify({'error': 'Ảnh không có khuôn mặt hợp lệ'}), 400
try:
# Kiểm tra username trùng
existing_user = users_col.find_one({"userName": username})
if existing_user:
return jsonify({'error': 'Tên người dùng đã tồn tại'}), 409
# Dữ liệu người dùng chỉ gồm các trường yêu cầu
user_info = {
"userName": username,
"password": password,
"img": img_str,
"fullName": fullName,
"email": email,
"phone": phone,
"gender": gender,
}
# Lưu vào MongoDB
users_col.insert_one(user_info)
return jsonify({'message': 'Đăng ký thành công!', 'user': username}), 201
except Exception as e:
return jsonify({'error': str(e)}), 500
# LOGIN + KIỂM TRA KHUÔN MẶT
# ========================
@app.route('/api/login', methods=['POST'])
def login():
data = request.json
username = data.get('username')
password = data.get('password')
img_data = data.get('img')
if not username or not password or not img_data:
return jsonify({'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:
# Lấy user từ MongoDB
user = users_col.find_one({"userName": username, "password": password})
if not user:
return jsonify({'error': 'Username hoặc password sai'}), 401
# Base64 → ảnh
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)
# So sánh mặt
try:
result = DeepFace.verify(img_input, img_db, enforce_detection=True)
except Exception as e:
return jsonify({'error': f'Lỗi khi nhận diện khuôn mặt: {e}'}), 400
# Tính %
distance = result.get("distance", 1)
similarity = max(0, (1 - distance)) * 100
similarity = round(similarity, 2)
if result['verified']:
token = secrets.token_hex(16)
# Xóa _id vì không serializable
user_info = {
"userName": user.get("userName"),
"fullName": user.get("fullName"),
"email": user.get("email"),
"phone": user.get("phone"),
"gender": user.get("gender"),
"img": user.get("img")
}
return jsonify({
'message': 'Login thành công!',
'token': token,
'similarity': similarity,
'user': user_info
})
else:
return jsonify({
'error': 'Khuôn mặt không trùng khớp',
'similarity': similarity
}), 401
except Exception as e:
return jsonify({'error': str(e)}), 500
# ========================
# PHÂN TÍCH KHUÔN MẶT
# ========================
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
@app.route('/api/analyze', methods=['POST'])
def analyze_face():
data = request.json
img_data = data.get('img')
if not img_data:
return jsonify({'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 jsonify({'result': result})
except Exception as e:
return jsonify({'error': f'Lỗi khi phân tích khuôn mặt: {e}'}), 400
@app.route('/api/compare', methods=['POST'])
def compare_faces():
data = request.json
img1_data = data.get("img1")
img2_data = data.get("img2")
if not img1_data or not img2_data:
return jsonify({'error': 'Cần 2 ảnh base64 để so sánh'}), 400
# Tách phần base64 (nếu có prefix data:image/png;base64,)
img1_str = img1_data.split(",")[1] if "," in img1_data else img1_data
img2_str = img2_data.split(",")[1] if "," in img2_data else img2_data
try:
# Base64 → OpenCV image
nparr1 = np.frombuffer(base64.b64decode(img1_str), np.uint8)
img1 = cv2.imdecode(nparr1, cv2.IMREAD_COLOR)
nparr2 = np.frombuffer(base64.b64decode(img2_str), np.uint8)
img2 = cv2.imdecode(nparr2, cv2.IMREAD_COLOR)
# So sánh khuôn mặt bằng DeepFace
try:
result = DeepFace.verify(img1, img2, enforce_detection=True)
except Exception as e:
return jsonify({'error': f'Lỗi nhận diện: {e}'}), 400
# Tính phần trăm giống nhau
distance = result.get("distance", 1)
similarity = max(0, (1 - distance)) * 100
similarity = round(similarity, 2)
return jsonify({
"verified": result.get("verified", False),
"distance": distance,
"similarity": similarity
})
except Exception as e:
return jsonify({'error': str(e)}), 500
# ========================
# RUN
# ========================
if __name__ == '__main__':
app.run(debug=True)