namespace App\Services\AI; use App\Models\AiAgent; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Storage; class AiPerformanceMonitoringService { /** * Get performance metrics for an AI agent * * @param int $agentId * @param string $timeframe day|week|month|all * @return array */ public function getAgentPerformanceMetrics(int $agentId, string $timeframe = 'day'): array { $agent = AiAgent::findOrFail($agentId); Log::info("Retrieving performance metrics for agent ID: {$agentId}, timeframe: {$timeframe}"); // In a real implementation, this would fetch actual metrics from a monitoring system // Simulating performance metrics $cacheKey = "agent_{$agentId}_metrics_{$timeframe}"; return Cache::remember($cacheKey, 300, function () use ($agent, $timeframe) { return $this->generateSimulatedMetrics($agent, $timeframe); }); } /** * Get real-time usage statistics for an AI agent * * @param int $agentId * @return array */ public function getRealTimeUsageStats(int $agentId): array { $agent = AiAgent::findOrFail($agentId); // In a real implementation, this would fetch real-time stats // Simulating real-time usage statistics return [ 'active_sessions' => rand(0, 50), 'requests_per_minute' => rand(0, 100), 'average_response_time' => rand(100, 2000), // milliseconds 'error_rate' => rand(0, 5) / 100, // percentage 'cpu_usage' => rand(5, 80), // percentage 'memory_usage' => rand(50, 500), // MB 'timestamp' => now()->toIso8601String(), ]; } /** * Set up monitoring alerts for an AI agent * * @param int $agentId * @param array $alertSettings * @return bool */ public function setupMonitoringAlerts(int $agentId, array $alertSettings): bool { $agent = AiAgent::findOrFail($agentId); Log::info("Setting up monitoring alerts for agent ID: {$agentId}", [ 'alert_settings' => $alertSettings ]); // In a real implementation, this would configure alerts in a monitoring system // Simulating alert setup return true; } /** * Get usage history for an AI agent * * @param int $agentId * @param string $timeframe day|week|month|all * @return array */ public function getUsageHistory(int $agentId, string $timeframe = 'week'): array { $agent = AiAgent::findOrFail($agentId); // In a real implementation, this would fetch historical usage data // Simulating usage history $history = []; $days = $this->getTimeframeDays($timeframe); for ($i = $days - 1; $i >= 0; $i--) { $date = Carbon::now()->subDays($i)->format('Y-m-d'); $history[] = [ 'date' => $date, 'requests' => rand(100, 10000), 'tokens_used' => rand(10000, 1000000), 'unique_users' => rand(10, 1000), 'average_response_time' => rand(100, 2000), // milliseconds 'error_rate' => rand(0, 5) / 100, // percentage ]; } return $history; } /** * Get conversation quality metrics for an AI agent * * @param int $agentId * @param string $timeframe day|week|month|all * @return array */ public function getConversationQualityMetrics(int $agentId, string $timeframe = 'week'): array { $agent = AiAgent::findOrFail($agentId); // In a real implementation, this would analyze conversation quality // Simulating conversation quality metrics return [ 'average_conversation_length' => rand(3, 15), // turns 'average_user_satisfaction' => rand(70, 98) / 100, // percentage 'task_completion_rate' => rand(75, 95) / 100, // percentage 'common_failure_points' => [ 'authentication' => rand(1, 10) / 100, 'complex_queries' => rand(5, 20) / 100, 'integration_errors' => rand(1, 8) / 100, ], 'top_user_intents' => [ 'information_request' => rand(30, 50) / 100, 'task_execution' => rand(20, 40) / 100, 'troubleshooting' => rand(10, 30) / 100, 'feedback' => rand(5, 15) / 100, ], ]; } /** * Generate simulated metrics based on timeframe * * @param AiAgent $agent * @param string $timeframe * @return array */ private function generateSimulatedMetrics(AiAgent $agent, string $timeframe): array { $days = $this->getTimeframeDays($timeframe); $requestMultiplier = $days; return [ 'total_requests' => rand(100, 1000) * $requestMultiplier, 'total_tokens_used' => rand(10000, 100000) * $requestMultiplier, 'unique_users' => min(rand(10, 100) * sqrt($requestMultiplier), 10000), 'average_response_time' => rand(100, 2000), // milliseconds 'error_rate' => rand(0, 5) / 100, // percentage 'uptime_percentage' => rand(95, 100) - (rand(0, 10) / 10), // percentage 'timeframe' => $timeframe, 'model_type' => $agent->model_type, 'cost_estimate' => $this->calculateCostEstimate($agent->model_type, rand(10000, 100000) * $requestMultiplier), ]; } /** * Calculate a simulated cost estimate based on tokens used * * @param string $modelType * @param int $tokensUsed * @return float */ private function calculateCostEstimate(string $modelType, int $tokensUsed): float { $ratePerThousandTokens = match($modelType) { 'gpt-4' => 0.06, 'gpt-3.5-turbo' => 0.002, 'claude-2' => 0.03, default => 0.01, }; return round(($tokensUsed / 1000) * $ratePerThousandTokens, 2); } /** * Convert timeframe to number of days * * @param string $timeframe * @return int */ private function getTimeframeDays(string $timeframe): int { return match($timeframe) { 'day' => 1, 'week' => 7, 'month' => 30, 'all' => 90, default => 7, }; } /** * Get resource utilization metrics for an AI agent * * @param int $agentId * @param string $timeframe day|week|month|all * @return array */ public function getResourceUtilizationMetrics(int $agentId, string $timeframe = 'day'): array { $agent = AiAgent::findOrFail($agentId); Log::info("Retrieving resource utilization metrics for agent ID: {$agentId}, timeframe: {$timeframe}"); $cacheKey = "agent_{$agentId}_resource_metrics_{$timeframe}"; return Cache::remember($cacheKey, 300, function () use ($agent, $timeframe) { return $this->generateResourceUtilizationMetrics($agent, $timeframe); }); } /** * Generate simulated resource utilization metrics * * @param AiAgent $agent * @param string $timeframe * @return array */ private function generateResourceUtilizationMetrics(AiAgent $agent, string $timeframe): array { $days = $this->getTimeframeDays($timeframe); $dataPoints = []; for ($i = $days - 1; $i >= 0; $i--) { $date = Carbon::now()->subDays($i)->format('Y-m-d'); $dataPoints[] = [ 'date' => $date, 'cpu_utilization' => [ 'average' => rand(10, 80), 'peak' => rand(50, 95), ], 'memory_utilization' => [ 'average' => rand(20, 70), 'peak' => rand(60, 90), ], 'gpu_utilization' => $this->shouldUseGPU($agent->model_type) ? [ 'average' => rand(30, 85), 'peak' => rand(70, 98), ] : null, 'network_bandwidth' => [ 'ingress_mb' => rand(50, 500), 'egress_mb' => rand(100, 1000), ], 'disk_io' => [ 'read_ops' => rand(1000, 10000), 'write_ops' => rand(500, 5000), ], ]; } return [ 'agent_id' => $agent->id, 'model_type' => $agent->model_type, 'timeframe' => $timeframe, 'data_points' => $dataPoints, 'summary' => [ 'average_cpu_utilization' => rand(20, 70), 'average_memory_utilization' => rand(30, 60), 'average_gpu_utilization' => $this->shouldUseGPU($agent->model_type) ? rand(40, 80) : null, 'total_network_bandwidth_gb' => rand(5, 50) / 10, 'resource_efficiency_score' => rand(60, 95), ], ]; } /** * Determine if the model type should use GPU resources * * @param string $modelType * @return bool */ private function shouldUseGPU(string $modelType): bool { return in_array($modelType, ['gpt-4', 'claude-2', 'llama-2-70b']); } /** * Get advanced conversation analytics for an AI agent * * @param int $agentId * @param string $timeframe day|week|month|all * @return array */ public function getAdvancedConversationAnalytics(int $agentId, string $timeframe = 'week'): array { $agent = AiAgent::findOrFail($agentId); $cacheKey = "agent_{$agentId}_conversation_analytics_{$timeframe}"; return Cache::remember($cacheKey, 300, function () use ($agent, $timeframe) { return $this->generateAdvancedConversationAnalytics($agent, $timeframe); }); } /** * Generate simulated advanced conversation analytics * * @param AiAgent $agent * @param string $timeframe * @return array */ private function generateAdvancedConversationAnalytics(AiAgent $agent, string $timeframe): array { return [ 'semantic_accuracy' => rand(85, 98) / 100, 'contextual_relevance' => rand(80, 95) / 100, 'conversation_depth' => [ 'average_turns' => rand(3, 15), 'max_turns' => rand(15, 50), 'turn_distribution' => [ '1-3' => rand(20, 40) / 100, '4-6' => rand(30, 50) / 100, '7-10' => rand(10, 30) / 100, '11+' => rand(5, 15) / 100, ], ], 'user_engagement' => [ 'follow_up_rate' => rand(40, 80) / 100, 'abandonment_rate' => rand(5, 20) / 100, 'average_session_duration' => rand(60, 600), // seconds 'return_user_rate' => rand(30, 70) / 100, ], 'topic_analysis' => [ 'most_common_topics' => [ ['name' => 'Technical Support', 'frequency' => rand(20, 40) / 100], ['name' => 'Feature Inquiries', 'frequency' => rand(15, 30) / 100], ['name' => 'Account Issues', 'frequency' => rand(10, 25) / 100], ['name' => 'Billing Questions', 'frequency' => rand(5, 20) / 100], ['name' => 'General Information', 'frequency' => rand(10, 30) / 100], ], 'topic_complexity' => rand(1, 10) / 2, // scale of 0.5-5 ], 'sentiment_analysis' => [ 'overall_sentiment' => rand(-10, 30) / 10, // scale of -1 to 3 'sentiment_trend' => rand(-5, 5) / 10, // change over time 'emotional_distribution' => [ 'positive' => rand(40, 70) / 100, 'neutral' => rand(20, 40) / 100, 'negative' => rand(5, 20) / 100, ], ], 'response_quality' => [ 'hallucination_rate' => rand(1, 10) / 100, 'factual_accuracy' => rand(85, 98) / 100, 'coherence_score' => rand(80, 95) / 100, 'helpfulness_rating' => rand(3, 5) / 1, // scale of 1-5 ], ]; } /** * Set up performance alert thresholds for an AI agent * * @param int $agentId * @param array $thresholds * @return bool */ public function setPerformanceAlertThresholds(int $agentId, array $thresholds): bool { $agent = AiAgent::findOrFail($agentId); Log::info("Setting performance alert thresholds for agent ID: {$agentId}", [ 'thresholds' => $thresholds ]); // In a real implementation, this would store thresholds in a database // For now, we'll cache them $cacheKey = "agent_{$agentId}_alert_thresholds"; Cache::put($cacheKey, $thresholds, now()->addDays(30)); return true; } /** * Get current performance alert thresholds for an AI agent * * @param int $agentId * @return array */ public function getPerformanceAlertThresholds(int $agentId): array { $agent = AiAgent::findOrFail($agentId); $cacheKey = "agent_{$agentId}_alert_thresholds"; return Cache::get($cacheKey, [ 'error_rate' => 0.05, // 5% 'response_time' => 2000, // milliseconds 'token_usage' => 1000000, // per day 'cpu_utilization' => 90, // percentage 'memory_utilization' => 85, // percentage 'gpu_utilization' => 95, // percentage 'cost_limit' => 50.00, // dollars per day ]); } /** * Check if any performance metrics exceed alert thresholds * * @param int $agentId * @return array */ public function checkPerformanceAlerts(int $agentId): array { $agent = AiAgent::findOrFail($agentId); $thresholds = $this->getPerformanceAlertThresholds($agentId); $currentMetrics = $this->getRealTimeUsageStats($agentId); $performanceMetrics = $this->getAgentPerformanceMetrics($agentId, 'day'); $alerts = []; // Check error rate if ($currentMetrics['error_rate'] > $thresholds['error_rate']) { $alerts[] = [ 'type' => 'error_rate', 'severity' => 'high', 'message' => "Error rate of {$currentMetrics['error_rate']} exceeds threshold of {$thresholds['error_rate']}", 'current_value' => $currentMetrics['error_rate'], 'threshold' => $thresholds['error_rate'], ]; } // Check response time if ($currentMetrics['average_response_time'] > $thresholds['response_time']) { $alerts[] = [ 'type' => 'response_time', 'severity' => 'medium', 'message' => "Average response time of {$currentMetrics['average_response_time']}ms exceeds threshold of {$thresholds['response_time']}ms", 'current_value' => $currentMetrics['average_response_time'], 'threshold' => $thresholds['response_time'], ]; } // Check CPU usage if ($currentMetrics['cpu_usage'] > $thresholds['cpu_utilization']) { $alerts[] = [ 'type' => 'cpu_usage', 'severity' => 'medium', 'message' => "CPU usage of {$currentMetrics['cpu_usage']}% exceeds threshold of {$thresholds['cpu_utilization']}%", 'current_value' => $currentMetrics['cpu_usage'], 'threshold' => $thresholds['cpu_utilization'], ]; } // Check memory usage if ($currentMetrics['memory_usage'] > ($thresholds['memory_utilization'] * 5)) { // Convert percentage to MB (rough estimate) $alerts[] = [ 'type' => 'memory_usage', 'severity' => 'medium', 'message' => "Memory usage of {$currentMetrics['memory_usage']}MB is high", 'current_value' => $currentMetrics['memory_usage'], 'threshold' => $thresholds['memory_utilization'] * 5, ]; } // Check cost estimate if (isset($performanceMetrics['cost_estimate']) && $performanceMetrics['cost_estimate'] > $thresholds['cost_limit']) { $alerts[] = [ 'type' => 'cost', 'severity' => 'high', 'message' => "Estimated cost of ${$performanceMetrics['cost_estimate']} exceeds daily limit of ${$thresholds['cost_limit']}", 'current_value' => $performanceMetrics['cost_estimate'], 'threshold' => $thresholds['cost_limit'], ]; } return [ 'agent_id' => $agentId, 'agent_name' => $agent->name, 'timestamp' => now()->toIso8601String(), 'alerts' => $alerts, 'alert_count' => count($alerts), 'status' => count($alerts) > 0 ? 'warning' : 'normal', ]; } /** * Export performance data to CSV format * * @param int $agentId * @param string $timeframe day|week|month|all * @param string $metricType performance|resource|conversation|all * @return string CSV content as string */ public function exportPerformanceDataToCsv(int $agentId, string $timeframe = 'week', string $metricType = 'all'): string { $agent = AiAgent::findOrFail($agentId); $data = []; $headers = ['Date', 'Metric', 'Value']; // Get appropriate data based on metric type if ($metricType === 'performance' || $metricType === 'all') { $performanceMetrics = $this->getAgentPerformanceMetrics($agentId, $timeframe); foreach ($performanceMetrics as $key => $value) { if (!is_array($value) && !is_object($value)) { $data[] = [now()->format('Y-m-d'), "performance_{$key}", $value]; } } } if ($metricType === 'resource' || $metricType === 'all') { $resourceMetrics = $this->getResourceUtilizationMetrics($agentId, $timeframe); if (isset($resourceMetrics['data_points'])) { foreach ($resourceMetrics['data_points'] as $point) { $date = $point['date']; if (isset($point['cpu_utilization']['average'])) { $data[] = [$date, 'cpu_utilization_avg', $point['cpu_utilization']['average']]; } if (isset($point['memory_utilization']['average'])) { $data[] = [$date, 'memory_utilization_avg', $point['memory_utilization']['average']]; } } } } if ($metricType === 'conversation' || $metricType === 'all') { $conversationMetrics = $this->getConversationQualityMetrics($agentId, $timeframe); foreach ($conversationMetrics as $key => $value) { if (!is_array($value)) { $data[] = [now()->format('Y-m-d'), "conversation_{$key}", $value]; } } } // Generate CSV $csv = implode(',', $headers) . "\n"; foreach ($data as $row) { $csv .= implode(',', $row) . "\n"; } return $csv; } /** * Generate a performance report for an AI agent * * @param int $agentId * @param string $timeframe day|week|month|all * @return array */ public function generatePerformanceReport(int $agentId, string $timeframe = 'week'): array { $agent = AiAgent::findOrFail($agentId); // Get all relevant metrics $performanceMetrics = $this->getAgentPerformanceMetrics($agentId, $timeframe); $resourceMetrics = $this->getResourceUtilizationMetrics($agentId, $timeframe); $conversationMetrics = $this->getConversationQualityMetrics($agentId, $timeframe); $usageHistory = $this->getUsageHistory($agentId, $timeframe); $alerts = $this->checkPerformanceAlerts($agentId); // Calculate trends $trends = $this->calculatePerformanceTrends($usageHistory); // Generate insights $insights = $this->generatePerformanceInsights( $agent, $performanceMetrics, $resourceMetrics, $conversationMetrics, $trends ); return [ 'agent_id' => $agentId, 'agent_name' => $agent->name, 'model_type' => $agent->model_type, 'report_generated_at' => now()->toIso8601String(), 'timeframe' => $timeframe, 'summary' => [ 'total_requests' => $performanceMetrics['total_requests'] ?? 0, 'total_tokens_used' => $performanceMetrics['total_tokens_used'] ?? 0, 'average_response_time' => $performanceMetrics['average_response_time'] ?? 0, 'error_rate' => $performanceMetrics['error_rate'] ?? 0, 'cost_estimate' => $performanceMetrics['cost_estimate'] ?? 0, 'user_satisfaction' => $conversationMetrics['average_user_satisfaction'] ?? 0, 'resource_efficiency_score' => $resourceMetrics['summary']['resource_efficiency_score'] ?? 0, ], 'performance_metrics' => $performanceMetrics, 'resource_metrics' => $resourceMetrics, 'conversation_metrics' => $conversationMetrics, 'usage_history' => $usageHistory, 'alerts' => $alerts, 'trends' => $trends, 'insights' => $insights, 'recommendations' => $this->generateOptimizationRecommendations($agent, $insights), ]; } /** * Calculate performance trends from usage history * * @param array $usageHistory * @return array */ private function calculatePerformanceTrends(array $usageHistory): array { if (count($usageHistory) < 2) { return [ 'requests' => 0, 'tokens_used' => 0, 'response_time' => 0, 'error_rate' => 0, ]; } $firstDay = $usageHistory[count($usageHistory) - 1]; $lastDay = $usageHistory[0]; return [ 'requests' => $this->calculateTrendPercentage($firstDay['requests'], $lastDay['requests']), 'tokens_used' => $this->calculateTrendPercentage($firstDay['tokens_used'], $lastDay['tokens_used']), 'response_time' => $this->calculateTrendPercentage($firstDay['average_response_time'], $lastDay['average_response_time']), 'error_rate' => $this->calculateTrendPercentage($firstDay['error_rate'], $lastDay['error_rate']), ]; } /** * Calculate percentage change between two values * * @param float $oldValue * @param float $newValue * @return float */ private function calculateTrendPercentage(float $oldValue, float $newValue): float { if ($oldValue == 0) { return $newValue > 0 ? 100 : 0; } return round((($newValue - $oldValue) / $oldValue) * 100, 2); } /** * Generate performance insights based on metrics * * @param AiAgent $agent * @param array $performanceMetrics * @param array $resourceMetrics * @param array $conversationMetrics * @param array $trends * @return array */ private function generatePerformanceInsights( AiAgent $agent, array $performanceMetrics, array $resourceMetrics, array $conversationMetrics, array $trends ): array { $insights = []; // Analyze request volume if (isset($trends['requests']) && $trends['requests'] > 20) { $insights[] = [ 'type' => 'growth', 'metric' => 'requests', 'description' => "Request volume has increased by {$trends['requests']}% in the selected timeframe.", 'impact' => 'high', ]; } elseif (isset($trends['requests']) && $trends['requests'] < -20) { $insights[] = [ 'type' => 'decline', 'metric' => 'requests', 'description' => "Request volume has decreased by " . abs($trends['requests']) . "% in the selected timeframe.", 'impact' => 'medium', ]; } // Analyze response time if (isset($performanceMetrics['average_response_time']) && $performanceMetrics['average_response_time'] > 1500) { $insights[] = [ 'type' => 'performance_issue', 'metric' => 'response_time', 'description' => "Average response time is high at {$performanceMetrics['average_response_time']}ms.", 'impact' => 'high', ]; } // Analyze error rate if (isset($performanceMetrics['error_rate']) && $performanceMetrics['error_rate'] > 0.03) { $insights[] = [ 'type' => 'reliability_issue', 'metric' => 'error_rate', 'description' => "Error rate is above optimal at " . ($performanceMetrics['error_rate'] * 100) . "%.", 'impact' => 'high', ]; } // Analyze resource utilization if (isset($resourceMetrics['summary']['average_cpu_utilization']) && $resourceMetrics['summary']['average_cpu_utilization'] > 70) { $insights[] = [ 'type' => 'resource_issue', 'metric' => 'cpu_utilization', 'description' => "Average CPU utilization is high at {$resourceMetrics['summary']['average_cpu_utilization']}%.", 'impact' => 'medium', ]; } // Analyze conversation quality if (isset($conversationMetrics['task_completion_rate']) && $conversationMetrics['task_completion_rate'] < 0.8) { $insights[] = [ 'type' => 'quality_issue', 'metric' => 'task_completion', 'description' => "Task completion rate is below target at " . ($conversationMetrics['task_completion_rate'] * 100) . "%.", 'impact' => 'high', ]; } // Analyze cost efficiency if (isset($performanceMetrics['cost_estimate']) && isset($performanceMetrics['total_requests']) && $performanceMetrics['total_requests'] > 0) { $costPerRequest = $performanceMetrics['cost_estimate'] / $performanceMetrics['total_requests']; if ($costPerRequest > 0.01) { $insights[] = [ 'type' => 'cost_issue', 'metric' => 'cost_per_request', 'description' => "Cost per request is high at $" . number_format($costPerRequest, 4) . ".", 'impact' => 'medium', ]; } } return $insights; } /** * Generate optimization recommendations based on insights * * @param AiAgent $agent * @param array $insights * @return array */ private function generateOptimizationRecommendations(AiAgent $agent, array $insights): array { $recommendations = []; foreach ($insights as $insight) { switch ($insight['metric']) { case 'response_time': $recommendations[] = [ 'priority' => $insight['impact'], 'title' => 'Optimize response time', 'description' => 'Consider optimizing prompt design or upgrading to a faster model to reduce response latency.', 'estimated_impact' => 'Could improve user experience and reduce abandonment rate.', ]; break; case 'error_rate': $recommendations[] = [ 'priority' => $insight['impact'], 'title' => 'Reduce error rate', 'description' => 'Implement better error handling and fallback mechanisms. Review common error patterns.', 'estimated_impact' => 'Could improve reliability and user satisfaction.', ]; break; case 'cpu_utilization': $recommendations[] = [ 'priority' => $insight['impact'], 'title' => 'Optimize resource usage', 'description' => 'Consider scaling infrastructure or implementing request batching to reduce CPU load.', 'estimated_impact' => 'Could reduce infrastructure costs and improve scalability.', ]; break; case 'task_completion': $recommendations[] = [ 'priority' => $insight['impact'], 'title' => 'Improve task completion rate', 'description' => 'Enhance prompt engineering or fine-tune the model to better handle common user requests.', 'estimated_impact' => 'Could significantly improve user satisfaction and reduce support tickets.', ]; break; case 'cost_per_request': $recommendations[] = [ 'priority' => $insight['impact'], 'title' => 'Reduce token usage', 'description' => 'Optimize prompts to use fewer tokens or consider using a more cost-effective model for certain tasks.', 'estimated_impact' => 'Could reduce operational costs while maintaining quality.', ]; break; } } // Add general recommendations if none were generated if (empty($recommendations)) { $recommendations[] = [ 'priority' => 'low', 'title' => 'Regular performance review', 'description' => 'Continue monitoring performance metrics and conduct regular reviews to maintain optimal operation.', 'estimated_impact' => 'Ensures continued high performance and early detection of issues.', ]; } return $recommendations; } /** * Schedule and generate periodic performance reports * * @param int $agentId * @param string $frequency daily|weekly|monthly * @param array $recipients Email addresses to send the report to * @return bool */ public function schedulePeriodicReports(int $agentId, string $frequency = 'weekly', array $recipients = []): bool { $agent = AiAgent::findOrFail($agentId); Log::info("Scheduling periodic performance reports for agent ID: {$agentId}", [ 'frequency' => $frequency, 'recipients' => $recipients ]); // In a real implementation, this would create a scheduled task // For now, we'll just store the schedule in cache $cacheKey = "agent_{$agentId}_report_schedule"; Cache::put($cacheKey, [ 'frequency' => $frequency, 'recipients' => $recipients, 'last_sent' => null, 'next_scheduled' => $this->calculateNextReportDate($frequency), ], now()->addYear()); return true; } /** * Calculate the next report date based on frequency * * @param string $frequency * @return string ISO8601 date string */ private function calculateNextReportDate(string $frequency): string { return match($frequency) { 'daily' => Carbon::tomorrow()->startOfDay(), 'weekly' => Carbon::now()->addWeek()->startOfWeek(), 'monthly' => Carbon::now()->addMonth()->startOfMonth(), default => Carbon::now()->addWeek(), }->toIso8601String(); } /** * Get trend analysis for an AI agent over multiple timeframes * * @param int $agentId * @return array */ public function getTrendAnalysis(int $agentId): array { $agent = AiAgent::findOrFail($agentId); // Get metrics for different timeframes $dayMetrics = $this->getAgentPerformanceMetrics($agentId, 'day'); $weekMetrics = $this->getAgentPerformanceMetrics($agentId, 'week'); $monthMetrics = $this->getAgentPerformanceMetrics($agentId, 'month'); // Calculate key performance indicators $kpis = [ 'requests_per_day' => [ 'day' => $dayMetrics['total_requests'] ?? 0, 'week' => ($weekMetrics['total_requests'] ?? 0) / 7, 'month' => ($monthMetrics['total_requests'] ?? 0) / 30, 'trend' => $this->calculateSimpleTrend( ($monthMetrics['total_requests'] ?? 0) / 30, ($weekMetrics['total_requests'] ?? 0) / 7, $dayMetrics['total_requests'] ?? 0 ), ], 'tokens_per_request' => [ 'day' => $dayMetrics['total_requests'] > 0 ? ($dayMetrics['total_tokens_used'] ?? 0) / $dayMetrics['total_requests'] : 0, 'week' => $weekMetrics['total_requests'] > 0 ? ($weekMetrics['total_tokens_used'] ?? 0) / $weekMetrics['total_requests'] : 0, 'month' => $monthMetrics['total_requests'] > 0 ? ($monthMetrics['total_tokens_used'] ?? 0) / $monthMetrics['total_requests'] : 0, 'trend' => 'stable', ], 'error_rate' => [ 'day' => $dayMetrics['error_rate'] ?? 0, 'week' => $weekMetrics['error_rate'] ?? 0, 'month' => $monthMetrics['error_rate'] ?? 0, 'trend' => $this->calculateSimpleTrend( $monthMetrics['error_rate'] ?? 0, $weekMetrics['error_rate'] ?? 0, $dayMetrics['error_rate'] ?? 0 ), ], 'response_time' => [ 'day' => $dayMetrics['average_response_time'] ?? 0, 'week' => $weekMetrics['average_response_time'] ?? 0, 'month' => $monthMetrics['average_response_time'] ?? 0, 'trend' => $this->calculateSimpleTrend( $monthMetrics['average_response_time'] ?? 0, $weekMetrics['average_response_time'] ?? 0, $dayMetrics['average_response_time'] ?? 0 ), ], 'cost_per_day' => [ 'day' => $dayMetrics['cost_estimate'] ?? 0, 'week' => ($weekMetrics['cost_estimate'] ?? 0) / 7, 'month' => ($monthMetrics['cost_estimate'] ?? 0) / 30, 'trend' => $this->calculateSimpleTrend( ($monthMetrics['cost_estimate'] ?? 0) / 30, ($weekMetrics['cost_estimate'] ?? 0) / 7, $dayMetrics['cost_estimate'] ?? 0 ), ], ]; // Calculate tokens per request trend $kpis['tokens_per_request']['trend'] = $this->calculateSimpleTrend( $kpis['tokens_per_request']['month'], $kpis['tokens_per_request']['week'], $kpis['tokens_per_request']['day'] ); return [ 'agent_id' => $agentId, 'agent_name' => $agent->name, 'analysis_date' => now()->toIso8601String(), 'kpis' => $kpis, 'summary' => $this->generateTrendSummary($kpis), ]; } /** * Calculate a simple trend direction based on three data points * * @param float $oldest * @param float $middle * @param float $newest * @return string increasing|decreasing|stable */ private function calculateSimpleTrend(float $oldest, float $middle, float $newest): string { // If both changes are in the same direction by a significant amount $middleChange = $middle - $oldest; $newestChange = $newest - $middle; // Define significance threshold as 5% of the oldest value or 0.01, whichever is larger $threshold = max(abs($oldest) * 0.05, 0.01); if (abs($middleChange) < $threshold && abs($newestChange) < $threshold) { return 'stable'; } if ($middleChange > $threshold && $newestChange > $threshold) { return 'increasing'; } if ($middleChange < -$threshold && $newestChange < -$threshold) { return 'decreasing'; } // If the changes are inconsistent or small return 'fluctuating'; } /** * Generate a summary of trend analysis * * @param array $kpis * @return array */ private function generateTrendSummary(array $kpis): array { $summary = []; // Analyze request volume trend if ($kpis['requests_per_day']['trend'] === 'increasing') { $summary[] = 'Request volume is trending upward, which may require scaling resources.'; } elseif ($kpis['requests_per_day']['trend'] === 'decreasing') { $summary[] = 'Request volume is trending downward, which may indicate reduced user engagement.'; } // Analyze error rate trend if ($kpis['error_rate']['trend'] === 'increasing') { $summary[] = 'Error rate is increasing, which requires immediate investigation.'; } elseif ($kpis['error_rate']['trend'] === 'decreasing') { $summary[] = 'Error rate is improving, indicating successful system optimizations.'; } // Analyze response time trend if ($kpis['response_time']['trend'] === 'increasing') { $summary[] = 'Response time is increasing, which may negatively impact user experience.'; } elseif ($kpis['response_time']['trend'] === 'decreasing') { $summary[] = 'Response time is improving, indicating better system performance.'; } // Analyze cost trend if ($kpis['cost_per_day']['trend'] === 'increasing') { $summary[] = 'Daily cost is trending upward, which may require budget adjustments.'; } elseif ($kpis['cost_per_day']['trend'] === 'decreasing') { $summary[] = 'Daily cost is trending downward, indicating improved cost efficiency.'; } // Add a general summary if all trends are stable if (empty($summary)) { $summary[] = 'All key performance indicators are stable, indicating consistent system performance.'; } return $summary; } /** * Compare performance between two AI agents * * @param int $agentId1 * @param int $agentId2 * @param string $timeframe day|week|month|all * @return array */ public function compareAgentPerformance(int $agentId1, int $agentId2, string $timeframe = 'week'): array { $agent1 = AiAgent::findOrFail($agentId1); $agent2 = AiAgent::findOrFail($agentId2); // Get metrics for both agents $metrics1 = $this->getAgentPerformanceMetrics($agentId1, $timeframe); $metrics2 = $this->getAgentPerformanceMetrics($agentId2, $timeframe); // Compare key metrics $comparison = [ 'response_time' => [ 'agent1' => $metrics1['average_response_time'] ?? 0, 'agent2' => $metrics2['average_response_time'] ?? 0, 'difference' => ($metrics1['average_response_time'] ?? 0) - ($metrics2['average_response_time'] ?? 0), 'percentage_diff' => $this->calculatePercentageDifference( $metrics1['average_response_time'] ?? 0, $metrics2['average_response_time'] ?? 0 ), 'better_agent' => ($metrics1['average_response_time'] ?? 0) < ($metrics2['average_response_time'] ?? 0) ? $agentId1 : $agentId2, ], 'error_rate' => [ 'agent1' => $metrics1['error_rate'] ?? 0, 'agent2' => $metrics2['error_rate'] ?? 0, 'difference' => ($metrics1['error_rate'] ?? 0) - ($metrics2['error_rate'] ?? 0), 'percentage_diff' => $this->calculatePercentageDifference( $metrics1['error_rate'] ?? 0, $metrics2['error_rate'] ?? 0 ), 'better_agent' => ($metrics1['error_rate'] ?? 0) < ($metrics2['error_rate'] ?? 0) ? $agentId1 : $agentId2, ], 'cost_efficiency' => [ 'agent1' => $metrics1['total_requests'] > 0 ? ($metrics1['cost_estimate'] ?? 0) / $metrics1['total_requests'] : 0, 'agent2' => $metrics2['total_requests'] > 0 ? ($metrics2['cost_estimate'] ?? 0) / $metrics2['total_requests'] : 0, 'difference' => 0, // Calculated below 'percentage_diff' => 0, // Calculated below 'better_agent' => null, // Determined below ], ]; // Calculate cost efficiency difference $comparison['cost_efficiency']['difference'] = $comparison['cost_efficiency']['agent1'] - $comparison['cost_efficiency']['agent2']; $comparison['cost_efficiency']['percentage_diff'] = $this->calculatePercentageDifference( $comparison['cost_efficiency']['agent1'], $comparison['cost_efficiency']['agent2'] ); $comparison['cost_efficiency']['better_agent'] = $comparison['cost_efficiency']['agent1'] < $comparison['cost_efficiency']['agent2'] ? $agentId1 : $agentId2; // Generate summary $summary = []; if ($comparison['response_time']['better_agent'] === $agentId1) { $summary[] = "{$agent1->name} has better response time by {$comparison['response_time']['percentage_diff']}%."; } else { $summary[] = "{$agent2->name} has better response time by {$comparison['response_time']['percentage_diff']}%."; } if ($comparison['error_rate']['better_agent'] === $agentId1) { $summary[] = "{$agent1->name} has lower error rate by {$comparison['error_rate']['percentage_diff']}%."; } else { $summary[] = "{$agent2->name} has lower error rate by {$comparison['error_rate']['percentage_diff']}%."; } if ($comparison['cost_efficiency']['better_agent'] === $agentId1) { $summary[] = "{$agent1->name} is more cost-efficient by {$comparison['cost_efficiency']['percentage_diff']}%."; } else { $summary[] = "{$agent2->name} is more cost-efficient by {$comparison['cost_efficiency']['percentage_diff']}%."; } return [ 'agent1' => [ 'id' => $agentId1, 'name' => $agent1->name, 'model_type' => $agent1->model_type, ], 'agent2' => [ 'id' => $agentId2, 'name' => $agent2->name, 'model_type' => $agent2->model_type, ], 'timeframe' => $timeframe, 'comparison' => $comparison, 'summary' => $summary, 'overall_recommendation' => $this->determineOverallBetterAgent($comparison, $agent1, $agent2), ]; } /** * Calculate percentage difference between two values * * @param float $value1 * @param float $value2 * @return float */ private function calculatePercentageDifference(float $value1, float $value2): float { if ($value1 == 0 && $value2 == 0) { return 0; } if ($value2 == 0) { return 100; // Avoid division by zero } return round(abs(($value1 - $value2) / $value2) * 100, 2); } /** * Determine which agent has better overall performance * * @param array $comparison * @param AiAgent $agent1 * @param AiAgent $agent2 * @return string */ private function determineOverallBetterAgent(array $comparison, AiAgent $agent1, AiAgent $agent2): string { $agent1Score = 0; $agent2Score = 0; // Weight factors (can be adjusted based on priorities) $weights = [ 'response_time' => 0.3, 'error_rate' => 0.4, 'cost_efficiency' => 0.3, ]; foreach ($comparison as $metric => $data) { if ($data['better_agent'] === $agent1->id) { $agent1Score += $weights[$metric]; } else { $agent2Score += $weights[$metric]; } } if ($agent1Score > $agent2Score) { return "{$agent1->name} demonstrates better overall performance with a score of " . round($agent1Score * 10, 1) . "/10 compared to " . round($agent2Score * 10, 1) . "/10 for {$agent2->name}."; } elseif ($agent2Score > $agent1Score) { return "{$agent2->name} demonstrates better overall performance with a score of " . round($agent2Score * 10, 1) . "/10 compared to " . round($agent1Score * 10, 1) . "/10 for {$agent1->name}."; } else { return "Both {$agent1->name} and {$agent2->name} demonstrate similar overall performance."; } } /** * Export performance data to JSON format * * @param int $agentId * @param string $timeframe day|week|month|all * @param string $metricType performance|resource|conversation|all * @return string JSON content as string */ public function exportPerformanceDataToJson(int $agentId, string $timeframe = 'week', string $metricType = 'all'): string { $agent = AiAgent::findOrFail($agentId); $data = []; // Get appropriate data based on metric type if ($metricType === 'performance' || $metricType === 'all') { $data['performance_metrics'] = $this->getAgentPerformanceMetrics($agentId, $timeframe); } if ($metricType === 'resource' || $metricType === 'all') { $data['resource_metrics'] = $this->getResourceUtilizationMetrics($agentId, $timeframe); } if ($metricType === 'conversation' || $metricType === 'all') { $data['conversation_metrics'] = $this->getConversationQualityMetrics($agentId, $timeframe); $data['advanced_conversation_analytics'] = $this->getAdvancedConversationAnalytics($agentId, $timeframe); } $data['metadata'] = [ 'agent_id' => $agentId, 'agent_name' => $agent->name, 'model_type' => $agent->model_type, 'export_date' => now()->toIso8601String(), 'timeframe' => $timeframe, 'metric_type' => $metricType, ]; return json_encode($data, JSON_PRETTY_PRINT); } /** * Save performance report to storage * * @param int $agentId * @param string $timeframe day|week|month|all * @param string $format json|csv * @return string File path */ public function savePerformanceReport(int $agentId, string $timeframe = 'week', string $format = 'json'): string { $agent = AiAgent::findOrFail($agentId); $timestamp = now()->format('Y-m-d_H-i-s'); $filename = "agent_{$agentId}_report_{$timeframe}_{$timestamp}.{$format}"; $path = "reports/{$filename}"; if ($format === 'json') { $content = $this->exportPerformanceDataToCsv($agentId, $timeframe, 'all'); } else { $content = $this->exportPerformanceDataToCsv($agentId, $timeframe, 'all'); } Storage::put($path, $content); Log::info("Performance report saved for agent ID: {$agentId}", [ 'path' => $path, 'format' => $format, 'timeframe' => $timeframe, ]); return $path; } /** * Get anomaly detection for an AI agent * * @param int $agentId * @param string $timeframe day|week|month * @return array */ public function detectPerformanceAnomalies(int $agentId, string $timeframe = 'week'): array { $agent = AiAgent::findOrFail($agentId); $usageHistory = $this->getUsageHistory($agentId, $timeframe); $anomalies = []; // Need at least 3 data points for anomaly detection if (count($usageHistory) < 3) { return [ 'agent_id' => $agentId, 'agent_name' => $agent->name, 'timeframe' => $timeframe, 'anomalies' => [], 'anomaly_count' => 0, 'status' => 'insufficient_data', ]; } // Calculate mean and standard deviation for key metrics $metrics = ['requests', 'tokens_used', 'average_response_time', 'error_rate']; $stats = []; foreach ($metrics as $metric) { $values = array_column($usageHistory, $metric); $stats[$metric] = [ 'mean' => array_sum($values) / count($values), 'std_dev' => $this->calculateStandardDeviation($values), ]; // Check each data point for anomalies (beyond 2 standard deviations) foreach ($usageHistory as $index => $day) { $zScore = abs(($day[$metric] - $stats[$metric]['mean']) / max($stats[$metric]['std_dev'], 0.001)); if ($zScore > 2) { $anomalies[] = [ 'date' => $day['date'], 'metric' => $metric, 'value' => $day[$metric], 'expected_range' => [ 'min' => $stats[$metric]['mean'] - (2 * $stats[$metric]['std_dev']), 'max' => $stats[$metric]['mean'] + (2 * $stats[$metric]['std_dev']), ], 'z_score' => $zScore, 'severity' => $zScore > 3 ? 'high' : 'medium', ]; } } } return [ 'agent_id' => $agentId, 'agent_name' => $agent->name, 'timeframe' => $timeframe, 'anomalies' => $anomalies, 'anomaly_count' => count($anomalies), 'status' => count($anomalies) > 0 ? 'anomalies_detected' : 'normal', 'statistics' => $stats, ]; } /** * Calculate standard deviation for an array of values * * @param array $values * @return float */ private function calculateStandardDeviation(array $values): float { $count = count($values); if ($count < 2) { return 0; } $mean = array_sum($values) / $count; $variance = 0; foreach ($values as $value) { $variance += pow($value - $mean, 2); } return sqrt($variance / ($count - 1)); } /** * Get historical performance data for visualization * * @param int $agentId * @param string $metric requests|tokens|response_time|error_rate|cost * @param string $timeframe day|week|month|all * @return array */ public function getPerformanceVisualizationData(int $agentId, string $metric = 'requests', string $timeframe = 'month'): array { $agent = AiAgent::findOrFail($agentId); $usageHistory = $this->getUsageHistory($agentId, $timeframe); $labels = []; $values = []; // Map metric name to the actual field in usage history $metricField = match($metric) { 'tokens' => 'tokens_used', 'response_time' => 'average_response_time', 'error_rate' => 'error_rate', 'cost' => 'cost_estimate', default => 'requests', }; // If cost is requested but not in usage history, calculate it if ($metric === 'cost' && !isset($usageHistory[0][$metricField])) { foreach ($usageHistory as $index => $day) { $usageHistory[$index]['cost_estimate'] = $this->calculateCostEstimate( $agent->model_type, $day['tokens_used'] ?? 0 ); } } // Extract data for visualization foreach ($usageHistory as $day) { $labels[] = $day['date']; $values[] = $day[$metricField] ?? 0; } return [ 'agent_id' => $agentId, 'agent_name' => $agent->name, 'metric' => $metric, 'timeframe' => $timeframe, 'labels' => $labels, 'values' => $values, 'unit' => $this->getMetricUnit($metric), 'statistics' => [ 'min' => !empty($values) ? min($values) : 0, 'max' => !empty($values) ? max($values) : 0, 'avg' => !empty($values) ? array_sum($values) / count($values) : 0, 'total' => !empty($values) ? array_sum($values) : 0, ], ]; } /** * Get the appropriate unit for a metric * * @param string $metric * @return string */ private function getMetricUnit(string $metric): string { return match($metric) { 'tokens' => 'tokens', 'response_time' => 'ms', 'error_rate' => '%', 'cost' => '$', default => 'count', }; } /** * Get performance dashboard data for an AI agent * * @param int $agentId * @return array */ public function getDashboardData(int $agentId): array { $agent = AiAgent::findOrFail($agentId); // Get real-time stats $realTimeStats = $this->getRealTimeUsageStats($agentId); // Get today's metrics $todayMetrics = $this->getAgentPerformanceMetrics($agentId, 'day'); // Get trend analysis $trends = $this->getTrendAnalysis($agentId); // Get alerts $alerts = $this->checkPerformanceAlerts($agentId); return [ 'agent_id' => $agentId, 'agent_name' => $agent->name, 'model_type' => $agent->model_type, 'timestamp' => now()->toIso8601String(), 'real_time' => $realTimeStats, 'today' => [ 'requests' => $todayMetrics['total_requests'] ?? 0, 'tokens' => $todayMetrics['total_tokens_used'] ?? 0, 'response_time' => $todayMetrics['average_response_time'] ?? 0, 'error_rate' => $todayMetrics['error_rate'] ?? 0, 'cost' => $todayMetrics['cost_estimate'] ?? 0, ], 'trends' => $trends['kpis'], 'alerts' => $alerts['alerts'], 'status' => $alerts['status'], 'recommendations' => $this->generateQuickRecommendations($agent, $todayMetrics, $trends), ]; } /** * Generate quick recommendations based on dashboard data * * @param AiAgent $agent * @param array $metrics * @param array $trends * @return array */ private function generateQuickRecommendations(AiAgent $agent, array $metrics, array $trends): array { $recommendations = []; // Check response time if (($metrics['average_response_time'] ?? 0) > 1500) { $recommendations[] = 'Consider optimizing prompts or upgrading model to improve response time.'; } // Check error rate if (($metrics['error_rate'] ?? 0) > 0.03) { $recommendations[] = 'Investigate and address the high error rate to improve reliability.'; } // Check cost efficiency if (($metrics['total_requests'] ?? 0) > 0 && ($metrics['cost_estimate'] ?? 0) > 0) { $costPerRequest = $metrics['cost_estimate'] / $metrics['total_requests']; if ($costPerRequest > 0.01) { $recommendations[] = 'Review prompt design to reduce token usage and improve cost efficiency.'; } } // Check trends if (isset($trends['kpis']['requests_per_day']['trend']) && $trends['kpis']['requests_per_day']['trend'] === 'increasing') { $recommendations[] = 'Usage is growing. Consider scaling resources to maintain performance.'; } // If no specific recommendations, provide a general one if (empty($recommendations)) { $recommendations[] = 'All metrics are within optimal ranges. Continue monitoring for any changes.'; } return $recommendations; } }