#!/usr/bin/env python3 """PhytoEvidence Medical Service — FastAPI Orchestrator (Ultra-Modular v3).""" from fastapi import FastAPI, Header, Body from fastapi.middleware.cors import CORSMiddleware import uvicorn import torch from config import API_KEY, HOST, PORT from models.loader import load_all, cleanup from security.auth import verify_bearer_token from endpoints import health, rerank, verify, verify_qa, validate_numeric, extract_claims, validate_claims from logger import setup_logger logger = setup_logger("app") APP_VERSION = "4.2.17" app = FastAPI( title="PhytoEvidence Medical Service", version=APP_VERSION, docs_url="/docs", openapi_url="/openapi.json", ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.on_event("startup") async def startup(): logger.info("=== Startup ===") if not API_KEY: raise RuntimeError("MED_SERVICE_KEY must be configured") try: load_all() logger.info("\u2713 Ready") except Exception as e: logger.error(f"\u2717 Startup failed: {e}") raise @app.on_event("shutdown") async def shutdown(): logger.info("=== Shutdown ===") cleanup() torch.cuda.empty_cache() @app.get("/") async def root(): return { "service": "PhytoEvidence Medical", "version": APP_VERSION, "docs": "/docs", } @app.get("/health") async def get_health(): payload = await health.get_health() if hasattr(payload, "model_dump"): payload = payload.model_dump() elif hasattr(payload, "dict"): payload = payload.dict() if isinstance(payload, dict): return { **payload, "version": APP_VERSION, } return payload @app.post("/rerank") async def post_rerank(request: dict = Body(...), authorization: str | None = Header(None)): await verify_bearer_token(authorization) return await rerank.post_rerank(request) @app.post("/verify") async def post_verify(request: dict = Body(...), authorization: str | None = Header(None)): await verify_bearer_token(authorization) return await verify.post_verify(request) @app.post("/verify-qa") async def post_verify_qa(request: dict = Body(...), authorization: str | None = Header(None)): await verify_bearer_token(authorization) return await verify_qa.post_verify_qa(request) @app.post("/validate-numeric") async def post_validate_numeric(request: dict = Body(...), authorization: str | None = Header(None)): await verify_bearer_token(authorization) return await validate_numeric.post_validate_numeric(request) @app.post("/extract-claims") async def post_extract_claims(request: dict = Body(...), authorization: str | None = Header(None)): await verify_bearer_token(authorization) return await extract_claims.post_extract_claims(request) @app.post("/validate-claims") async def post_validate_claims(request: dict = Body(...), authorization: str | None = Header(None)): await verify_bearer_token(authorization) return await validate_claims.post_validate_claims(request) if __name__ == "__main__": uvicorn.run(app, host=HOST, port=PORT, log_level="info")