huy00001 commited on
Commit
19d3e3d
·
verified ·
1 Parent(s): bd13b2f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +99 -173
app.py CHANGED
@@ -1,250 +1,176 @@
1
- from flask import Flask, request, jsonify
2
- from flask_cors import CORS
3
  import base64
4
  import secrets
5
- import os
6
- from deepface import DeepFace
7
- import cv2
8
  import numpy as np
 
 
9
  from pymongo import MongoClient
10
- app = Flask(__name__)
11
- CORS(app)
12
 
13
  # ========================
14
- # KẾT NỐI MONGODB
15
  # ========================
16
  mongo_uri = "mongodb+srv://huyh01480_db_user:zxvAwzAhr8yk3lWe@cluster0.n8pboqq.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0"
17
  client = MongoClient(mongo_uri)
18
-
19
- db = client["userdb"] # database
20
- users_col = db["users"] # collection tương đương bảng user
21
-
22
 
23
  # ========================
24
- # REGISTER USER
25
  # ========================
 
 
 
 
 
 
 
 
 
 
 
26
 
27
-
28
- from deepface import DeepFace
29
- import cv2
30
- import numpy as np
31
- import base64
32
-
33
- @app.route('/api/register', methods=['POST'])
34
- def register():
35
- data = request.json
36
-
37
  username = data.get('username')
38
  password = data.get('password')
39
  img_data = data.get('img')
40
-
41
  fullName = data.get('fullName')
42
  email = data.get('email')
43
  phone = data.get('phone')
44
  gender = data.get('gender')
45
 
46
- # Kiểm tra dữ liệu bắt buộc
47
  if not username or not password or not img_data:
48
- return jsonify({'error': 'username, password và ảnh là bắt buộc'}), 400
49
 
50
  img_str = img_data.split(",")[1] if "," in img_data else img_data
51
-
52
- # Kiểm tra Base64 hợp lệ
53
  try:
54
  decoded = base64.b64decode(img_str)
55
- except Exception:
56
- return jsonify({'error': 'Ảnh không hợp lệ, phải là Base64'}), 400
57
-
58
- # Chuyển base64 → ảnh OpenCV
59
- try:
60
  nparr = np.frombuffer(decoded, np.uint8)
61
  img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
62
-
63
  if img is None:
64
- return jsonify({'error': 'Ảnh không thể đọc được'}), 400
65
-
66
  except Exception:
67
- return jsonify({'error': 'Không thể xử lý ảnh'}), 400
68
 
69
- # ===== KIỂM TRA ẢNH CÓ MẶT KHÔNG =====
70
  try:
71
  DeepFace.extract_faces(img, enforce_detection=True)
72
  except Exception:
73
- return jsonify({'error': 'Ảnh không có khuôn mặt hợp lệ'}), 400
74
 
75
- try:
76
- # Kiểm tra username trùng
77
- existing_user = users_col.find_one({"userName": username})
78
- if existing_user:
79
- return jsonify({'error': 'Tên người dùng đã tồn tại'}), 409
80
-
81
- # Dữ liệu người dùng chỉ gồm các trường yêu cầu
82
- user_info = {
83
- "userName": username,
84
- "password": password,
85
- "img": img_str,
86
- "fullName": fullName,
87
- "email": email,
88
- "phone": phone,
89
- "gender": gender,
90
- }
91
-
92
- # Lưu vào MongoDB
93
- users_col.insert_one(user_info)
94
-
95
- return jsonify({'message': 'Đăng ký thành công!', 'user': username}), 201
96
 
97
- except Exception as e:
98
- return jsonify({'error': str(e)}), 500
99
- # LOGIN + KIỂM TRA KHUÔN MẶT
100
- # ========================
101
- @app.route('/api/login', methods=['POST'])
102
- def login():
103
- data = request.json
 
 
 
 
 
 
 
104
  username = data.get('username')
105
  password = data.get('password')
106
  img_data = data.get('img')
107
 
108
  if not username or not password or not img_data:
109
- return jsonify({'error': 'username, password và ảnh là bắt buộc'}), 400
110
 
111
  img_str = img_data.split(",")[1] if "," in img_data else img_data
 
 
 
112
 
113
  try:
