from __future__ import annotations import logging import time import sys from pathlib import Path # Ensure top-level `training`, `chemistry`, etc. packages are importable ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT / 'src')) from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel from .predictor import HybridDDIPredictor logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(name)s %(message)s') logger = logging.getLogger('medcare_ddi.api') predictor = HybridDDIPredictor.from_default_paths() app = FastAPI(title='MEDCARE-DDI Hybrid Predictor', version='2.0.0') app.add_middleware( CORSMiddleware, allow_origins=['*'], allow_credentials=True, allow_methods=['*'], allow_headers=['*'], ) class PredictionRequest(BaseModel): # Accept both frontend keys (`drug_a`, `drug_b`) and legacy keys (`drug_a_id`, `drug_b_id`). drug_a_id: str | None = None drug_b_id: str | None = None drug_a: str | None = None drug_b: str | None = None @app.get('/health') def health() -> dict[str, object]: return predictor.health() @app.post('/predict') def predict(request: PredictionRequest) -> dict[str, object]: started_at = time.perf_counter() # Prefer explicit `drug_a`/`drug_b` from frontend; fall back to legacy `drug_a_id` fields. drug_a = (request.drug_a or request.drug_a_id or '') drug_b = (request.drug_b or request.drug_b_id or '') result = predictor.predict(drug_a, drug_b) latency_ms = round((time.perf_counter() - started_at) * 1000, 2) logger.info( 'prediction_completed source=%s severity=%s confidence=%.3f latency_ms=%.2f drug_a=%s drug_b=%s', result['source'], result['severity'], result['confidence'], latency_ms, result['drug_a_name'], result['drug_b_name'], ) return { **result, 'latency_ms': latency_ms, }