Files
crm.clientright.ru/aiassist/n8n_proxy.php
Fedor 1a4653298d Реализован SSE + Redis Pub/Sub для AI Drawer
- Добавлен SSE endpoint (aiassist/ai_sse.php) для real-time получения ответов от n8n
- Обновлен n8n_proxy.php: убран callback, добавлена передача Redis параметров в n8n
- Обновлен ai-drawer-simple.js: переход с polling на SSE с fallback через Redis
- Добавлен check_redis_response.php для прямого чтения из Redis кэша
- Добавлена документация: N8N_REDIS_SETUP.md, N8N_REDIS_FIX.md, AI_DRAWER_REDIS_SSE.md
- Поддержка plain text ответов от n8n (автоматическое определение формата)
- Кэширование ответов в Redis для надежности (TTL 5 минут)
2025-11-11 15:16:27 +03:00

116 lines
3.9 KiB
PHP

<?php
// aiassist/n8n_proxy.php
// Proxy между AI Drawer и n8n
// n8n обрабатывает запрос и публикует ответ напрямую в Redis
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit();
}
error_reporting(E_ALL);
ini_set('display_errors', 1);
if (!function_exists('curl_init')) {
http_response_code(500);
echo json_encode(['error' => 'cURL not available']);
exit();
}
try {
$input = json_decode(file_get_contents('php://input'), true);
if (!$input) {
throw new Exception('Invalid JSON input');
}
$message = $input['message'] ?? '';
$context = $input['context'] ?? [];
$sessionId = $input['sessionId'] ?? 'crm-session-' . time();
// Генерируем уникальный task_id
$taskId = 'task-' . uniqid() . '-' . time();
error_log("N8N Proxy: New task {$taskId} for session {$sessionId}");
// Отправляем запрос в n8n
// n8n обработает и опубликует ответ напрямую в Redis: ai:response:{taskId}
$n8nWebhookUrl = 'https://n8n.clientright.pro/webhook/0b20bf1e-7cda-4dc8-899e-a7c3be4096c0';
$payload = [
'message' => $message,
'context' => $context,
'sessionId' => $sessionId,
'taskId' => $taskId,
'redisChannel' => "ai:response:{$taskId}", // Канал для публикации ответа
'redisHost' => 'crm.clientright.ru',
'redisPort' => 6379,
'redisPassword' => 'CRM_Redis_Pass_2025_Secure!',
'timestamp' => date('Y-m-d H:i:s'),
'source' => 'crm-client'
];
error_log("N8N Proxy: Sending to n8n - Task: {$taskId}, Redis channel: ai:response:{$taskId}");
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $n8nWebhookUrl,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'User-Agent: CRM-N8N-Integration/1.0'
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_FOLLOWLOCATION => true
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
error_log("N8N Proxy: cURL error for task {$taskId}: {$error}");
} else {
error_log("N8N Proxy: Task {$taskId} sent to n8n, HTTP code: {$httpCode}");
}
// Возвращаем task_id клиенту
// Клиент подпишется на SSE и получит ответ когда n8n опубликует в Redis
echo json_encode([
'success' => true,
'task_id' => $taskId,
'status' => 'accepted',
'message' => 'Запрос принят в обработку',
'redisChannel' => "ai:response:{$taskId}" // Для информации
]);
} catch (Exception $e) {
$errorMessage = "N8N Proxy Error: " . $e->getMessage();
error_log($errorMessage);
$logEntry = [
'timestamp' => date('Y-m-d H:i:s'),
'error' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString()
];
file_put_contents('/var/www/fastuser/data/www/crm.clientright.ru/logs/n8n_proxy_errors.log', json_encode($logEntry, JSON_UNESCAPED_UNICODE) . "\n", FILE_APPEND | LOCK_EX);
http_response_code(500);
echo json_encode([
'error' => $e->getMessage(),
'fallback' => true,
'timestamp' => date('Y-m-d H:i:s')
]);
}
?>