Spaces:
Runtime error
Runtime error
| """ | |
| api/persons.py — Endpoints quản lý thông tin Person | |
| GET /api/persons — Danh sách tất cả persons có embedding | |
| PUT /api/persons/<id> — Cập nhật thông tin cá nhân | |
| DELETE /api/persons/<id> — Xóa person (cascade: visits, embeddings, logs, MongoDB) | |
| DELETE /api/db/<filename> — Legacy alias xóa theo tên file (backward compat) | |
| """ | |
| import logging | |
| from flask import Blueprint, jsonify, request | |
| from face_model.analyzer import face_analyzer | |
| from storage.mongo_storage import mongo_storage | |
| from storage.pg_storage import pg_storage | |
| logger = logging.getLogger("api.persons") | |
| bp = Blueprint("persons", __name__, url_prefix="/api") | |
| def list_persons(): | |
| """ | |
| GET /api/persons | |
| Trả về danh sách tất cả persons có face_embedding active. | |
| """ | |
| try: | |
| persons = pg_storage.list_persons_with_faces() | |
| for p in persons: | |
| crop_id = p.get("face_crop_mongo_id", "") | |
| p["face_url"] = f"/api/face-crops/{crop_id}" if crop_id else None | |
| return jsonify({ | |
| "total": len(persons), | |
| "persons": persons, | |
| }), 200 | |
| except Exception as e: | |
| logger.error(f"[list_persons] Error: {e}", exc_info=True) | |
| return jsonify({"error": { | |
| "code": "FETCH_FAILED", | |
| "message": f"Không thể lấy danh sách persons: {e}", | |
| "status": 500, | |
| }}), 500 | |
| def update_person(person_id: str): | |
| """ | |
| PUT /api/persons/<person_id> | |
| Body JSON: { full_name, date_of_birth?, phone_number?, address? } | |
| """ | |
| body = request.get_json(silent=True) | |
| if not body or "full_name" not in body: | |
| return jsonify({"error": { | |
| "code": "VALIDATION_ERROR", | |
| "message": "Thiếu trường bắt buộc: full_name.", | |
| "status": 400, | |
| }}), 400 | |
| full_name = body["full_name"].strip() | |
| date_of_birth = body.get("date_of_birth") | |
| phone_number = body.get("phone_number") | |
| address = body.get("address") | |
| if not full_name: | |
| return jsonify({"error": { | |
| "code": "VALIDATION_ERROR", | |
| "message": "full_name không được để trống.", | |
| "status": 400, | |
| }}), 400 | |
| try: | |
| updated = pg_storage.update_person_info( | |
| person_id=person_id, | |
| full_name=full_name, | |
| date_of_birth=date_of_birth, | |
| phone_number=phone_number, | |
| address=address, | |
| ) | |
| if not updated: | |
| return jsonify({"error": { | |
| "code": "NOT_FOUND", | |
| "message": f"Không tìm thấy person với ID: {person_id}", | |
| "status": 404, | |
| }}), 404 | |
| # Cập nhật tên trong RAM cache | |
| face_analyzer.update_name_in_cache(person_id, full_name) | |
| return jsonify({ | |
| "success": True, | |
| "person_id": person_id, | |
| "full_name": full_name, | |
| "message": f"Đã cập nhật thông tin cho {full_name}.", | |
| }), 200 | |
| except Exception as e: | |
| logger.error(f"[update_person] Error: {e}", exc_info=True) | |
| return jsonify({"error": { | |
| "code": "UPDATE_FAILED", | |
| "message": f"Không thể cập nhật thông tin: {e}", | |
| "status": 500, | |
| }}), 500 | |
| def delete_person(person_id: str): | |
| """ | |
| DELETE /api/persons/<person_id> | |
| Xóa person và toàn bộ dữ liệu liên quan (cascade). | |
| """ | |
| try: | |
| success, mongo_ids = pg_storage.delete_person(person_id) | |
| if not success: | |
| return jsonify({"error": { | |
| "code": "NOT_FOUND", | |
| "message": f"Không tìm thấy person với ID: {person_id}", | |
| "status": 404, | |
| }}), 404 | |
| # Xóa ảnh crop trên MongoDB | |
| for mid in mongo_ids: | |
| mongo_storage.delete_face_crop(mid) | |
| # Xóa khỏi RAM cache | |
| face_analyzer.remove_from_cache(person_id) | |
| return jsonify({ | |
| "success": True, | |
| "person_id": person_id, | |
| "message": "Đã xóa person thành công.", | |
| "total_faces": face_analyzer.total, | |
| }), 200 | |
| except Exception as e: | |
| logger.error(f"[delete_person] Error: {e}", exc_info=True) | |
| return jsonify({"error": { | |
| "code": "DELETE_FAILED", | |
| "message": f"Không thể xóa person: {e}", | |
| "status": 500, | |
| }}), 500 | |
| # ── Legacy endpoints ─────────────────────────────────────────────────────── | |
| def update_person_legacy(person_id: str): | |
| """Legacy alias → PUT /api/persons/<person_id>""" | |
| return update_person(person_id) | |