""" Analytics Dashboard API Routes Provides endpoints for message analytics, cross-platform correlation, and predictive insights. """ from datetime import datetime, timezone from typing import Any, Dict, List, Optional from fastapi import Query from core.base_routes import BaseAPIRouter from core.cross_platform_correlation import ( CrossPlatformCorrelationEngine, get_cross_platform_correlation_engine, ) from core.message_analytics_engine import MessageAnalyticsEngine, get_message_analytics_engine from core.predictive_insights import ( PredictiveInsightsEngine, UrgencyLevel, get_predictive_insights_engine, ) router = BaseAPIRouter(prefix="/api/analytics", tags=["analytics"]) @router.get("/summary") async def get_analytics_summary( time_window: str = Query("24h", description="Time window: 24h, 7d, 30d, all"), platform: Optional[str] = Query(None, description="Filter by platform") ) -> Dict[str, Any]: """ Get comprehensive analytics summary. Args: time_window: Time period for analytics platform: Optional platform filter Returns: Analytics summary with message stats, response times, sentiment, etc. """ try: analytics_engine = get_message_analytics_engine() # Get all messages (in production, would query from database) # For now, return summary structure summary = { "time_window": time_window, "message_stats": { "total_messages": 0, "total_words": 0, "with_attachments": 0, "with_mentions": 0, "with_urls": 0, "sentiment_distribution": { "positive": 0, "negative": 0, "neutral": 0 } }, "response_times": { "avg_response_seconds": 0, "median_response_seconds": 0, "p95_response_seconds": 0, "total_responses_analyzed": 0 }, "activity_peaks": { "peak_days": [], "messages_per_day": {} }, "cross_platform": { "platforms": {}, "most_active_platform": None, "total_messages": 0 } } if platform: summary["platform_filter"] = platform return summary except Exception as e: raise router.internal_error(message=f"Error generating analytics: {str(e)}") @router.get("/sentiment") async def get_sentiment_analysis( platform: Optional[str] = Query(None, description="Filter by platform"), time_window: str = Query("24h", description="Time window for analysis") ) -> Dict[str, Any]: """ Get sentiment analysis breakdown. Args: platform: Optional platform filter time_window: Time period for analysis Returns: Sentiment distribution and trends """ try: analytics_engine = get_message_analytics_engine() return { "platform": platform, "time_window": time_window, "sentiment_distribution": { "positive": 0, "negative": 0, "neutral": 0 }, "sentiment_trend": [], # Time series of sentiment "most_positive_topics": [], "most_negative_topics": [] } except Exception as e: raise router.internal_error(message=f"Error analyzing sentiment: {str(e)}") @router.get("/response-times") async def get_response_time_metrics( platform: Optional[str] = Query(None, description="Filter by platform"), time_window: str = Query("7d", description="Time window for analysis") ) -> Dict[str, Any]: """ Get response time metrics. Args: platform: Optional platform filter time_window: Time period for analysis Returns: Response time statistics (avg, median, P95, P99) """ try: analytics_engine = get_message_analytics_engine() return { "platform": platform, "time_window": time_window, "avg_response_seconds": 0, "median_response_seconds": 0, "p95_response_seconds": 0, "p99_response_seconds": 0, "response_time_distribution": [], "slowest_threads": [], "fastest_threads": [] } except Exception as e: raise router.internal_error(message=f"Error calculating response times: {str(e)}") @router.get("/activity") async def get_activity_metrics( period: str = Query("daily", description="Period: hourly, daily, weekly"), platform: Optional[str] = Query(None, description="Filter by platform") ) -> Dict[str, Any]: """ Get activity metrics and peak times. Args: period: Time period granularity platform: Optional platform filter Returns: Activity metrics with peaks and patterns """ try: analytics_engine = get_message_analytics_engine() return { "period": period, "platform": platform, "messages_per_hour": {}, "messages_per_day": {}, "messages_per_channel": {}, "peak_hours": [], "peak_days": [], "activity_heatmap": [] # For visualization } except Exception as e: raise router.internal_error(message=f"Error analyzing activity: {str(e)}") @router.get("/cross-platform") async def get_cross_platform_analytics( time_window: str = Query("7d", description="Time window for analysis") ) -> Dict[str, Any]: """ Get cross-platform analytics and comparisons. Args: time_window: Time period for analysis Returns: Platform comparison and insights """ try: analytics_engine = get_message_analytics_engine() return { "time_window": time_window, "platforms": { "slack": { "message_count": 0, "sentiment": {"positive": 0, "negative": 0, "neutral": 0}, "avg_response_time": 0 }, "teams": { "message_count": 0, "sentiment": {"positive": 0, "negative": 0, "neutral": 0}, "avg_response_time": 0 }, "gmail": { "message_count": 0, "sentiment": {"positive": 0, "negative": 0, "neutral": 0}, "avg_response_time": 0 } }, "most_active_platform": "slack", "platform_comparison": [] } except Exception as e: raise router.internal_error(message=f"Error analyzing cross-platform: {str(e)}") @router.post("/correlations") async def analyze_cross_platform_correlations( messages: List[Dict[str, Any]] ) -> Dict[str, Any]: """ Analyze and correlate conversations across platforms. Args: messages: List of unified messages to analyze Returns: Linked conversations and correlations """ try: correlation_engine = get_cross_platform_correlation_engine() conversations = correlation_engine.correlate_conversations(messages) return { "linked_conversations": [ { "conversation_id": c.conversation_id, "platforms": list(c.platforms), "participants": list(c.participants), "message_count": c.message_count, "correlation_strength": c.correlation_strength.value, "unified_message_count": len(c.unified_messages) } for c in conversations ], "total_correlations": len(conversations), "cross_platform_links": len(correlation_engine.cross_platform_links) } except Exception as e: raise router.internal_error(message=f"Error analyzing correlations: {str(e)}") @router.get("/correlations/{conversation_id}/timeline") async def get_unified_timeline( conversation_id: str ) -> Dict[str, Any]: """ Get unified timeline for a cross-platform conversation. Args: conversation_id: ID of the linked conversation Returns: Unified message timeline from all platforms """ try: correlation_engine = get_cross_platform_correlation_engine() timeline = correlation_engine.get_unified_timeline(conversation_id) if timeline is None: raise router.not_found_error("Conversation", conversation_id) return router.success_response( data={ "conversation_id": conversation_id, "message_count": len(timeline), "messages": [ { "id": m.get("id"), "platform": m.get("platform"), "content": m.get("content"), "sender": m.get("sender_name") or m.get("sender"), "timestamp": m.get("timestamp"), "source": m.get("_correlation_source") } for m in timeline ] }, message="Timeline retrieved successfully" ) except Exception as e: raise router.internal_error(message=f"Error getting timeline: {str(e)}") @router.get("/predictions/response-time") async def predict_response_time( recipient: str = Query(..., description="User ID or name"), platform: str = Query(..., description="Platform to send on"), urgency: str = Query("medium", description="Urgency: low, medium, high, urgent") ) -> Dict[str, Any]: """ Predict response time for a user. Args: recipient: User to predict for platform: Platform to send on urgency: Message urgency Returns: Predicted response time with confidence """ try: insights_engine = get_predictive_insights_engine() urgency_level = UrgencyLevel(urgency) prediction = insights_engine.predict_response_time( recipient=recipient, platform=platform, urgency=urgency_level ) return { "recipient": prediction.user_id, "platform": platform, "urgency": urgency, "predicted_response_seconds": prediction.predicted_seconds, "predicted_response_minutes": prediction.predicted_seconds / 60, "confidence": prediction.confidence.value, "factors": prediction.factors } except ValueError: raise router.validation_error("urgency", f"Invalid urgency level: {urgency}") except Exception as e: raise router.internal_error(message=f"Error predicting response time: {str(e)}") @router.get("/recommendations/channel") async def recommend_channel( recipient: str = Query(..., description="User ID or name"), message_type: str = Query("general", description="Type of message"), urgency: str = Query("medium", description="Urgency: low, medium, high, urgent") ) -> Dict[str, Any]: """ Get optimal channel recommendation for a user. Args: recipient: User to recommend for message_type: Type of message urgency: Message urgency Returns: Channel recommendation with alternatives """ try: insights_engine = get_predictive_insights_engine() urgency_level = UrgencyLevel(urgency) recommendation = insights_engine.recommend_channel( recipient=recipient, message_type=message_type, urgency=urgency_level ) return { "recipient": recommendation.user_id, "recommended_platform": recommendation.recommended_platform, "reason": recommendation.reason, "confidence": recommendation.confidence.value, "expected_response_time_minutes": recommendation.expected_response_time / 60 if recommendation.expected_response_time else None, "alternatives": recommendation.alternatives } except ValueError: raise router.validation_error("urgency", f"Invalid urgency level: {urgency}") except Exception as e: raise router.internal_error(message=f"Error generating recommendation: {str(e)}") @router.get("/bottlenecks") async def detect_bottlenecks( threshold_hours: float = Query(24.0, description="Hours without response to flag") ) -> Dict[str, Any]: """ Detect communication bottlenecks. Args: threshold_hours: Hours to wait before flagging Returns: List of bottleneck alerts """ try: insights_engine = get_predictive_insights_engine() bottlenecks = insights_engine.detect_bottlenecks(threshold_hours=threshold_hours) return { "total_bottlenecks": len(bottlenecks), "threshold_hours": threshold_hours, "bottlenecks": [ { "severity": b.severity.value, "thread_id": b.thread_id, "platform": b.platform, "description": b.description, "affected_users": b.affected_users, "wait_time_hours": b.wait_time_seconds / 3600, "suggested_action": b.suggested_action } for b in bottlenecks ] } except Exception as e: raise router.internal_error(message=f"Error detecting bottlenecks: {str(e)}") @router.get("/patterns/{user_id}") async def get_user_patterns( user_id: str ) -> Dict[str, Any]: """ Get communication patterns for a specific user. Args: user_id: User to analyze Returns: User's communication patterns and preferences """ try: insights_engine = get_predictive_insights_engine() pattern = insights_engine.get_user_pattern(user_id) if pattern is None: raise router.not_found_error("User patterns", user_id) return router.success_response( data={ "user_id": pattern.user_id, "most_active_platform": pattern.most_active_platform, "most_active_hours": pattern.most_active_hours, "avg_response_time_minutes": pattern.avg_response_time / 60 if pattern.avg_response_time else None, "response_probability_by_hour": pattern.response_probability_by_hour, "preferred_message_types": pattern.preferred_message_types }, message="User patterns retrieved successfully" ) except Exception as e: raise router.internal_error(message=f"Error getting patterns: {str(e)}") @router.get("/overview") async def get_analytics_overview() -> Dict[str, Any]: """ Get high-level analytics overview for dashboard. Returns: Key metrics and insights for the dashboard """ try: message_engine = get_message_analytics_engine() insights_engine = get_predictive_insights_engine() correlation_engine = get_cross_platform_correlation_engine() insights_summary = insights_engine.get_insights_summary() return { "timestamp": datetime.now(timezone.utc).isoformat(), "message_analytics": { "total_messages": 0, # Would come from database "active_threads": 0, "platforms_active": ["slack", "teams", "gmail"] }, "predictive_insights": { "users_analyzed": insights_summary.get("users_analyzed", 0), "bottlenecks_detected": insights_summary.get("bottlenecks_detected", 0), "avg_response_time_minutes": insights_summary.get("avg_response_time_all_users", 0) / 60 }, "cross_platform": { "linked_conversations": len(correlation_engine.linked_conversations), "cross_platform_links": len(correlation_engine.cross_platform_links) }, "health_status": "healthy" # Could derive from actual metrics } except Exception as e: raise router.internal_error(message=f"Error generating overview: {str(e)}")