userInterests()->orderByDesc('created_at')->get(); $suggestions = session('suggestions', []); return view('admin.interests.index', compact('interests', 'suggestions')); } /** * Store a new user interest. */ public function store(Request $request): RedirectResponse { $validated = $request->validate([ 'interest' => ['required', 'string', 'max:255'], ]); /** @var \App\Models\User $user */ $user = Auth::user(); $user->userInterests()->create([ 'interest' => $validated['interest'], ]); return back()->with('success', __('Interest added successfully.')); } /** * Remove the specified user interest. */ public function destroy(UserInterest $userInterest): RedirectResponse { $this->authorize('delete', $userInterest); $userInterest->delete(); return back()->with('success', __('Interest removed successfully.')); } /** * Generate AI subject suggestions based on user interests. */ public function generateSuggestions(Request $request): RedirectResponse { /** @var \App\Models\User $user */ $user = Auth::user(); $interests = $user->userInterests()->pluck('interest')->toArray(); if (empty($interests)) { return back()->with('error', __('Add at least one interest before generating suggestions.')); } $interestsList = implode(', ', $interests); $prompt = "Com base nos interesses do usuário: {$interestsList}. Sugira de 3 a 5 temas de assuntos de aprendizado que seriam relevantes para este usuário. Para cada tema, forneça: 1) name (formato: 'Aprendizado e Treinamento de [Tema]'), 2) description (máximo 1000 caracteres), 3) introduction (máximo 5000 caracteres). Retorne APENAS um array JSON válido (sem texto adicional, sem markdown, sem code blocks) com objetos contendo esses campos. Todo o conteúdo deve estar em Português do Brasil."; /** @var \App\Services\AIService $ai */ $ai = app(AIService::class); $result = $ai->generateInsight('Sugestões de assuntos', $prompt, ['language' => 'pt_BR']); if (!$result['success']) { return back()->with('error', __('Failed to generate suggestions: :error', ['error' => $result['error'] ?? __('Unknown error')])); } $suggestions = $this->extractJsonFromAiResponse($result['content']); if (!$suggestions || !is_array($suggestions)) { return back()->with('error', __('Failed to parse AI suggestions. Please try again.')); } return back()->with('suggestions', $suggestions)->with('success', __('Suggestions generated successfully.')); } /** * Create a subject automatically from a suggestion. */ public function createSubjectFromSuggestion(Request $request): RedirectResponse { $request->validate([ 'name' => ['required', 'string', 'max:255'], 'description' => ['nullable', 'string', 'max:1000'], 'introduction' => ['nullable', 'string', 'max:5000'], ]); $existing = Subject::where('name', $request->name)->first(); if ($existing) { return back()->with('error', __('A subject with this name already exists.')); } $subject = Subject::create([ 'user_id' => Auth::id(), 'name' => $request->name, 'description' => $request->description, 'introduction' => $request->introduction, 'is_system' => false, 'is_active' => true, ]); UserSubject::firstOrCreate( [ 'user_id' => Auth::id(), 'subject_id' => $subject->id, ], [ 'frequency' => 'daily', 'preferred_times' => ['09:00'], 'insight_language' => Auth::user()->locale ?? 'en', 'delivery_channels' => ['dashboard'], 'is_active' => true, ] ); return back()->with('success', __('Subject created successfully.')); } /** * Extract JSON from AI response, handling code blocks and plain text. */ private function extractJsonFromAiResponse(string $content): ?array { $content = trim($content); if (str_starts_with($content, '```')) { $content = preg_replace('/^```(?:json)?\s*/', '', $content); $content = preg_replace('/\s*```$/', '', $content); } $data = json_decode($content, true); if (json_last_error() === JSON_ERROR_NONE && is_array($data)) { return $data; } if (preg_match('/\[.*\]/s', $content, $matches)) { $data = json_decode($matches[0], true); if (json_last_error() === JSON_ERROR_NONE && is_array($data)) { return $data; } } return null; } }