$metrics */ public function calculatePopularityScore(array $metrics): float { return round( ((float) ($metrics['unique_visitors'] ?? 0) * 1) + ((float) ($metrics['engaged_views'] ?? 0) * 3) + ((float) ($metrics['likes'] ?? 0) * 5) + ((float) ($metrics['saves'] ?? 0) * 7) + ((float) ($metrics['prompt_copies'] ?? 0) * 8) + ((float) ($metrics['negative_prompt_copies'] ?? 0) * 4) + ((float) ($metrics['starts'] ?? 0) * 4) + ((float) ($metrics['completions'] ?? 0) * 10) + ((float) ($metrics['upgrade_clicks'] ?? 0) * 15) + ((float) ($metrics['premium_preview_views'] ?? 0) * 3) - ((float) ($metrics['bounce_count'] ?? 0) * 2), 2, ); } /** * @param array $metrics */ public function calculateConversionScore(array $metrics): float { $uniqueVisitors = max(1, (int) ($metrics['unique_visitors'] ?? 0)); return round((((float) ($metrics['upgrade_clicks'] ?? 0) * 100) / $uniqueVisitors), 2); } public function queryBetween(Carbon $from, Carbon $to): Builder { return AcademyContentMetricDaily::query() ->whereBetween('date', [$from->copy()->startOfDay(), $to->copy()->endOfDay()]); } public function topContent(Carbon $from, Carbon $to, int $limit = 10): Collection { return $this->queryBetween($from, $to) ->selectRaw('content_type, content_id, sum(views) as views, sum(unique_visitors) as unique_visitors, sum(engaged_views) as engaged_views, sum(likes) as likes, sum(saves) as saves, sum(prompt_copies) as prompt_copies, sum(completions) as completions, sum(upgrade_clicks) as upgrade_clicks, sum(popularity_score) as popularity_score') ->groupBy('content_type', 'content_id') ->orderByDesc('popularity_score') ->limit($limit) ->get(); } }