"""FastAPI entrypoint for the Medbillcodes OHIP billing copilot backend.""" from __future__ import annotations import logging from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from .config import settings from .routes import analyze, approve, intake, specialties, provinces, workspace from .weave_trace import init_weave logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) app = FastAPI( title="Medbillcodes Billing Copilot", version="0.3.0", description=( "Provincial fee suggestions grounded in the current physician schedule. " f"Default jurisdiction: {settings.default_province_code}; " f"default specialty: {settings.default_specialty_code}; " f"retrieval: {settings.retrieval_backend}." ), ) # LAN-only frontend; tighten origins for the actual clinic deployment. app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) app.include_router(intake.router) app.include_router(analyze.router) app.include_router(approve.router) app.include_router(specialties.router) app.include_router(provinces.router) app.include_router(workspace.router) def _use_sqlite() -> bool: return settings.retrieval_backend == "sqlite" @app.on_event("startup") async def _startup() -> None: init_weave() if _use_sqlite(): from . import sqlite_store # noqa: PLC0415 from .build_sqlite import build_sqlite_index # noqa: PLC0415 sqlite_store.ensure_schema() if sqlite_store.count_codes() == 0: logger.info("SQLite fee index empty — building from public OHIP sources…") try: summary = build_sqlite_index(force=True) logger.info("SQLite index ready: %s", summary) except Exception as exc: # noqa: BLE001 logger.error( "Failed to build SQLite index at startup (%s). " "Call POST /admin/ingest after fixing data paths.", exc, ) else: logger.info( "SQLite fee index ready (%d codes)", sqlite_store.count_codes() ) return # Full path: OpenSearch + feedback learning (+ optional remote embeddings). try: from .clinic_workspace import ensure_workspace_index # noqa: PLC0415 from .feedback import ensure_feedback_index # noqa: PLC0415 from .opensearch_client import ensure_index, get_client # noqa: PLC0415 from .reconciliation import ensure_remittance_index # noqa: PLC0415 client = get_client() ensure_index(client) ensure_feedback_index(client) ensure_remittance_index(client) ensure_workspace_index(client) logger.info( "OpenSearch ready (index=%s, embeddings=%s)", settings.opensearch_index, "remote" if settings.embedding_url else "local", ) except Exception as exc: # noqa: BLE001 logger.warning( "OpenSearch not ready at startup (%s). Retry via /admin/ingest.", exc ) if settings.refresh_enabled: from .scheduler import start_scheduler # noqa: PLC0415 start_scheduler() @app.on_event("shutdown") async def _shutdown() -> None: if _use_sqlite(): return try: from .scheduler import shutdown_scheduler # noqa: PLC0415 shutdown_scheduler() except Exception: # noqa: BLE001 pass @app.get("/health") def health() -> dict: payload: dict = { "status": "ok", "retrieval_backend": settings.retrieval_backend, "pilot_mode": settings.pilot_mode, "model": settings.llm_model, "vllm_url": settings.vllm_url, "embeddings": "remote" if settings.embedding_url else "local", "embedding_model": settings.embedding_model, "embedding_dim": settings.embedding_dim, "fusion_technique": settings.fusion_technique, "rrf_rank_constant": settings.rrf_rank_constant, "feedback_learning": not _use_sqlite(), "llm_justify_sync": settings.llm_justify, "llm_enrich_justifications": settings.llm_enrich_justifications, "weave_enabled": settings.weave_enabled, "weave_project": settings.weave_project if settings.weave_enabled else None, "weave_llm_judge": settings.weave_llm_judge, "weave_gate_top3": settings.weave_gate_top3, "weave_gate_mrr": settings.weave_gate_mrr, } if _use_sqlite(): from . import sqlite_store # noqa: PLC0415 payload["codes"] = sqlite_store.count_codes() payload["sqlite_path"] = str(sqlite_store.db_path()) else: payload["index"] = settings.opensearch_index return payload