Spaces:
Sleeping
Sleeping
| """ | |
| KYC POC API - Main Application Entry Point | |
| This is a FastAPI application for KYC (Know Your Customer) verification | |
| using face matching (AuraFace) and liveness detection (Silent-Face-Anti-Spoofing). | |
| Run with: | |
| uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 | |
| """ | |
| import logging | |
| from contextlib import asynccontextmanager | |
| from concurrent.futures import ThreadPoolExecutor | |
| import asyncio | |
| from fastapi import FastAPI, Request | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import JSONResponse | |
| from fastapi.exceptions import RequestValidationError | |
| from .config import settings | |
| from .api.routes import health, kyc, kyc_base64, ocr | |
| from .services.face_recognition import face_recognition_service | |
| from .services.liveness_detection import liveness_detection_service | |
| from .services.ktp_ocr import ktp_ocr_service | |
| # Configure logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # Thread pool for ML model initialization | |
| executor = ThreadPoolExecutor(max_workers=3) | |
| async def lifespan(app: FastAPI): | |
| """ | |
| Application lifespan manager. | |
| Initializes ML models on startup and cleans up on shutdown. | |
| """ | |
| logger.info("Starting KYC POC API...") | |
| # Initialize ML models in background threads | |
| loop = asyncio.get_event_loop() | |
| try: | |
| # Initialize face recognition service | |
| logger.info("Initializing face recognition service...") | |
| await loop.run_in_executor(executor, face_recognition_service.initialize) | |
| logger.info("Face recognition service ready") | |
| except Exception as e: | |
| logger.error(f"Failed to initialize face recognition: {e}") | |
| try: | |
| # Initialize liveness detection service | |
| logger.info("Initializing liveness detection service...") | |
| await loop.run_in_executor(executor, liveness_detection_service.initialize) | |
| logger.info("Liveness detection service ready") | |
| except Exception as e: | |
| logger.error(f"Failed to initialize liveness detection: {e}") | |
| try: | |
| # Initialize KTP OCR service | |
| logger.info("Initializing KTP OCR service...") | |
| await loop.run_in_executor(executor, ktp_ocr_service.initialize) | |
| logger.info("KTP OCR service ready") | |
| except Exception as e: | |
| logger.error(f"Failed to initialize KTP OCR: {e}") | |
| logger.info("KYC POC API started successfully") | |
| yield | |
| # Cleanup on shutdown | |
| logger.info("Shutting down KYC POC API...") | |
| executor.shutdown(wait=True) | |
| logger.info("Shutdown complete") | |
| # Create FastAPI application | |
| app = FastAPI( | |
| title=settings.APP_NAME, | |
| version=settings.APP_VERSION, | |
| description=""" | |
| ## KYC POC API | |
| A proof-of-concept API for KYC (Know Your Customer) verification using: | |
| - **AuraFace** for face recognition and matching | |
| - **Silent-Face-Anti-Spoofing** for liveness detection | |
| - **EasyOCR** for KTP text extraction | |
| ### Features | |
| - Face matching between KTP (ID card) and selfie | |
| - Liveness detection to prevent spoofing | |
| - Face quality analysis (blur, brightness, pose) | |
| - Age and gender estimation | |
| - **KTP OCR**: Extract and parse Indonesian ID card data (NIK, name, address, etc.) | |
| - **NIK Validation**: Validate and decode NIK information | |
| ### Endpoints | |
| - **File Upload**: `/api/v1/kyc/*` - Accepts multipart/form-data | |
| - **Base64**: `/api/v1/kyc/base64/*` - Accepts JSON with base64 images | |
| - **OCR**: `/api/v1/kyc/ocr/*` - KTP text extraction and NIK validation | |
| """, | |
| docs_url="/docs", | |
| redoc_url="/redoc", | |
| lifespan=lifespan | |
| ) | |
| # Add CORS middleware | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # ============================================================================ | |
| # Exception Handlers | |
| # ============================================================================ | |
| async def validation_exception_handler(request: Request, exc: RequestValidationError): | |
| """Handle request validation errors.""" | |
| errors = exc.errors() | |
| return JSONResponse( | |
| status_code=422, | |
| content={ | |
| "error_code": "VALIDATION_ERROR", | |
| "message": "Request validation failed", | |
| "detail": errors | |
| } | |
| ) | |
| async def general_exception_handler(request: Request, exc: Exception): | |
| """Handle unexpected errors.""" | |
| logger.error(f"Unexpected error: {exc}", exc_info=True) | |
| return JSONResponse( | |
| status_code=500, | |
| content={ | |
| "error_code": "INTERNAL_ERROR", | |
| "message": "An unexpected error occurred", | |
| "detail": str(exc) if settings.DEBUG else None | |
| } | |
| ) | |
| # ============================================================================ | |
| # Register Routes | |
| # ============================================================================ | |
| # Health check routes (no prefix) | |
| app.include_router(health.router) | |
| # KYC routes (file upload) | |
| app.include_router(kyc.router, prefix="/api/v1") | |
| # KYC routes (base64) | |
| app.include_router(kyc_base64.router, prefix="/api/v1") | |
| # OCR routes | |
| app.include_router(ocr.router, prefix="/api/v1") | |
| # ============================================================================ | |
| # Main Entry Point | |
| # ============================================================================ | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run( | |
| "app.main:app", | |
| host="0.0.0.0", | |
| port=8000, | |
| reload=settings.DEBUG | |
| ) | |