json([ 'success' => false, 'message' => 'O assistente virtual está indisponível no momento.', ], 403); } $validator = Validator::make($request->all(), [ 'session_id' => 'required|string|max:255|regex:/^[a-zA-Z0-9\-_]+$/', 'name' => 'required|string|max:255', 'phone' => 'required|string|max:30', 'city' => 'required|string|max:255', ], [ 'session_id.regex' => 'ID de sessão inválido.', 'name.required' => 'Por favor, informe seu nome.', 'phone.required' => 'Por favor, informe seu telefone.', 'city.required' => 'Por favor, informe sua cidade.', ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => 'Preencha todos os campos obrigatórios.', 'errors' => $validator->errors(), ], 422); } $sessionId = $request->input('session_id'); // Get or create conversation and save visitor info $conversation = ChatbotConversation::getOrCreateBySession($sessionId); $conversation->update([ 'visitor_name' => trim($request->input('name')), 'visitor_phone' => trim($request->input('phone')), 'visitor_city' => trim($request->input('city')), ]); // Send notification to admins $adminTypes = \App\Models\UserType::where('is_admin', true)->pluck('name')->toArray(); $admins = User::whereIn('user_type', $adminTypes)->get(); if ($admins->isNotEmpty()) { Notification::send($admins, new ChatbotConversationNotification($conversation)); } return response()->json([ 'success' => true, 'message' => 'Dados registrados com sucesso.', ]); } /** * Handle an incoming chat message from the public widget. */ public function sendMessage(Request $request): JsonResponse { // Check if chatbot is enabled if (Setting::get('chatbot_enabled', 'off') !== 'on') { return response()->json([ 'success' => false, 'message' => 'O assistente virtual está indisponível no momento.', ], 403); } $validator = Validator::make($request->all(), [ 'message' => 'required|string|max:1000', 'session_id' => 'required|string|max:255|regex:/^[a-zA-Z0-9\-_]+$/', ], [ 'session_id.regex' => 'ID de sessão inválido.', ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => 'Mensagem inválida.', 'errors' => $validator->errors(), ], 422); } $sessionId = $request->input('session_id'); $userMessage = trim($request->input('message')); // Get or create conversation $conversation = ChatbotConversation::getOrCreateBySession($sessionId); // Check if conversation is ended if ($conversation->isEnded()) { return response()->json([ 'success' => false, 'message' => 'Esta conversa foi finalizada. Inicie uma nova conversa.', 'conversation_ended' => true, ], 403); } // Save user message ChatbotMessage::create([ 'conversation_id' => $conversation->id, 'role' => 'user', 'content' => $userMessage, ]); // Get conversation context $context = $conversation->getContextForApi(20); // Call the configured AI provider (OpenRouter or llama.cpp) $provider = Setting::get('chatbot_provider', 'openrouter'); if ($provider === 'llamacpp') { $aiService = new LlamaCppService(); } else { $aiService = new OpenRouterService(); } $result = $aiService->chat($context, $conversation); // Save assistant message with token usage ChatbotMessage::create([ 'conversation_id' => $conversation->id, 'role' => 'assistant', 'content' => $result['content'], 'tokens_used' => $result['tokens_used'], ]); return response()->json([ 'success' => true, 'message' => $result['content'], ]); } /** * End a conversation. */ public function endConversation(Request $request): JsonResponse { $validator = Validator::make($request->all(), [ 'session_id' => 'required|string|max:255|regex:/^[a-zA-Z0-9\-_]+$/', ], [ 'session_id.regex' => 'ID de sessão inválido.', ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => 'Sessão inválida.', ], 422); } $sessionId = $request->input('session_id'); $conversation = ChatbotConversation::where('session_id', $sessionId)->first(); if (!$conversation) { return response()->json([ 'success' => false, 'message' => 'Conversa não encontrada.', ], 404); } if ($conversation->isEnded()) { return response()->json([ 'success' => true, 'message' => 'Conversa já foi finalizada.', ]); } $conversation->update([ 'status' => 'ended', 'ended_at' => now(), ]); return response()->json([ 'success' => true, 'message' => 'Conversa finalizada com sucesso.', ]); } /** * Submit a rating for a conversation. */ public function rateConversation(Request $request): JsonResponse { $validator = Validator::make($request->all(), [ 'session_id' => 'required|string|max:255|regex:/^[a-zA-Z0-9\-_]+$/', 'rating' => 'required|integer|min:1|max:5', 'comment' => 'nullable|string|max:500', ], [ 'session_id.regex' => 'ID de sessão inválido.', 'rating.required' => 'Por favor, selecione uma avaliação.', 'rating.min' => 'A avaliação mínima é 1 estrela.', 'rating.max' => 'A avaliação máxima é 5 estrelas.', ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => 'Avaliação inválida.', 'errors' => $validator->errors(), ], 422); } $sessionId = $request->input('session_id'); $conversation = ChatbotConversation::where('session_id', $sessionId)->first(); if (!$conversation) { return response()->json([ 'success' => false, 'message' => 'Conversa não encontrada.', ], 404); } $conversation->update([ 'rating' => $request->input('rating'), 'rating_comment' => $request->input('comment'), ]); return response()->json([ 'success' => true, 'message' => 'Avaliação registrada. Obrigado pelo feedback!', ]); } /** * Get the initial welcome message and chatbot status. */ public function getStatus(): JsonResponse { $enabled = Setting::get('chatbot_enabled', 'off') === 'on'; $welcomeMessage = Setting::get('chatbot_welcome_message', 'Olá! Como posso ajudar você hoje?'); return response()->json([ 'enabled' => $enabled, 'welcome_message' => $welcomeMessage, ]); } }