Source code for veupath_chatbot.transport.http.routers.health
"""Health check endpoints."""
from datetime import UTC, datetime
from fastapi import APIRouter
from fastapi.responses import JSONResponse
from veupath_chatbot import __version__
from veupath_chatbot.persistence.session import async_session_factory
from veupath_chatbot.platform.config import get_settings
from veupath_chatbot.platform.health import check_database, check_qdrant
from veupath_chatbot.platform.logging import get_logger
from veupath_chatbot.transport.http.schemas import HealthResponse, SystemConfigResponse
from veupath_chatbot.transport.http.schemas.health import ProviderStatus
router = APIRouter(tags=["health"])
logger = get_logger(__name__)
[docs]
@router.get("/health", response_model=HealthResponse)
async def health_check() -> HealthResponse:
"""Liveness check - is the service running?"""
return HealthResponse(
status="healthy",
version=__version__,
timestamp=datetime.now(UTC),
)
[docs]
@router.get("/health/config", response_model=SystemConfigResponse)
async def system_config() -> SystemConfigResponse:
"""Report whether the system has LLM provider keys configured.
This is unauthenticated so the frontend can show a setup-required
screen before asking users to log in.
"""
settings = get_settings()
is_mock = settings.chat_provider.strip().lower() == "mock"
providers = ProviderStatus(
openai=bool(settings.openai_api_key),
anthropic=bool(settings.anthropic_api_key),
google=bool(settings.gemini_api_key),
ollama=bool(settings.ollama_base_url),
)
return SystemConfigResponse(
chat_provider=settings.chat_provider,
llm_configured=is_mock
or providers.openai
or providers.anthropic
or providers.google
or providers.ollama,
providers=providers,
)
[docs]
@router.get("/health/ready", response_model=HealthResponse)
async def readiness_check() -> HealthResponse | JSONResponse:
"""Readiness check - is the service ready to accept requests?
Checks database connectivity and Qdrant availability (if RAG is enabled).
Returns 503 if any dependency is unreachable.
"""
settings = get_settings()
failures: list[str] = []
try:
async with async_session_factory() as session:
await check_database(session)
except Exception as e:
logger.error("Readiness check: database unreachable", error=str(e))
failures.append("database")
if settings.rag_enabled:
try:
await check_qdrant()
except Exception as e:
logger.error("Readiness check: Qdrant unreachable", error=str(e))
failures.append("qdrant")
if failures:
return JSONResponse(
status_code=503,
content={
"status": "unhealthy",
"version": __version__,
"timestamp": datetime.now(UTC).isoformat(),
"failed_checks": failures,
},
)
return HealthResponse(
status="healthy",
version=__version__,
timestamp=datetime.now(UTC),
)