import json import logging import logging.config import time import uuid import yaml from fastapi import FastAPI, Request from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse from surya.endpoint.legacy import router as legacy_router from surya.endpoint.openai import router as openai_router from surya.endpoint.service import _error_response with open("logger.yaml", "r", encoding="utf-8") as f: config = yaml.safe_load(f.read()) logging.config.dictConfig(config) logger = logging.getLogger(__name__) app = FastAPI( title="OCR SERVICE API SERVICE", version="1.0", docs_url="/v1/api/ai/swagger", openapi_url="/v1/api/ai/openapi.json", ) @app.exception_handler(RequestValidationError) async def validation_exception_handler(request: Request, exc: RequestValidationError): request_id = getattr(request.state, "request_id", "-") logger.warning( "request_validation_failed request_id=%s method=%s path=%s errors=%s", request_id, request.method, request.url.path, exc.errors(), ) return JSONResponse( status_code=200, content={ "data": [], "message": json.dumps({"error info": exc.errors()}, default=str), "code": 422, }, ) @app.middleware("http") async def allow_openapi_unauthorized(request: Request, call_next): if request.url.path == "/v1/api/ai/openapi.json": response = await call_next(request) return response return await call_next(request) @app.middleware("http") async def log_request_response(request, call_next): request_id = uuid.uuid4().hex request.state.request_id = request_id start = time.perf_counter() client = request.client.host if request.client else "-" logger.info( "request_start request_id=%s method=%s path=%s client=%s", request_id, request.method, request.url.path, client, ) try: response = await call_next(request) except Exception as e: duration_ms = (time.perf_counter() - start) * 1000 logger.exception( "request_unhandled_exception request_id=%s method=%s path=%s duration_ms=%.2f", request_id, request.method, request.url.path, duration_ms, exc_info=True, ) return JSONResponse(status_code=500, content=_error_response(e)) duration_ms = (time.perf_counter() - start) * 1000 logger.info( "request_end request_id=%s method=%s path=%s status_code=%s duration_ms=%.2f", request_id, request.method, request.url.path, response.status_code, duration_ms, ) return response app.include_router(legacy_router) app.include_router(openai_router)