init project

This commit is contained in:
2026-05-10 13:21:24 +03:30
parent 5f210c6c73
commit dc36701c9d
26 changed files with 2149 additions and 69 deletions

View 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();
}
}