nimuli/app/Livewire/Pages/Ai/Insights.php

91 lines
3.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?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 12 observations possible from the limited data, then stop.
- Otherwise give 34 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']);
}
}