huy00001 commited on
Commit
90742b5
·
verified ·
1 Parent(s): 754959c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +235 -126
app.py CHANGED
@@ -1,138 +1,247 @@
1
- from PIL import Image
2
- from io import BytesIO
3
- import numpy as np
4
  import base64
5
- import uuid
6
- import pymongo
7
- import certifi
8
  from deepface import DeepFace
9
- import gradio as gr
10
- import json
11
-
12
- # =======================
13
- # MongoDB setup
14
- # =======================
15
- client = pymongo.MongoClient(
16
- "mongodb+srv://username:password@cluster0.n8pboqq.mongodb.net/?retryWrites=true&w=majority",
17
- tlsCAFile=certifi.where()
18
- )
19
- db = client["faceDB"]
20
- face_collection = db["faceImg"]
21
-
22
- # =======================
23
- # Upload ảnh + MongoDB
24
- # =======================
25
- def upload_image(image, name):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  try:
27
- if isinstance(image, Image.Image):
28
- image = np.array(image)
29
-
30
- image_id = str(uuid.uuid4())
31
- pil_image = Image.fromarray(image)
32
- buffer = BytesIO()
33
- pil_image.save(buffer, format="PNG")
34
- img_bytes = buffer.getvalue()
35
- img_base64 = base64.b64encode(img_bytes).decode('utf-8')
36
-
37
- doc = {
38
- "_id": image_id,
39
- "name": name,
40
- "image": img_base64
41
  }
42
- face_collection.insert_one(doc)
43
 
44
- return f"✅ Upload thành công!\nID: {image_id}\nTên: {name}", image_id
 
 
 
 
45
  except Exception as e:
46
- return f"❌ Lỗi upload: {str(e)}", None
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- # =======================
49
- # Nhận diện khuôn mặt
50
- # =======================
51
- def recognize_face(image, image_id):
52
  try:
