NathanPereira's picture
Upload 7 files
9ccd45c verified
Raw
History Blame Contribute Delete
3.13 kB
"""
Single-port entrypoint for the Multi-Agent Medical Assistant on HF Spaces.
Everything is served from one FastAPI app on port 7860:
- /api/* your agent + RAG + imaging routes
- /health liveness probe
- /* the React single-page app (static build)
Design constraints baked in:
- Hosted LLM API (keys read from Space Secrets via env vars)
- Embedded Qdrant + SQLite (no external DB servers)
- Imaging models loaded lazily on first request (no GPU work at import time)
"""
import os
from pathlib import Path
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
# ---- Secrets / config (set these in Space Settings -> Variables & secrets) ----
# e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, ELEVENLABS_API_KEY
LLM_API_KEY = os.environ.get("LLM_API_KEY") # rename to match your provider
ELEVENLABS_API_KEY = os.environ.get("ELEVENLABS_API_KEY")
STATIC_DIR = Path(__file__).resolve().parent.parent / "static"
app = FastAPI(title="Multi-Agent Medical Assistant")
# Frontend is served from the same origin, so CORS is mostly a no-op here,
# but keep it permissive if you ever call the API from elsewhere.
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/health")
def health():
return {"status": "ok"}
# ---------------------------------------------------------------------------
# API ROUTES
# Import your existing routers here. Keep heavy imports (torch, imaging models)
# INSIDE the route handlers or a lazy loader — never at module top level, so the
# container starts fast and the build never touches the GPU.
# ---------------------------------------------------------------------------
# from backend.agents.router import router as agents_router
# app.include_router(agents_router, prefix="/api")
# ---- Lazy imaging-model loader example (T4 GPU) ----------------------------
_models = {}
def get_imaging_model(name: str):
"""Load a model once, on first use, onto the GPU."""
if name not in _models:
import torch # imported lazily so build stage never needs CUDA
# _models[name] = load_your_model(name).to(
# "cuda" if torch.cuda.is_available() else "cpu"
# )
raise NotImplementedError("Wire up your imaging model loader here.")
return _models[name]
# ---------------------------------------------------------------------------
# STATIC FRONTEND (mounted LAST so it doesn't shadow /api and /health)
# ---------------------------------------------------------------------------
if STATIC_DIR.exists():
app.mount("/assets", StaticFiles(directory=STATIC_DIR / "assets"), name="assets")
@app.get("/{full_path:path}")
def serve_spa(full_path: str):
# Serve real files if they exist, else fall back to index.html (SPA routing)
candidate = STATIC_DIR / full_path
if full_path and candidate.is_file():
return FileResponse(candidate)
return FileResponse(STATIC_DIR / "index.html")