Files
bot_palmas/services/AiBot.php
T
2026-06-12 12:18:21 -05:00

156 lines
5.1 KiB
PHP

<?php
declare(strict_types=1);
class AiBot
{
public static function process(array $company, array $context, string $input): ?array
{
$botCtx = ConversationContext::getOrCreate((int)$company['id'], $context['from'], 'ai');
$ctxId = (int)$botCtx['id'];
$config = self::getConfig($company);
$systemPrompt = $config['ai_prompt'] ?? self::defaultPrompt($company);
ConversationContext::addAiMessage($ctxId, ['role' => 'user', 'content' => $input]);
$result = self::callLlm($systemPrompt, $ctxId, $company);
if ($result === null) {
return null;
}
ConversationContext::addAiMessage($ctxId, ['role' => 'assistant', 'content' => $result['content'] ?? '']);
return [
'action' => 'send',
'type' => 'text',
'to' => $context['from'],
'payload' => json_encode(['text' => $result['content'] ?? '']),
];
}
private static function callLlm(string $systemPrompt, int $ctxId, array $company): ?array
{
$provider = env('AI_PROVIDER', 'openai');
$history = ConversationContext::getAiHistory($ctxId);
return match ($provider) {
'openai' => self::callOpenAI($systemPrompt, $history, $company),
'mock' => self::mockResponse($history),
default => self::callOpenAI($systemPrompt, $history, $company),
};
}
private static function callOpenAI(string $systemPrompt, array $history, array $company): ?array
{
$apiKey = env('OPENAI_API_KEY', '');
if ($apiKey === '') {
return null;
}
$model = env('OPENAI_MODEL', 'gpt-4o-mini');
$messages = [
['role' => 'system', 'content' => $systemPrompt],
];
foreach ($history as $msg) {
$messages[] = [
'role' => $msg['role'] ?? 'user',
'content' => $msg['content'] ?? '',
];
}
$payload = json_encode([
'model' => $model,
'messages' => $messages,
'max_tokens' => (int)env('AI_MAX_TOKENS', '500'),
'temperature' => 0.7,
]);
$ch = curl_init('https://api.openai.com/v1/chat/completions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey,
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($httpCode !== 200 || $response === false) {
WpWebhook::log('ERROR', "OpenAI API error: {$error} HTTP:{$httpCode}");
return [
'content' => 'Lo siento, tengo problemas para procesar tu mensaje. Por favor intenta de nuevo más tarde.',
];
}
$data = json_decode($response, true);
$text = $data['choices'][0]['message']['content'] ?? null;
if ($text === null) {
return [
'content' => 'No pude generar una respuesta adecuada. ¿Puedes reformular tu pregunta?',
];
}
return ['content' => $text];
}
private static function mockResponse(array $history): array
{
$last = end($history);
$input = $last['content'] ?? '';
$responses = [
'hola' => '¡Hola! ¿En qué puedo ayudarte hoy?',
'gracias' => '¡De nada! Si necesitas algo más, estoy aquí.',
'adios' => '¡Hasta luego! Que tengas un excelente día.',
'default' => "Gracias por tu mensaje. He recibido: \"{$input}\". Un asesor se pondrá en contacto contigo pronto.",
];
$normalized = mb_strtolower(trim($input));
$found = $responses['default'];
foreach ($responses as $keyword => $response) {
if (str_contains($normalized, $keyword)) {
$found = $response;
break;
}
}
return ['content' => $found];
}
private static function defaultPrompt(array $company): string
{
$name = $company['display_name'] ?? $company['name'] ?? 'la empresa';
return <<<PROMPT
Eres un asistente virtual de {$name}. Tu rol es:
1. Responder preguntas sobre los servicios y productos de {$name}.
2. Ayudar a los clientes con información general.
3. Ser amable, profesional y responder siempre en español.
4. Si no sabes la respuesta, indica que un asesor se comunicará.
5. No inventes información. Si no sabes algo, dilo honestamente.
Mantén las respuestas concisas (máximo 3 párrafos).
PROMPT;
}
private static function getConfig(array $company): array
{
$json = $company['config_json'] ?? '';
if ($json === '') return [];
$config = json_decode($json, true);
return is_array($config) ? $config : [];
}
}