53
- doc = face_collection.find_one({"_id": image_id})
54
- if not doc:
55
- return "❌ Ảnh ID không tồn tại"
56
-
57
- # Decode base64 lưu tạm
58
- img_bytes = base64.b64decode(doc['image'])
59
- temp_path = f"temp_{image_id}.png"
60
- with open(temp_path, "wb") as f:
61
- f.write(img_bytes)
62
-
63
- # Lưu input ảnh tạm
64
- if isinstance(image, Image.Image):
65
- image = np.array(image)
66
- pil_input = Image.fromarray(image)
67
- input_path = f"input_{image_id}.png"
68
- pil_input.save(input_path)
69
-
70
- result = DeepFace.verify(img1_path=input_path, img2_path=temp_path)
71
- output = {
72
- "Verified": result["verified"],
73
- "Khoảng cách": round(result["distance"], 4),
74
- "Tên ảnh gốc": doc['name']
75
- }
76
- return json.dumps(output, ensure_ascii=False, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  except Exception as e:
78
- return f"❌ Lỗi nhận diện: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
- # =======================
81
- # Phân tích khuôn mặt
82
- # =======================
83
- def analyze_face(image):
84
  try:
85
- if isinstance(image, Image.Image):
86
- image = np.array(image)
87
- pil_image = Image.fromarray(image)
88
- temp_path = f"analyze_{uuid.uuid4().hex}.png"
89
- pil_image.save(temp_path)
90
-
91
- result = DeepFace.analyze(
92
- img_path=temp_path,
93
- actions=["age", "gender", "emotion", "race"],
94
- enforce_detection=False
95
- )
96
- info = result[0]
97
- output = {
98
- "Tuổi ước tính": info["age"],
99
- "Giới tính": "Nam" if info["dominant_gender"] == "Man" else "Nữ",
100
- "Cảm xúc chính": info["dominant_emotion"],
101
- "Chủng tộc": info["dominant_race"]
102
- }
103
- return json.dumps(output, ensure_ascii=False, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  except Exception as e:
105
- return f"❌ Lỗi phân tích: {str(e)}"
106
-
107
- # =======================
108
- # Gradio interface
109
- # =======================
110
- with gr.Blocks() as demo:
111
- gr.Markdown("## 📁 Upload ảnh vào MongoDB")
112
- with gr.Row():
113
- upload_input = gr.Image(label="Upload ảnh", type="numpy")
114
- name_input = gr.Textbox(label="Tên người trong ảnh")
115
- upload_btn = gr.Button("Upload")
116
- upload_output = gr.Textbox(label="Kết quả Upload")
117
- image_id_store = gr.State()
118
-
119
- upload_btn.click(upload_image, inputs=[upload_input, name_input], outputs=[upload_output, image_id_store])
120
-
121
- gr.Markdown("## 🆔 Nhận diện khuôn mặt")
122
- with gr.Row():
123
- recognize_input = gr.Image(label="Ảnh cần nhận diện", type="numpy")
124
- recognize_btn = gr.Button("Nhận diện")
125
- recognize_output = gr.Textbox(label="Kết quả nhận diện")
126
-
127
- recognize_btn.click(recognize_face, inputs=[recognize_input, image_id_store], outputs=recognize_output)
128
-
129
- gr.Markdown("## 🔍 Phân tích khuôn mặt")
130
- with gr.Row():
131
- analyze_input = gr.Image(label="Ảnh cần phân tích", type="numpy")
132
- analyze_btn = gr.Button("Phân tích")
133
- analyze_output = gr.Textbox(label="Kết quả phân tích")
134
-
135
- analyze_btn.click(analyze_face, inputs=analyze_input, outputs=analyze_output)
136
-
137
- if __name__ == "__main__":
138
- demo.launch()
 
1
+ from flask import Flask, request, jsonify
2
+ from flask_cors import CORS
 
3
  import base64
4
+ import secrets
 
 
5
  from deepface import DeepFace
6
+ import cv2
7
+ import numpy as np
8
+ from pymongo import MongoClient
9
+ app = Flask(__name__)
10
+ CORS(app)
11
+
12
+ # ========================
13
+ # KẾT NỐI MONGODB
14
+ # ========================
15
+ mongo_uri = "mongodb+srv://huyh01480_db_user:zxvAwzAhr8yk3lWe@cluster0.n8pboqq.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0"
16
+ client = MongoClient(mongo_uri)
17
+
18
+ db = client["userdb"] # database
19
+ users_col = db["users"] # collection tương đương bảng user
20
+
21
+
22
+ # ========================
23
+ # REGISTER USER
24
+ # ========================
25
+
26
+
27
+ from deepface import DeepFace
28
+ import cv2
29
+ import numpy as np
30
+ import base64
31
+
32
+ @app.route('/api/register', methods=['POST'])
33
+ def register():
34
+ data = request.json
35
+
36
+ username = data.get('username')
37
+ password = data.get('password')
38
+ img_data = data.get('img')
39
+
40
+ fullName = data.get('fullName')
41
+ email = data.get('email')
42
+ phone = data.get('phone')
43
+ gender = data.get('gender')
44
+
45
+ # Kiểm tra dữ liệu bắt buộc
46
+ if not username or not password or not img_data:
47
+ return jsonify({'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
+
51
+ # Kiểm tra Base64 hợp lệ
52
+ try:
53
+ decoded = base64.b64decode(img_str)
54
+ except Exception:
55
+ return jsonify({'error': 'Ảnh không hợp lệ, phải là Base64'}), 400
56
+
57
+ # Chuyển base64 → ảnh OpenCV
58
+ try:
59
+ nparr = np.frombuffer(decoded, np.uint8)
60
+ img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
61
+
62
+ if img is None:
63
+ return jsonify({'error': 'Ảnh không thể đọc được'}), 400
64
+
65
+ except Exception:
66
+ return jsonify({'error': 'Không thể xử lý ảnh'}), 400
67
+
68
+ # ===== KIỂM TRA ẢNH CÓ MẶT KHÔNG =====
69
+ try:
70
+ DeepFace.extract_faces(img, enforce_detection=True)
71
+ except Exception:
72
+ return jsonify({'error': 'Ảnh không có khuôn mặt hợp lệ'}), 400
73
+
74
  try:
75
+ # Kiểm tra username trùng
76
+ existing_user = users_col.find_one({"userName": username})
77
+ if existing_user:
78
+ return jsonify({'error': 'Tên người dùng đã tồn tại'}), 409
79
+
80
+ # Dữ liệu người dùng chỉ gồm các trường yêu cầu
81
+ user_info = {
82
+ "userName": username,
83
+ "password": password,
84
+ "img": img_str,
85
+ "fullName": fullName,
86
+ "email": email,
87
+ "phone": phone,
88
+ "gender": gender,
89
  }
 
90
 
91
+ # Lưu vào MongoDB
92
+ users_col.insert_one(user_info)
93
+
94
+ return jsonify({'message': 'Đăng ký thành công!', 'user': username}), 201
95
+
96
  except Exception as e:
97
+ return jsonify({'error': str(e)}), 500
98
+ # LOGIN + KIỂM TRA KHUÔN MẶT
99
+ # ========================
100
+ @app.route('/api/login', methods=['POST'])
101
+ def login():
102
+ data = request.json
103
+ username = data.get('username')
104
+ password = data.get('password')
105
+ img_data = data.get('img')
106
+
107
+ if not username or not password or not img_data:
108
+ return jsonify({'error': 'username, password và ảnh là bắt buộc'}), 400
109
+
110
+ img_str = img_data.split(",")[1] if "," in img_data else img_data
111
 
 
 
 
 
112
  try:
113
+ # Lấy user từ MongoDB
114
+ user = users_col.find_one({"userName": username, "password": password})
115
+
116
+ if not user:
117
+ return jsonify({'error': 'Username hoặc password sai'}), 401
118
+
119
+ # Base64 → ảnh
120
+ nparr_input = np.frombuffer(base64.b64decode(img_str), np.uint8)
121
+ img_input = cv2.imdecode(nparr_input, cv2.IMREAD_COLOR)
122
+
123
+ nparr_db = np.frombuffer(base64.b64decode(user['img']), np.uint8)
124
+ img_db = cv2.imdecode(nparr_db, cv2.IMREAD_COLOR)
125
+
126
+ # So sánh mặt
127
+ try:
128
+ result = DeepFace.verify(img_input, img_db, enforce_detection=True)
129
+ except Exception as e:
130
+ return jsonify({'error': f'Lỗi khi nhận diện khuôn mặt: {e}'}), 400
131
+
132
+ # Tính %
133
+ distance = result.get("distance", 1)
134
+ similarity = max(0, (1 - distance)) * 100
135
+ similarity = round(similarity, 2)
136
+
137
+ if result['verified']:
138
+ token = secrets.token_hex(16)
139
+
140
+ # Xóa _id vì không serializable
141
+ user_info = {
142
+ "userName": user.get("userName"),
143
+ "fullName": user.get("fullName"),
144
+ "email": user.get("email"),
145
+ "phone": user.get("phone"),
146
+ "gender": user.get("gender"),
147
+ "img": user.get("img")
148
+ }
149
+
150
+ return jsonify({
151
+ 'message': 'Login thành công!',
152
+ 'token': token,
153
+ 'similarity': similarity,
154
+ 'user': user_info
155
+ })
156
+ else:
157
+ return jsonify({
158
+ 'error': 'Khuôn mặt không trùng khớp',
159
+ 'similarity': similarity
160
+ }), 401
161
+
162
  except Exception as e:
163
+ return jsonify({'error': str(e)}), 500
164
+
165
+ # ========================
166
+ # PHÂN TÍCH KHUÔN MẶT
167
+ # ========================
168
+ def convert_numpy(obj):
169
+ if isinstance(obj, dict):
170
+ return {k: convert_numpy(v) for k, v in obj.items()}
171
+ elif isinstance(obj, list):
172
+ return [convert_numpy(i) for i in obj]
173
+ elif isinstance(obj, (np.float32, np.float64)):
174
+ return float(obj)
175
+ elif isinstance(obj, (np.int32, np.int64)):
176
+ return int(obj)
177
+ else:
178
+ return obj
179
+
180
+ @app.route('/api/analyze', methods=['POST'])
181
+ def analyze_face():
182
+ data = request.json
183
+ img_data = data.get('img')
184
+
185
+ if not img_data:
186
+ return jsonify({'error': 'Ảnh là bắt buộc'}), 400
187
+
188
+ img_str = img_data.split(",")[1] if "," in img_data else img_data
189
 
 
 
 
 
190
  try:
191
+ nparr = np.frombuffer(base64.b64decode(img_str), np.uint8)
192
+ img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
193
+
194
+ result = DeepFace.analyze(img, actions=['age','gender','emotion','race'], enforce_detection=True)
195
+ result = convert_numpy(result)
196
+
197
+ return jsonify({'result': result})
198
+
199
+ except Exception as e:
200
+ return jsonify({'error': f'Lỗi khi phân tích khuôn mặt: {e}'}), 400
201
+
202
+ @app.route('/api/compare', methods=['POST'])
203
+ def compare_faces():
204
+ data = request.json
205
+ img1_data = data.get("img1")
206
+ img2_data = data.get("img2")
207
+
208
+ if not img1_data or not img2_data:
209
+ return jsonify({'error': 'Cần 2 ảnh base64 để so sánh'}), 400
210
+
211
+ # Tách phần base64 (nếu có prefix data:image/png;base64,)
212
+ img1_str = img1_data.split(",")[1] if "," in img1_data else img1_data
213
+ img2_str = img2_data.split(",")[1] if "," in img2_data else img2_data
214
+
215
+ try:
216
+ # Base64 → OpenCV image
217
+ nparr1 = np.frombuffer(base64.b64decode(img1_str), np.uint8)
218
+ img1 = cv2.imdecode(nparr1, cv2.IMREAD_COLOR)
219
+
220
+ nparr2 = np.frombuffer(base64.b64decode(img2_str), np.uint8)
221
+ img2 = cv2.imdecode(nparr2, cv2.IMREAD_COLOR)
222
+
223
+ # So sánh khuôn mặt bằng DeepFace
224
+ try:
225
+ result = DeepFace.verify(img1, img2, enforce_detection=True)
226
+ except Exception as e:
227
+ return jsonify({'error': f'Lỗi nhận diện: {e}'}), 400
228
+
229
+ # Tính phần trăm giống nhau
230
+ distance = result.get("distance", 1)
231
+ similarity = max(0, (1 - distance)) * 100
232
+ similarity = round(similarity, 2)
233
+
234
+ return jsonify({
235
+ "verified": result.get("verified", False),
236
+ "distance": distance,
237
+ "similarity": similarity
238
+ })
239
+
240
  except Exception as e:
241
+ return jsonify({'error': str(e)}), 500
242
+
243
+ # ========================
244
+ # RUN
245
+ # ========================
246
+ if __name__ == '__main__':
247
+ app.run(debug=True)