""" app.py — Entry point: khởi tạo Flask, đăng ký blueprints, xử lý lỗi chuẩn. Cấu trúc module: config.py — Biến môi trường utils/image.py — Tiện ích xử lý ảnh storage/ mongo_storage — MongoDB: raw_images, face_crops, unknown_faces, recognition_payloads pg_storage — Supabase: persons, visits, face_embeddings, recognition_logs face_model/ analyzer — InsightFace singleton + RAM cache api/ system — GET /api/health, POST /api/database/reload recognize — POST /api/recognitions (+ legacy /api/recognize) faces — POST /api/faces, GET /api/face-crops/ persons — GET/PUT/DELETE /api/persons/ database — GET /api/faces, /api/db, DELETE /api/db/, GET /api/unknown-faces """ import logging import sys from flask import Flask, jsonify from flask_cors import CORS import config from face_model.analyzer import face_analyzer from storage.pg_storage import pg_storage # ── Logging ─────────────────────────────────────────────────────────────── logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s — %(message)s", ) logger = logging.getLogger("app") # ── Flask Init ──────────────────────────────────────────────────────────── app = Flask(__name__) CORS(app, resources={r"/api/*": {"origins": "*"}}, supports_credentials=True) # ── Register Blueprints ─────────────────────────────────────────────────── from api.system import bp as system_bp from api.recognize import bp as recognize_bp from api.faces import bp as faces_bp from api.persons import bp as persons_bp from api.database import bp as database_bp app.register_blueprint(system_bp) app.register_blueprint(recognize_bp) app.register_blueprint(faces_bp) app.register_blueprint(persons_bp) app.register_blueprint(database_bp) # ── Root Route ──────────────────────────────────────────────────────────── @app.route("/") def index(): return jsonify({ "status": "success", "message": "FaceID AI Service is running successfully on HuggingFace Spaces!", "endpoints": { "health_check": "/api/health", "recognize": "/api/recognitions", "faces": "/api/faces" } }), 200 # ── Global Error Handlers ───────────────────────────────────────────────── @app.errorhandler(404) def not_found(e): return jsonify({"error": {"code": "NOT_FOUND", "message": str(e), "status": 404}}), 404 @app.errorhandler(405) def method_not_allowed(e): return jsonify({"error": {"code": "METHOD_NOT_ALLOWED", "message": str(e), "status": 405}}), 405 @app.errorhandler(500) def internal_error(e): return jsonify({"error": {"code": "INTERNAL_ERROR", "message": str(e), "status": 500}}), 500 # ── Startup: Model + DB Cache ───────────────────────────────────────────── def startup(): # 1. Khởi tạo InsightFace try: face_analyzer.initialize() except Exception as e: logger.critical(f"Failed to initialize InsightFace: {e}", exc_info=True) sys.exit(1) # 2. Load embeddings từ Supabase vào RAM try: records = pg_storage.load_all_embeddings() face_analyzer.reload_cache(records) except Exception as e: logger.warning(f"[Startup] Supabase load failed: {e}. Falling back to local folder...") try: face_analyzer.reload_from_local_folder(config.DB_FOLDER) except Exception as fe: logger.warning(f"[Startup] Local fallback also failed: {fe}") logger.info( f"[Startup] Ready. Model={config.MODEL_NAME}, " f"Embeddings={face_analyzer.total}, Port={config.PORT}" ) # Khởi chạy startup khi import (cần thiết cho Gunicorn) startup() # ── Main ────────────────────────────────────────────────────────────────── if __name__ == "__main__": logger.info(f"Starting Flask RESTful API on {config.HOST}:{config.PORT} ...") app.run(host=config.HOST, port=config.PORT, debug=False)