"""Keyword routes for API endpoints.""" import logging from fastapi import APIRouter from fastapi.responses import JSONResponse from collectors.finfast.keyword import collect as run_historical_backfill # pylint: disable=import-error from models.database import keywords_collection, summary_collection # pylint: disable=import-error # Configure logger logger = logging.getLogger(__name__) # Create FastAPI Router router = APIRouter(prefix="/keyword", tags=["keyword"]) @router.post('/historical-backfill') async def historical_backfill(): """ Manual trigger endpoint for 60-day historical keyword backfill. Returns: JSON response with status and details """ try: logger.info("Received request for historical keyword backfill") # Run the historical backfill run_historical_backfill() logger.info("Historical keyword backfill completed successfully") return JSONResponse(content={ "status": "success", "message": "Historical keyword backfill completed successfully", "details": { "operation": "60-day historical keyword backfill", "method": "standard approach (day-by-day processing)" } }, status_code=200) except Exception as e: # pylint: disable=broad-exception-caught logger.error("Error during historical keyword backfill: %s", e) return JSONResponse(content={ "status": "error", "message": "Failed to complete historical keyword backfill", "error": str(e) }, status_code=500) @router.get('/status') async def keyword_status(): """ Get status of keyword processing. Returns: JSON response with keyword processing status """ try: # Get basic statistics total_documents = keywords_collection.count_documents({}) # Get date range oldest_doc = keywords_collection.find_one(sort=[("_id", 1)]) newest_doc = keywords_collection.find_one(sort=[("_id", -1)]) status_info = { "status": "operational", "total_keyword_documents": total_documents, "date_range": { "oldest": oldest_doc["_id"] if oldest_doc else None, "newest": newest_doc["_id"] if newest_doc else None } } return JSONResponse(content=status_info, status_code=200) except Exception as e: # pylint: disable=broad-exception-caught logger.error("Error getting keyword status: %s", e) return JSONResponse(content={ "status": "error", "message": "Failed to get keyword status", "error": str(e) }, status_code=500) @router.get('/summary') async def get_all_summaries(): """ Get all summaries (today, week, month). Returns: JSON response with all summary data """ try: logger.info("Received request for all summaries") summaries = {} periods = ["today", "week", "month"] for period in periods: summary_doc = summary_collection.find_one({"_id": period}) if summary_doc: summaries[period] = { "keywords": summary_doc.get("keywords", []), "categories": summary_doc.get("categories", []) } else: summaries[period] = { "keywords": [], "categories": [], "message": f"No summary available for {period}" } return JSONResponse(content={ "status": "success", "summaries": summaries }, status_code=200) except Exception as e: # pylint: disable=broad-exception-caught logger.error("Error getting all summaries: %s", e) return JSONResponse(content={ "status": "error", "message": "Failed to get summaries", "error": str(e) }, status_code=500) @router.get('/summary/{period}') async def get_summary_by_period(period: str): """ Get specific summary by period (today/week/month). Args: period: Analysis period (today, week, or month) Returns: JSON response with specific summary data """ try: # Validate period parameter valid_periods = ["today", "week", "month"] if period not in valid_periods: return JSONResponse(content={ "status": "error", "message": "Invalid period. Must be one of: today, week, month", "valid_periods": valid_periods }, status_code=400) logger.info("Received request for %s summary", period) summary_doc = summary_collection.find_one({"_id": period}) if summary_doc: return JSONResponse(content={ "status": "success", "period": period, "summary": { "keywords": summary_doc.get("keywords", []), "categories": summary_doc.get("categories", []) } }, status_code=200) return JSONResponse(content={ "status": "not_found", "message": f"No summary available for {period}", "period": period }, status_code=404) except Exception as e: # pylint: disable=broad-exception-caught logger.error("Error getting %s summary: %s", period, e) return JSONResponse(content={ "status": "error", "message": f"Failed to get {period} summary", "error": str(e) }, status_code=500)