"""Define API routes for status.""" import time from typing import Any from fastapi import APIRouter from app.config.settings import settings from app.shared.bootstrap import ( get_bm25_retriever, get_binary_store, get_conversation_store, get_document_query_service, get_vector_index, ) router = APIRouter(prefix="/status", tags=["系统状态"]) # --------------------------------------------------------------------------- # Simple TTL cache for /stats (avoids O(N) doc scan on every request) # --------------------------------------------------------------------------- _stats_cache: dict[str, Any] = {} _stats_cache_time: float = 0.0 _STATS_TTL_SECONDS: float = 10.0 @router.get("/stats") async def get_stats(): """Return document statistics (cached for 10 s).""" global _stats_cache, _stats_cache_time now = time.time() if _stats_cache and (now - _stats_cache_time) < _STATS_TTL_SECONDS: return _stats_cache documents = get_document_query_service().list_documents() indexed = sum(1 for d in documents if d.status.value == "indexed") failed = sum(1 for d in documents if d.status.value == "failed") _stats_cache = { "documents_total": len(documents), "documents_indexed": indexed, "documents_failed": failed, "chunks_total": sum(d.chunk_count for d in documents), } _stats_cache_time = now return _stats_cache @router.get("/config") async def get_config(): """Return system configuration.""" return { "embedding_model": settings.embedding_model, "embedding_dim": settings.embedding_dim, "embedding_base_url": settings.embedding_base_url, "milvus_collection": settings.milvus_collection, "parser_backend": settings.parser_backend, "chunk_backend": settings.chunk_backend, "artifact_prefix": settings.document_parse_artifact_prefix, "parser_failure_mode": settings.parser_failure_mode, "llm_provider": settings.llm_provider, "llm_model": settings.llm_model, "document_metadata_path": settings.document_metadata_path, } @router.get("/milvus/health") async def milvus_health(): """Return Milvus health (kept for backwards compat).""" return get_vector_index().health() @router.get("/health") async def get_health(): """Return aggregate health of all backend services.""" # --- Milvus --- try: milvus_info = get_vector_index().health() milvus_status = "ok" if milvus_info.get("connected") else "error" except Exception as exc: # noqa: BLE001 milvus_info = {} milvus_status = "error" milvus_info["error"] = str(exc) # --- MinIO --- try: minio_connected = get_binary_store().client.connected minio_status = "ok" if minio_connected else "error" except Exception: # noqa: BLE001 minio_status = "error" minio_connected = False # --- BM25 --- bm25 = get_bm25_retriever() # --- Sessions --- try: session_count = len(get_conversation_store().list_sessions()) except Exception: # noqa: BLE001 session_count = 0 return { "milvus": {"status": milvus_status, **milvus_info}, "minio": {"status": minio_status, "connected": minio_connected}, "bm25": {"available": bm25 is not None}, "reranker": { "enabled": settings.reranker_enabled, "model": settings.reranker_model if settings.reranker_enabled else None, }, "sessions": { "active": session_count, "max": settings.session_max_sessions, }, }