Initial implementation of the HomeSysPanel CMS built with Laravel 13.0. Includes complete admin panel, content management, user authentication, modular architecture for products/services/chatbot, and marketing tools. Key features: - User authentication with email verification and password reset - Role-based access control (Admin/User with granular permissions) - Content management (pages, news, FAQ, downloads, galleries, banners) - Contact management system with subjects and responses - Marketing tools (email campaigns, visitor analytics, social sharing) - Modular architecture (Products, Services, Chatbot modules) - AI Chatbot integration with OpenRouter.ai and LlamaCpp support - Visitor tracking with geolocation - SEO optimization with meta tags and Open Graph - Responsive design with Bootstrap 5 - Dark mode support - Maintenance mode - Feature request system
260 lines
8.5 KiB
PHP
Executable File
260 lines
8.5 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Modules\Chatbot\Http\Controllers;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Setting;
|
|
use App\Models\User;
|
|
use App\Modules\Chatbot\Models\ChatbotConversation;
|
|
use App\Modules\Chatbot\Models\ChatbotMessage;
|
|
use App\Modules\Chatbot\Notifications\ChatbotConversationNotification;
|
|
use App\Modules\Chatbot\Services\OpenRouterService;
|
|
use App\Modules\Chatbot\Services\LlamaCppService;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Notification;
|
|
use Illuminate\Support\Facades\Validator;
|
|
|
|
class ChatbotApiController extends Controller
|
|
{
|
|
/**
|
|
* Register visitor information before starting the chat.
|
|
*/
|
|
public function registerVisitor(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(), [
|
|
'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,
|
|
]);
|
|
}
|
|
}
|