114
- # Lấy user từ MongoDB
115
- user = users_col.find_one({"userName": username, "password": password})
116
-
117
- if not user:
118
- return jsonify({'error': 'Username hoặc password sai'}), 401
119
-
120
- # Base64 → ảnh
121
  nparr_input = np.frombuffer(base64.b64decode(img_str), np.uint8)
122
  img_input = cv2.imdecode(nparr_input, cv2.IMREAD_COLOR)
123
-
124
  nparr_db = np.frombuffer(base64.b64decode(user['img']), np.uint8)
125
  img_db = cv2.imdecode(nparr_db, cv2.IMREAD_COLOR)
126
-
127
- # So sánh mặt
128
- try:
129
- result = DeepFace.verify(img_input, img_db, enforce_detection=True)
130
- except Exception as e:
131
- return jsonify({'error': f'Lỗi khi nhận diện khuôn mặt: {e}'}), 400
132
-
133
- # Tính %
134
- distance = result.get("distance", 1)
135
- similarity = max(0, (1 - distance)) * 100
136
- similarity = round(similarity, 2)
137
-
138
- if result['verified']:
139
- token = secrets.token_hex(16)
140
-
141
- # Xóa _id vì không serializable
142
- user_info = {
143
- "userName": user.get("userName"),
144
- "fullName": user.get("fullName"),
145
- "email": user.get("email"),
146
- "phone": user.get("phone"),
147
- "gender": user.get("gender"),
148
- "img": user.get("img")
149
- }
150
-
151
- return jsonify({
152
- 'message': 'Login thành công!',
153
- 'token': token,
154
- 'similarity': similarity,
155
- 'user': user_info
156
- })
157
- else:
158
- return jsonify({
159
- 'error': 'Khuôn mặt không trùng khớp',
160
- 'similarity': similarity
161
- }), 401
162
-
163
  except Exception as e:
164
- return jsonify({'error': str(e)}), 500
165
 
166
- # ========================
167
- # PHÂN TÍCH KHUÔN MẶT
168
- # ========================
169
- def convert_numpy(obj):
170
- if isinstance(obj, dict):
171
- return {k: convert_numpy(v) for k, v in obj.items()}
172
- elif isinstance(obj, list):
173
- return [convert_numpy(i) for i in obj]
174
- elif isinstance(obj, (np.float32, np.float64)):
175
- return float(obj)
176
- elif isinstance(obj, (np.int32, np.int64)):
177
- return int(obj)
178
  else:
179
- return obj
180
 
181
- @app.route('/api/analyze', methods=['POST'])
182
- def analyze_face():
183
- data = request.json
184
- img_data = data.get('img')
185
 
 
 
186
  if not img_data:
187
- return jsonify({'error': 'Ảnh là bắt buộc'}), 400
188
-
189
  img_str = img_data.split(",")[1] if "," in img_data else img_data
190
-
191
  try:
192
  nparr = np.frombuffer(base64.b64decode(img_str), np.uint8)
193
  img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
194
-
195
  result = DeepFace.analyze(img, actions=['age','gender','emotion','race'], enforce_detection=True)
196
  result = convert_numpy(result)
197
-
198
- return jsonify({'result': result})
199
-
200
  except Exception as e:
201
- return jsonify({'error': f'Lỗi khi phân tích khuôn mặt: {e}'}), 400
202
 
203
- @app.route('/api/compare', methods=['POST'])
204
- def compare_faces():
205
- data = request.json
206
  img1_data = data.get("img1")
207
  img2_data = data.get("img2")
208
-
209
  if not img1_data or not img2_data:
210
- return jsonify({'error': 'Cần 2 ảnh base64 để so sánh'}), 400
211
-
212
- # Tách phần base64 (nếu có prefix data:image/png;base64,)
213
- img1_str = img1_data.split(",")[1] if "," in img1_data else img1_data
214
- img2_str = img2_data.split(",")[1] if "," in img2_data else img2_data
215
-
216
  try:
217
- # Base64 OpenCV image
218
- nparr1 = np.frombuffer(base64.b64decode(img1_str), np.uint8)
219
  img1 = cv2.imdecode(nparr1, cv2.IMREAD_COLOR)
220
-
221
- nparr2 = np.frombuffer(base64.b64decode(img2_str), np.uint8)
222
  img2 = cv2.imdecode(nparr2, cv2.IMREAD_COLOR)
