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:
@@ -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
@@ -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],
|
||||
|
||||
Reference in New Issue
Block a user