| """Biomedical RAG service main program entry point.""" |
|
|
| import importlib |
| import os |
| import pkgutil |
| import time |
|
|
| import uvicorn |
| from dotenv import load_dotenv |
|
|
| |
| load_dotenv() |
|
|
| from asgi_correlation_id import CorrelationIdMiddleware, correlation_id |
| from fastapi import FastAPI, Request |
| from fastapi_mcp import FastApiMCP |
| from fastapi.middleware.cors import CORSMiddleware |
| from slowapi import Limiter, _rate_limit_exceeded_handler |
| from slowapi.util import get_remote_address |
| from slowapi.errors import RateLimitExceeded |
|
|
| from routers import sensor, mcp_sensor |
| from utils.bio_logger import bio_logger as logger |
|
|
| |
| logger.info(f"SERPER_API_KEY loaded: {'Yes' if os.getenv('SERPER_API_KEY') else 'No'}") |
|
|
|
|
| app = FastAPI( |
| docs_url=None, |
| redoc_url=None, |
| openapi_url=None, |
| debug=False, |
| ) |
|
|
| |
| limiter = Limiter(key_func=get_remote_address) |
| app.state.limiter = limiter |
| app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) |
|
|
| |
| app.add_middleware(CorrelationIdMiddleware) |
| |
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| |
| app.include_router(sensor.router) |
| app.include_router(mcp_sensor.router) |
|
|
| @app.get("/health") |
| async def health_check(): |
| """健康检查端点""" |
| return {"status": "healthy", "service": "bio-rag-mcp"} |
|
|
|
|
| @app.middleware("http") |
| async def add_process_time_header(request: Request, call_next): |
| """HTTP中间件,记录请求处理时间和状态。完全兼容SSE流式响应。""" |
| start_time = time.time() |
| |
| |
| is_sse_endpoint = request.url.path.startswith("/sse") |
| |
| logger.info(f"Request started | URL: {request.url}") |
|
|
| try: |
| response = await call_next(request) |
| process_time = time.time() - start_time |
| |
| |
| if is_sse_endpoint: |
| logger.info( |
| f"SSE connection established | " |
| f"Time: {process_time:.2f}s" |
| ) |
| else: |
| |
| try: |
| status_code = getattr(response, 'status_code', 'UNKNOWN') |
| logger.info( |
| f"Request completed | " |
| f"Status: {status_code} | " |
| f"Time: {process_time:.2f}s" |
| ) |
| except Exception as e: |
| logger.warning(f"Could not get status code: {e}") |
| logger.info( |
| f"Request completed | " |
| f"Status: UNKNOWN | " |
| f"Time: {process_time:.2f}s" |
| ) |
| |
| return response |
| |
| except Exception as e: |
| process_time = time.time() - start_time |
| logger.error( |
| f"Request failed | " |
| f"Error: {str(e)} | " |
| f"Time: {process_time:.2f}s" |
| ) |
| raise |
|
|
|
|
| def dynamic_import_subclasses(parent_dir: str) -> None: |
| """动态导入指定目录下的所有Python模块。 |
| |
| Args: |
| parent_dir: 要导入的目录路径 |
| """ |
| for _, module_name, _ in pkgutil.iter_modules([parent_dir]): |
| module = importlib.import_module(f"{parent_dir}.{module_name}") |
| logger.info(f"Imported: {module.__name__}") |
|
|
|
|
| |
| mcp = FastApiMCP(app, name="bio qa mcp", include_operations=["bio_qa_stream_chat"]) |
|
|
| |
| mcp.mount_sse() |
|
|
| if __name__ == "__main__": |
| logger.info("Starting Bio RAG Server...") |
| dynamic_import_subclasses("search_service") |
| uvicorn.run(app, host="0.0.0.0", port=9487) |
|
|