string, 'tokens_used' => int|null] */ public function chat(array $messages, ?ChatbotConversation $conversation = null): array { $apiKey = Setting::get('chatbot_openrouter_api_key'); $model = Setting::get('chatbot_openrouter_model', 'openai/gpt-3.5-turbo'); if (empty($apiKey)) { Log::warning('Chatbot: OpenRouter API key not configured.'); return [ 'content' => 'Desculpe, o assistente virtual não está configurado corretamente. Por favor, entre em contato com a empresa.', 'tokens_used' => null, ]; } $systemPrompt = $this->buildSystemPrompt($conversation); $payload = [ 'model' => $model, 'messages' => array_merge( [['role' => 'system', 'content' => $systemPrompt]], $messages ), 'max_tokens' => (int) Setting::get('chatbot_max_tokens', 500), 'temperature' => (float) Setting::get('chatbot_temperature', 0.7), ]; try { $response = Http::withHeaders([ 'Authorization' => 'Bearer ' . $apiKey, 'Content-Type' => 'application/json', 'HTTP-Referer' => config('app.url'), 'X-Title' => 'SysSiteCMS Chatbot', ])->post('https://openrouter.ai/api/v1/chat/completions', $payload); if ($response->successful()) { $data = $response->json(); $tokensUsed = $data['usage']['total_tokens'] ?? null; // Update cumulative token counter if ($tokensUsed) { $currentTotal = (int) Setting::get('chatbot_total_tokens_used', 0); Setting::set('chatbot_total_tokens_used', $currentTotal + $tokensUsed, 'chatbot'); } return [ 'content' => $data['choices'][0]['message']['content'] ?? 'Desculpe, não consegui processar sua mensagem.', 'tokens_used' => $tokensUsed, ]; } Log::error('Chatbot: OpenRouter API error', [ 'status' => $response->status(), 'body' => $response->body(), ]); return [ 'content' => 'Desculpe, estou com dificuldades para responder no momento. Tente novamente em instantes.', 'tokens_used' => null, ]; } catch (\Exception $e) { Log::error('Chatbot: Exception calling OpenRouter API', [ 'message' => $e->getMessage(), ]); return [ 'content' => 'Desculpe, ocorreu um erro de conexão. Tente novamente em instantes.', 'tokens_used' => null, ]; } } /** * Build the system prompt with company knowledge. */ protected function buildSystemPrompt(?ChatbotConversation $conversation = null): string { $companyName = Setting::get('company_name', 'Nossa Empresa'); $companyEmail = Setting::get('company_email'); $companyPhone = Setting::get('company_phone'); $companyAddress = Setting::get('company_address'); $companyHours = Setting::get('company_hours'); $customInstructions = Setting::get('chatbot_custom_instructions', ''); $prompt = "Você é um assistente virtual de atendimento ao cliente da empresa **{$companyName}**.\n\n"; $prompt .= "## Regras Importantes:\n"; $prompt .= "- Responda APENAS sobre a empresa {$companyName}, seus produtos, serviços e informações relacionadas.\n"; $prompt .= "- Seja sempre educado, profissional e prestativo.\n"; $prompt .= "- Responda em português do Brasil.\n"; $prompt .= "- Se não souber a resposta, diga que não possui essa informação e sugira entrar em contato pelo telefone ou e-mail da empresa.\n"; $prompt .= "- NUNCA invente informações que não foram fornecidas na base de conhecimento.\n"; $prompt .= "- NUNCA forneça informações sobre concorrentes ou outras empresas.\n"; $prompt .= "- NUNCA recomende ou sugira que o visitante faça pesquisas na internet (ex: \"pesquise no Google\", \"busque online\", \"procure no site\", \"acesse o link\", etc.). Toda informação deve ser fornecida diretamente por você com base exclusivamente no conteúdo da empresa {$companyName}.\n"; $prompt .= "- NUNCA forneça links, URLs ou endereços de sites externos, redes sociais ou buscadores. Utilize apenas os canais de contato oficiais da empresa (telefone, e-mail, WhatsApp ou endereço físico) listados abaixo.\n"; $prompt .= "- NUNCA diga frases como \"você pode pesquisar\", \"procure saber\", \"verifique na internet\", \"consulte online\" ou qualquer variação que incentive o visitante a buscar informação fora deste chat.\n"; $prompt .= "- Mantenha as respostas concisas e objetivas.\n\n"; if ($companyEmail) { $prompt .= "- E-mail de contato: {$companyEmail}\n"; } if ($companyPhone) { $prompt .= "- Telefone de contato: {$companyPhone}\n"; } if ($companyAddress) { $prompt .= "- Endereço: {$companyAddress}\n"; } if ($companyHours) { $prompt .= "- Horário de funcionamento: {$companyHours}\n"; } $prompt .= "\n"; // Add visitor info if available if ($conversation && $conversation->visitor_name) { $prompt .= "## Dados do Visitante:\n"; $prompt .= "- **Nome**: {$conversation->visitor_name}\n"; if ($conversation->visitor_phone) { $prompt .= "- **Telefone**: {$conversation->visitor_phone}\n"; } if ($conversation->visitor_city) { $prompt .= "- **Cidade**: {$conversation->visitor_city}\n"; } $prompt .= "\nSempre cumprimente o visitante pelo nome e personalize o atendimento.\n"; $prompt .= "\n"; } // Add knowledge base entries $knowledge = ChatbotKnowledge::getFormattedKnowledge(); if ($knowledge) { $prompt .= "## Base de Conhecimento da Empresa:\n"; $prompt .= $knowledge; } // Add configurable AI rules (admin-defined behavior constraints) $rules = ChatbotRule::getFormattedRules(); if ($rules) { $prompt .= "\n## Regras Obrigatórias de Comportamento:\n"; $prompt .= "As regras abaixo foram definidas pela administração e DEVEM ser seguidas rigorosamente em TODAS as respostas:\n"; $prompt .= $rules . "\n"; } // Add custom instructions if ($customInstructions) { $prompt .= "\n## Instruções Adicionais:\n{$customInstructions}\n"; } return $prompt; } }