223
-
224
- # So sánh khuôn mặt bằng DeepFace
225
- try:
226
- result = DeepFace.verify(img1, img2, enforce_detection=True)
227
- except Exception as e:
228
- return jsonify({'error': f'Lỗi nhận diện: {e}'}), 400
229
-
230
- # Tính phần trăm giống nhau
231
  distance = result.get("distance", 1)
232
  similarity = max(0, (1 - distance)) * 100
233
  similarity = round(similarity, 2)
234
-
235
- return jsonify({
236
- "verified": result.get("verified", False),
237
- "distance": distance,
238
- "similarity": similarity
239
- })
240
-
241
  except Exception as e:
242
- return jsonify({'error': str(e)}), 500
243
 
244
  # ========================
245
- # RUN
246
  # ========================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
 
248
- if __name__ == '__main__':
249
- port = int(os.environ.get("PORT", 7860))
250
- app.run(host='0.0.0.0', port=port, debug=True)
 
1
+ import os
2
+ import json
3
  import base64
4
  import secrets
 
 
 
5
  import numpy as np
6
+ import cv2
7
+ from deepface import DeepFace
8
  from pymongo import MongoClient
9
+ import gradio as gr
 
10
 
11
  # ========================
12
+ # MongoDB connection
13
  # ========================
14
  mongo_uri = "mongodb+srv://huyh01480_db_user:zxvAwzAhr8yk3lWe@cluster0.n8pboqq.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0"
15
  client = MongoClient(mongo_uri)
16
+ db = client["userdb"]
17
+ users_col = db["users"]
 
 
18
 
19
  # ========================
20
+ # Helper functions
21
  # ========================
22
+ def convert_numpy(obj):
23
+ if isinstance(obj, dict):
24
+ return {k: convert_numpy(v) for k, v in obj.items()}
25
+ elif isinstance(obj, list):
26
+ return [convert_numpy(i) for i in obj]
27
+ elif isinstance(obj, (np.float32, np.float64)):
28
+ return float(obj)
29
+ elif isinstance(obj, (np.int32, np.int64)):
30
+ return int(obj)
31
+ else:
32
+ return obj
33
 
34
+ # ========================
35
+ # Internal API functions
36
+ # ========================
37
+ def register_internal(data):
 
 
 
 
 
 
38
  username = data.get('username')
39
  password = data.get('password')
40
  img_data = data.get('img')
 
41
  fullName = data.get('fullName')
42
  email = data.get('email')
43
  phone = data.get('phone')
44
  gender = data.get('gender')
45
 
 
46
  if not username or not password or not img_data:
47
+ return {'error': 'username, password và ảnh là bắt buộc'}, 400
48
 
49
  img_str = img_data.split(",")[1] if "," in img_data else img_data
 
 
50
  try:
51
  decoded = base64.b64decode(img_str)
 
 
 
 
 
52
  nparr = np.frombuffer(decoded, np.uint8)
53
  img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
 
54
  if img is None:
55
+ return {'error': 'Ảnh không thể đọc được'}, 400
 
56
  except Exception:
57
+ return {'error': 'Ảnh không hợp lệ'}, 400
58
 
 
59
  try:
60
  DeepFace.extract_faces(img, enforce_detection=True)
61
  except Exception:
62
+ return {'error': 'Ảnh không có khuôn mặt hợp lệ'}, 400
63
 
64
+ if users_col.find_one({"userName": username}):
65
+ return {'error': 'Tên người dùng đã tồn tại'}, 409
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
+ user_info = {
68
+ "userName": username,
69
+ "password": password,
70
+ "img": img_str,
71
+ "fullName": fullName,
72
+ "email": email,
73
+ "phone": phone,
74
+ "gender": gender,
75
+ }
76
+ users_col.insert_one(user_info)
77
+ return {'message': 'Đăng ký thành công!', 'user': username}, 201
78
+
79
+
80
+ def login_internal(data):
81
  username = data.get('username')
82
  password = data.get('password')
83
  img_data = data.get('img')
84
 
85
  if not username or not password or not img_data:
86
+ return {'error': 'username, password và ảnh là bắt buộc'}, 400
87
 
88
  img_str = img_data.split(",")[1] if "," in img_data else img_data
89
+ user = users_col.find_one({"userName": username, "password": password})
90
+ if not user:
91
+ return {'error': 'Username hoặc password sai'}, 401
92
 
