init project
This commit is contained in:
153
app/Services/DashboardUsageSummary.php
Normal file
153
app/Services/DashboardUsageSummary.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\EmbeddingUsageEvent;
|
||||
use App\Models\User;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DashboardUsageSummary
|
||||
{
|
||||
/**
|
||||
* @return array{
|
||||
* days: int,
|
||||
* totals: array{actions: int, inputs: int, results: int, models: int},
|
||||
* daily: array<int, array{date: string, label: string, actions: int, inputs: int, height: int}>,
|
||||
* tools: array<int, array{key: string, label: string, actions: int, inputs: int, results: int, percentage: int}>,
|
||||
* models: array<int, array{label: string, actions: int, inputs: int, percentage: int}>,
|
||||
* recent: array<int, array{tool: string, tool_label: string, model: string, inputs: int, results: int, created_at: string}>
|
||||
* }
|
||||
*/
|
||||
public function forUser(User $user, int $days = 14): array
|
||||
{
|
||||
$days = max(7, min(30, $days));
|
||||
$startDate = CarbonImmutable::today()->subDays($days - 1);
|
||||
|
||||
$events = EmbeddingUsageEvent::query()
|
||||
->whereBelongsTo($user)
|
||||
->where('created_at', '>=', $startDate->startOfDay())
|
||||
->latest()
|
||||
->get(['tool', 'model', 'input_count', 'result_count', 'created_at']);
|
||||
|
||||
return [
|
||||
'days' => $days,
|
||||
'totals' => $this->totals($events),
|
||||
'daily' => $this->dailyActivity($events, $startDate, $days),
|
||||
'tools' => $this->toolUsage($events),
|
||||
'models' => $this->modelUsage($events),
|
||||
'recent' => $this->recentActivity($events),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, EmbeddingUsageEvent> $events
|
||||
* @return array{actions: int, inputs: int, results: int, models: int}
|
||||
*/
|
||||
protected function totals(Collection $events): array
|
||||
{
|
||||
return [
|
||||
'actions' => $events->count(),
|
||||
'inputs' => (int) $events->sum('input_count'),
|
||||
'results' => (int) $events->sum('result_count'),
|
||||
'models' => $events->pluck('model')->unique()->count(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, EmbeddingUsageEvent> $events
|
||||
* @return array<int, array{date: string, label: string, actions: int, inputs: int, height: int}>
|
||||
*/
|
||||
protected function dailyActivity(Collection $events, CarbonImmutable $startDate, int $days): array
|
||||
{
|
||||
$daily = collect(range(0, $days - 1))
|
||||
->map(function (int $offset) use ($events, $startDate): array {
|
||||
$date = $startDate->addDays($offset);
|
||||
$dayEvents = $events->filter(fn (EmbeddingUsageEvent $event): bool => $event->created_at->isSameDay($date));
|
||||
|
||||
return [
|
||||
'date' => $date->toDateString(),
|
||||
'label' => $date->format('M j'),
|
||||
'actions' => $dayEvents->count(),
|
||||
'inputs' => (int) $dayEvents->sum('input_count'),
|
||||
'height' => 0,
|
||||
];
|
||||
});
|
||||
|
||||
$maxActions = max(1, (int) $daily->max('actions'));
|
||||
|
||||
return $daily
|
||||
->map(fn (array $day): array => [
|
||||
...$day,
|
||||
'height' => $day['actions'] > 0 ? max(8, (int) round(($day['actions'] / $maxActions) * 100)) : 0,
|
||||
])
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, EmbeddingUsageEvent> $events
|
||||
* @return array<int, array{key: string, label: string, actions: int, inputs: int, results: int, percentage: int}>
|
||||
*/
|
||||
protected function toolUsage(Collection $events): array
|
||||
{
|
||||
$maxActions = max(1, $events->groupBy('tool')->map->count()->max() ?? 0);
|
||||
|
||||
return $events
|
||||
->groupBy('tool')
|
||||
->map(fn (Collection $toolEvents, string $tool): array => [
|
||||
'key' => $tool,
|
||||
'label' => Str::of($tool)->replace('_', ' ')->headline()->value(),
|
||||
'actions' => $toolEvents->count(),
|
||||
'inputs' => (int) $toolEvents->sum('input_count'),
|
||||
'results' => (int) $toolEvents->sum('result_count'),
|
||||
'percentage' => (int) round(($toolEvents->count() / $maxActions) * 100),
|
||||
])
|
||||
->sortByDesc('actions')
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, EmbeddingUsageEvent> $events
|
||||
* @return array<int, array{label: string, actions: int, inputs: int, percentage: int}>
|
||||
*/
|
||||
protected function modelUsage(Collection $events): array
|
||||
{
|
||||
$maxActions = max(1, $events->groupBy('model')->map->count()->max() ?? 0);
|
||||
|
||||
return $events
|
||||
->groupBy('model')
|
||||
->map(fn (Collection $modelEvents, string $model): array => [
|
||||
'label' => $model,
|
||||
'actions' => $modelEvents->count(),
|
||||
'inputs' => (int) $modelEvents->sum('input_count'),
|
||||
'percentage' => (int) round(($modelEvents->count() / $maxActions) * 100),
|
||||
])
|
||||
->sortByDesc('actions')
|
||||
->take(5)
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, EmbeddingUsageEvent> $events
|
||||
* @return array<int, array{tool: string, tool_label: string, model: string, inputs: int, results: int, created_at: string}>
|
||||
*/
|
||||
protected function recentActivity(Collection $events): array
|
||||
{
|
||||
return $events
|
||||
->take(6)
|
||||
->map(fn (EmbeddingUsageEvent $event): array => [
|
||||
'tool' => $event->tool,
|
||||
'tool_label' => Str::of($event->tool)->replace('_', ' ')->headline()->value(),
|
||||
'model' => $event->model,
|
||||
'inputs' => $event->input_count,
|
||||
'results' => $event->result_count,
|
||||
'created_at' => $event->created_at->diffForHumans(short: true),
|
||||
])
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user