91 lines
3.0 KiB
PHP
91 lines
3.0 KiB
PHP
<?php
|
||
|
||
namespace App\Livewire\Pages\Ai;
|
||
|
||
use App\Domains\Ai\Services\AiService;
|
||
use App\Domains\Link\Models\Link;
|
||
use App\Domains\Workspace\Models\Workspace;
|
||
use Illuminate\View\View;
|
||
use Livewire\Component;
|
||
|
||
class Insights extends Component
|
||
{
|
||
public string $insights = '';
|
||
|
||
public string $error = '';
|
||
|
||
public int $workspaceId = 0;
|
||
|
||
public function mount(): void
|
||
{
|
||
$this->workspaceId = require_workspace()->id;
|
||
}
|
||
|
||
public function generate(): void
|
||
{
|
||
$this->error = '';
|
||
$this->insights = '';
|
||
|
||
if (! config('services.openai.api_key')) {
|
||
$this->error = 'OPENAI_API_KEY is not configured. Add it to .env and restart.';
|
||
return;
|
||
}
|
||
|
||
try {
|
||
$workspace = Workspace::findOrFail($this->workspaceId);
|
||
|
||
$topLinks = Link::where('workspace_id', $workspace->id)
|
||
->withCount('clicks')
|
||
->orderByDesc('clicks_count')
|
||
->limit(10)
|
||
->get(['slug', 'target_url', 'clicks_count']);
|
||
|
||
if ($topLinks->isEmpty()) {
|
||
$this->error = 'No links with clicks found. Create and share some links first.';
|
||
return;
|
||
}
|
||
|
||
$locale = auth()->user()?->locale ?? 'en';
|
||
$langMap = ['de' => 'German', 'en' => 'English', 'fr' => 'French', 'es' => 'Spanish', 'it' => 'Italian', 'pt' => 'Portuguese'];
|
||
$language = $langMap[$locale] ?? 'English';
|
||
|
||
$totalClicks = $topLinks->sum('clicks_count');
|
||
$linkCount = $topLinks->count();
|
||
$summary = $topLinks->map(fn ($l) => "- {$l->slug} ({$l->clicks_count} clicks) → {$l->target_url}")->implode("\n");
|
||
|
||
$prompt = <<<PROMPT
|
||
You are a link performance analyst for a URL shortener. Respond in {$language}.
|
||
|
||
Workspace: {$workspace->name}
|
||
Links analysed: {$linkCount} | Total clicks: {$totalClicks}
|
||
|
||
Data:
|
||
{$summary}
|
||
|
||
Rules:
|
||
- If fewer than 3 links or fewer than 10 total clicks exist, say so upfront and explain that reliable patterns need more data. Give 1–2 observations possible from the limited data, then stop.
|
||
- Otherwise give 3–4 insights: best-performing destination types, domain patterns, what underperforming links share, one concrete next action.
|
||
- Every claim must reference a specific slug or URL from the data above.
|
||
- No generic marketing advice. No padding. Plain language, no excessive formatting.
|
||
PROMPT;
|
||
|
||
$result = app(AiService::class)->complete($prompt);
|
||
|
||
if ($result === '') {
|
||
$this->error = 'AI returned an empty response. Check your API key and try again.';
|
||
return;
|
||
}
|
||
|
||
$this->insights = $result;
|
||
} catch (\Throwable $e) {
|
||
$this->error = 'Failed to generate insights: ' . $e->getMessage();
|
||
}
|
||
}
|
||
|
||
public function render(): View
|
||
{
|
||
return view('livewire.pages.ai.insights')
|
||
->layout('layouts.nimuli-app', ['title' => 'AI Insights']);
|
||
}
|
||
}
|