93
  try:
 
 
 
 
 
 
 
94
  nparr_input = np.frombuffer(base64.b64decode(img_str), np.uint8)
95
  img_input = cv2.imdecode(nparr_input, cv2.IMREAD_COLOR)
 
96
  nparr_db = np.frombuffer(base64.b64decode(user['img']), np.uint8)
97
  img_db = cv2.imdecode(nparr_db, cv2.IMREAD_COLOR)
98
+ result = DeepFace.verify(img_input, img_db, enforce_detection=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  except Exception as e:
100
+ return {'error': f'Lỗi khi nhận diện khuôn mặt: {e}'}, 400
101
 
102
+ distance = result.get("distance", 1)
103
+ similarity = max(0, (1 - distance)) * 100
104
+ similarity = round(similarity, 2)
105
+
106
+ if result['verified']:
107
+ token = secrets.token_hex(16)
108
+ user_info = {k: user[k] for k in ["userName", "fullName", "email", "phone", "gender", "img"]}
109
+ return {'message': 'Login thành công!', 'token': token, 'similarity': similarity, 'user': user_info}, 200
 
 
 
 
110
  else:
111
+ return {'error': 'Khuôn mặt không trùng khớp', 'similarity': similarity}, 401
112
 
 
 
 
 
113
 
114
+ def analyze_internal(data):
115
+ img_data = data.get('img')
116
  if not img_data:
117
+ return {'error': 'Ảnh là bắt buộc'}, 400
 
118
  img_str = img_data.split(",")[1] if "," in img_data else img_data
 
119
  try:
120
  nparr = np.frombuffer(base64.b64decode(img_str), np.uint8)
121
  img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
 
122
  result = DeepFace.analyze(img, actions=['age','gender','emotion','race'], enforce_detection=True)
123
  result = convert_numpy(result)
124
+ return {'result': result}, 200
 
 
125
  except Exception as e:
126
+ return {'error': f'Lỗi khi phân tích khuôn mặt: {e}'}, 400
127
 
128
+
129
+ def compare_internal(data):
 
130
  img1_data = data.get("img1")
131
  img2_data = data.get("img2")
 
132
  if not img1_data or not img2_data:
133
+ return {'error': 'Cần 2 ảnh base64 để so sánh'}, 400
 
 
 
 
 
134
  try:
135
+ nparr1 = np.frombuffer(base64.b64decode(img1_data.split(",")[1] if "," in img1_data else img1_data), np.uint8)
 
136
  img1 = cv2.imdecode(nparr1, cv2.IMREAD_COLOR)
137
+ nparr2 = np.frombuffer(base64.b64decode(img2_data.split(",")[1] if "," in img2_data else img2_data), np.uint8)
 
138
  img2 = cv2.imdecode(nparr2, cv2.IMREAD_COLOR)
139
+ result = DeepFace.verify(img1, img2, enforce_detection=True)
 
 
 
 
 
 
 
140
  distance = result.get("distance", 1)
141
  similarity = max(0, (1 - distance)) * 100
142
  similarity = round(similarity, 2)
143
+ return {"verified": result.get("verified", False), "distance": distance, "similarity": similarity}, 200
 
 
 
 
 
 
144
  except Exception as e:
145
+ return {'error': str(e)}, 500
146
 
147
  # ========================
148
+ # Gradio wrapper
149
  # ========================
150
+ def gradio_handler(json_str, action="login"):
151
+ try:
152
+ data = json.loads(json_str)
153
+ except Exception:
154
+ return json.dumps({'error': 'Invalid JSON input'})
155
+
156
+ if action == "register":
157
+ res, status = register_internal(data)
158
+ elif action == "login":
159
+ res, status = login_internal(data)
160
+ elif action == "analyze":
161
+ res, status = analyze_internal(data)
162
+ elif action == "compare":
163
+ res, status = compare_internal(data)
164
+ else:
165
+ res = {'error': 'Unknown action'}
166
+ return json.dumps(res)
167
+
168
+
169
+ iface = gr.Interface(
170
+ fn=gradio_handler,
171
+ inputs=[gr.Textbox(label="JSON input"), gr.Dropdown(["register","login","analyze","compare"], label="Action")],
172
+ outputs="textbox",
173
+ live=False
174
+ )
175
 
176
+ iface.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))