|
"""This module defines the /summary route for the Flask application.""" |
|
|
|
import importlib |
|
from venv import logger |
|
import re |
|
from fastapi import APIRouter, HTTPException, Path |
|
from fastapi.responses import JSONResponse |
|
from controllers.summary import get_summary_data |
|
from models.database import knowledge_base |
|
|
|
router = APIRouter(prefix="/summary", tags=["summary"]) |
|
|
|
@router.get("/{email}") |
|
async def get_user_document_stats( |
|
email: str = Path(..., description="User's email address") |
|
) -> JSONResponse: |
|
""" |
|
Get document statistics for a specific user. |
|
|
|
This endpoint counts the number of unique emails and files uploaded by the user. |
|
It groups documents by metadata.id to ensure unique document counting (not chunks). |
|
|
|
Args: |
|
email (str): The user's email address |
|
|
|
Returns: |
|
JSONResponse: A JSON response containing document counts: |
|
{ |
|
"email": "[email protected]", |
|
"emails": 5, |
|
"files": 12, |
|
"total_documents": 17 |
|
} |
|
|
|
Raises: |
|
HTTPException: 400 for invalid email, 500 for database errors |
|
""" |
|
try: |
|
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' |
|
if not email or not re.match(email_pattern, email): |
|
raise HTTPException( |
|
status_code=400, |
|
detail="Invalid email format. Must be a valid email address." |
|
) |
|
|
|
|
|
result = knowledge_base.get_doc_count(email) |
|
|
|
|
|
result["email"] = email |
|
|
|
return JSONResponse(content=result, status_code=200) |
|
|
|
except ValueError as e: |
|
logger.error("Validation error for user %s: %s", email, str(e)) |
|
raise HTTPException(status_code=400, detail=str(e)) |
|
|
|
except Exception as e: |
|
logger.error("Database error for user %s: %s", email, str(e)) |
|
raise HTTPException( |
|
status_code=500, |
|
detail="Internal server error while retrieving document statistics." |
|
) |
|
|
|
@router.get('') |
|
async def get_summary() -> JSONResponse: |
|
""" |
|
Generate a summary dashboard with content flow and entity analysis data. |
|
|
|
This endpoint provides a complete summary overview, including: |
|
- Content Flow Tracker: Article counts by source and category |
|
- Entity Analysis: Top entities by type with mentions |
|
|
|
All data is returned together, divided into three time periods: today, week, and month. |
|
|
|
Returns: |
|
JSONResponse: A JSON response containing the complete summary dashboard data: |
|
{ |
|
"content": {"today": {...}, "week": {...}, "month": {...}}, |
|
"entity": {"today": {...}, "week": {...}, "month": {...}} |
|
} |
|
""" |
|
try: |
|
summary_data = get_summary_data() |
|
return JSONResponse(content=summary_data) |
|
except Exception as e: |
|
return JSONResponse(content={"error": str(e)}, status_code=500) |
|
|
|
@router.get("/{module}/{chart_id}") |
|
def get_summary_chart(module: str, chart_id: str) -> JSONResponse: |
|
""" |
|
Handles GET requests to the summary route with a specific module and chart ID. |
|
|
|
Args: |
|
module (str): The module identifier (content or entity). |
|
chart_id (str): The chart identifier (today, weekly, monthly). |
|
|
|
Returns: |
|
tuple: The result of the chart's process function and HTTP status code 200. |
|
|
|
Raises: |
|
ImportError: If the specified chart module cannot be imported. |
|
AttributeError: If the imported module does not have a 'process' function. |
|
|
|
Endpoint: |
|
GET /<module>/<chart_id> |
|
""" |
|
try: |
|
result = importlib.import_module(f"controllers.summary.{module}.{chart_id}").process() |
|
return JSONResponse(content=result) |
|
except ImportError as e: |
|
return JSONResponse(content={"error": str(e)}, status_code=404) |
|
except AttributeError as e: |
|
return JSONResponse(content={"error": str(e)}, status_code=500) |
|
|
|
@router.get("/{module}") |
|
async def get_summary_module(module: str) -> JSONResponse: |
|
""" |
|
Handles GET requests to the summary route for a specific module. |
|
Triggers the process for each chart under this module concurrently. |
|
|
|
Args: |
|
module (str): The module identifier (content or entity). |
|
|
|
Returns: |
|
dict: {"module": module, "charts": [chart1, chart2, ...]} |
|
""" |
|
try: |
|
result = importlib.import_module("controllers.summary").process(module) |
|
return JSONResponse(content=result) |
|
except ImportError as e: |
|
return JSONResponse(content={"error": str(e)}, status_code=404) |
|
except Exception as e: |
|
return JSONResponse(content={"error": str(e)}, status_code=500) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|