feat: add GET /stats endpoint with system statistics

Returns counts for:
- Neo4j: nodes by type (Document, Entity, Collection, Search)
- Qdrant: vectors per collection
- Wiki.js: total page count
- Paperless: documents, tags, correspondents, document types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-30 12:07:02 +01:00
co-authored by Claude Opus 4.5
parent d6b30570a0
commit 68eb1add3d
2 changed files with 88 additions and 10 deletions
-9
View File
@@ -41,12 +41,3 @@ Check for duplicate or highly similar documents using vector similarity and grap
3. Check graph relationships
4. Return candidates with similarity scores
## System Statistics
#### `GET /stats`
Get system statistics (wiki pages, neo4j nodes, qdrant vectors).
**Implementation needed:**
- Query Neo4j for node count
- Query Qdrant for vector count
- Query Wiki.js for page count
+88 -1
View File
@@ -18,7 +18,7 @@ from pathlib import Path
from src.config import Settings, get_settings, __version__
from src.core.dependencies import (
verify_api_key, QdrantDep, WikiJSDep, OllamaDep, Neo4jDep
verify_api_key, QdrantDep, WikiJSDep, OllamaDep, Neo4jDep, PaperlessDep
)
from src.core.multi_tenancy import DEFAULT_USER
@@ -85,6 +85,14 @@ class HealthResponse(BaseModel):
services: Dict[str, Any]
class StatsResponse(BaseModel):
"""System statistics response model."""
neo4j: Dict[str, int]
qdrant: Dict[str, Any]
wiki_pages: int
paperless: Dict[str, Any]
# Routes
@app.get("/", tags=["Root"])
async def root() -> Dict[str, str]:
@@ -141,6 +149,85 @@ async def health(settings: Settings = Depends(get_settings)) -> HealthResponse:
)
@app.get("/stats", response_model=StatsResponse, tags=["System"])
async def stats(
user: str = Query(default=DEFAULT_USER, description="User identifier"),
neo4j: Neo4jDep = None,
qdrant: QdrantDep = None,
wikijs: WikiJSDep = None,
paperless: PaperlessDep = None,
api_key: str = Depends(verify_api_key)
) -> StatsResponse:
"""
Get system statistics.
Returns counts for:
- Neo4j: nodes by type (Document, Entity, Collection, Search)
- Qdrant: vectors per collection
- Wiki.js: total page count
- Paperless: documents, tags, correspondents, document types
"""
# Neo4j node counts by label
neo4j_stats = {}
try:
for label in ["Document", "Entity", "Collection", "Search"]:
result = await neo4j.execute_query(
f"MATCH (n:{label}) RETURN count(n) as count"
)
neo4j_stats[label.lower() + "_nodes"] = result[0]["count"] if result else 0
except Exception as e:
logger.error(f"Failed to get Neo4j stats: {e}")
neo4j_stats = {"error": str(e)}
# Qdrant collection stats
qdrant_stats = {}
try:
collections = await qdrant.list_collections()
qdrant_stats["collections"] = len(collections)
qdrant_stats["total_vectors"] = sum(c.get("vectors_count", 0) for c in collections)
qdrant_stats["by_collection"] = {
c["name"]: c["vectors_count"] for c in collections
}
except Exception as e:
logger.error(f"Failed to get Qdrant stats: {e}")
qdrant_stats = {"error": str(e)}
# Wiki.js page count
wiki_pages = 0
try:
pages = await wikijs.list_all_pages(user)
wiki_pages = len(pages)
except Exception as e:
logger.warning(f"Failed to get Wiki.js stats: {e}")
# Paperless-ngx document stats
paperless_stats = {}
try:
# Get document count (page_size=1 for efficiency, we just need the count)
docs_result = await paperless.list_documents(page_size=1)
paperless_stats["documents"] = docs_result.get("count", 0)
# Get metadata counts
tags = await paperless.list_tags()
paperless_stats["tags"] = len(tags)
correspondents = await paperless.list_correspondents()
paperless_stats["correspondents"] = len(correspondents)
doc_types = await paperless.list_document_types()
paperless_stats["document_types"] = len(doc_types)
except Exception as e:
logger.warning(f"Failed to get Paperless stats: {e}")
paperless_stats = {"error": str(e)}
return StatsResponse(
neo4j=neo4j_stats,
qdrant=qdrant_stats,
wiki_pages=wiki_pages,
paperless=paperless_stats
)
@app.post("/ingest/check-updates", tags=["Ingestion"])
async def check_updates(
documents: Dict[str, Any],