Files
crm.clientright.ru/iacode15.php

461 lines
20 KiB
PHP
Raw Permalink Normal View History

<?php
// iacode15.php
require_once 'aiassist/config.php';
require_once 'aiassist/logger.php';
require_once 'aiassist/database.php';
require_once 'aiassist/crmHandler.php';
require_once 'aiassist/elastic.php';
require_once 'aiassist/fileHandler.php';
require_once 'aiassist/vectorgpt.php';
require_once 'aiassist/gptAssistant.php';
require_once 'aiassist/search.php';
require_once 'aiassist/utils.php';
// 1. Получение ID кейса
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$id = $_POST['id'] ?? null;
if (!$id) {
$input = json_decode(file_get_contents('php://input'), true);
$id = $input['id'] ?? null;
}
if (!$id || !is_numeric($id)) {
logMessage("Ошибка: Некорректный ID.");
die(json_encode(["status" => "error", "message" => "Некорректный ID."], JSON_UNESCAPED_UNICODE));
}
// 2. Получение документов из CRM
$pdo = getDbConnection();
$documents = fetchDocumentData($pdo, $id);
if (empty($documents)) {
logMessage("Документы не найдены для ID: $id");
die("Документы не найдены для ID: $id");
}
logMessage("✅ Документы получены: " . json_encode($documents, JSON_UNESCAPED_UNICODE));
// Формирование массива путей документов для проверки
$filePathList = array_map(function($doc) {
return $doc['filepath'];
}, $documents);
/*
// 3. Проверка на наличие ранее сохранённого анализа в ElasticSearch
$previousAnalysis = checkPreviousAnalysis($id, $filePathList);
logMessage("DEBUG: Значение предыдущего анализа: " . print_r($previousAnalysis, true));
if ($previousAnalysis) {
logMessage("Найден сохранённый анализ, отправляем его в CRM.");
sendAnalysisToCRM($id, $previousAnalysis);
exit;
} else {
logMessage("Сохранённый анализ не найден, продолжаем обработку.");
}
*/
// 3.5 Создание Vector Store и загрузка файлов
$uploadResult = createVectorStoreAndUploadFiles($filePathList);
if (!$uploadResult) {
logMessage("Ошибка создания Vector Store или загрузки файлов");
die("Ошибка создания Vector Store или загрузки файлов");
}
$vectorStoreId = $uploadResult['vectorStoreId'];
$uploadedFileIds = $uploadResult['fileIds'];
// 4. Формирование предварительного запроса в GPT
// Объединяем текст из документов. Если не удалось извлечь текст (например, для изображений), пробуем OCR.
$combinedContent = analyzeDocuments($documents, $uploadedFileIds); // пробуем новый подход
logMessage("📄 Собранный контент для предварительного запроса:\n" . $combinedContent);
if (empty($combinedContent)) {
logMessage("❌ Ошибка: не удалось извлечь текст из документов.");
die("Ошибка: не удалось извлечь текст из документов.");
}
// Создаем тред для общения с GPT
$threadId = createNewThread();
if (!$threadId) {
logMessage("❌ Ошибка создания треда GPT");
die("Ошибка создания треда");
}
//9.1. тестируем ответ с базой знаний
/*
$knowledgeThreadId = "thread_zYRFzxYn0JTo59VUwz84D9p4"; // `thread_id` базы знаний
$documentThreadId = $threadId; // `thread_id` с новыми документами
$analysisResult2 = analyzeDocumentWithKnowledgeBase($knowledgeThreadId, $documentThreadId);
logMessage( "📌 Анализ нового документа с учетом базы знаний:\n" . $analysisResult2);
//----------------------------------------
*/
/*
// 5⃣ Предварительный анализ через GPT-4
logMessage("📤 Отправляем предварительный запрос в GPT-4 для извлечения ключевых параметров...");
$prelimAnalysis = extractCaseDetailsWithGPT($threadId, ASSISTANT_ID, $vectorStoreId, $combinedContent);
if (!$prelimAnalysis) {
logMessage("❌ Ошибка анализа обращения через GPT-4 (предварительный ответ).");
die("Ошибка анализа обращения через GPT-4 (предварительный ответ).");
}
logMessage("[INFO] ✅ Полученный JSON от GPT-4: " . json_encode($prelimAnalysis, JSON_UNESCAPED_UNICODE));
// Используем результат напрямую как JSON
$jsonData = $prelimAnalysis;
if (!$jsonData) {
logMessage("[ERROR] ❌ Ошибка: JSON от GPT-4 пуст!");
die("Ошибка: JSON от GPT-4 пуст.");
}
// Убираем строки "null" → заменяем на null
foreach (["articles", "claim_amount", "document_client_name"] as $key) {
if (isset($jsonData[$key]) && $jsonData[$key] === "null") {
$jsonData[$key] = null;
}
}
// Проверяем `facts_full` перед векторизацией
if (!isset($jsonData['facts_full']) || empty($jsonData['facts_full'])) {
logMessage("[WARNING] ⚠️ `facts_full` пуст! Устанавливаем значение 'Не указано'.");
$jsonData['facts_full'] = "Не указано";
}
logMessage("🔹 JSON для Elasticsearch (исправленный): " . json_encode($jsonData, JSON_UNESCAPED_UNICODE));
// Получаем векторное представление `facts_full`
$embedding = getTextEmbedding($jsonData['facts_full']);
logMessage("📡 Векторизация facts_full:\n" . json_encode($embedding, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
*/
// 5⃣ Предварительный анализ через GPT-4
logMessage("📤 Отправляем предварительный запрос в GPT-4 для извлечения ключевых параметров...");
$prelimAnalysis = extractCaseDetailsWithGPT($threadId, ASSISTANT_ID, $vectorStoreId, $combinedContent);
if (!$prelimAnalysis) { // ✅ Проверяем, что анализ не пустой
logMessage("❌ Ошибка анализа обращения через GPT-4 (предварительный ответ).");
die("Ошибка анализа обращения через GPT-4 (предварительный ответ).");
}
$parsedJson = [];
if (!empty($prelimAnalysis['json_data'])) {
$parsedJson = $prelimAnalysis['json_data'];
} elseif (!empty($prelimAnalysis['text_data'])) {
$parsedJson = extractCleanJsonFromGPT($prelimAnalysis['text_data']);
}
// ✅ Логируем полный JSON-ответ от GPT-4
logMessage("[INFO] ✅ Полученный JSON от GPT-4: " . json_encode($prelimAnalysis, JSON_UNESCAPED_UNICODE));
// ✅ Проверяем, где находится JSON
$jsonData = isset($prelimAnalysis["json_data"]) && !empty($prelimAnalysis["json_data"])
? $prelimAnalysis["json_data"]
: json_decode($prelimAnalysis["text_data"][0]["text"]["value"], true);
// ✅ Если JSON пуст, выбрасываем ошибку
if (!$jsonData) {
logMessage("[ERROR] ❌ Ошибка: JSON от GPT-4 пуст!");
die("Ошибка: JSON от GPT-4 пуст.");
}
// ✅ Убираем строки `"null"` → заменяем на `null`
foreach (["articles", "claim_amount", "document_client_name"] as $key) {
if (isset($jsonData[$key]) && $jsonData[$key] === "null") {
$jsonData[$key] = null;
}
}
// ✅ Проверяем `facts_full` перед векторизацией
if (!isset($jsonData['facts_full']) || empty($jsonData['facts_full'])) {
logMessage("[WARNING] ⚠️ `facts_full` пуст! Устанавливаем значение 'Не указано'.");
$jsonData['facts_full'] = "Не указано"; // 🔹 Заполняем, чтобы избежать ошибки в векторизаторе
}
// ✅ Логируем, что передаём в векторизатор
logMessage("🔹 JSON для Elasticsearch (исправленный): " . json_encode($jsonData, JSON_UNESCAPED_UNICODE));
// ✅ Получаем векторное представление `facts_full`
$embedding = getTextEmbedding($jsonData['facts_full']);
//logMessage("📡 Векторизация facts_full:\n" . json_encode($embedding, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
// ✅ Проверяем наличие векторов и нормализуем
$normalizedEmbedding1024 = null;
if (isset($embedding["embedding_1024"])) {
$sumSquares = 0;
foreach ($embedding["embedding_1024"] as $x) {
$sumSquares += $x * $x;
}
$magnitude = sqrt($sumSquares);
if ($magnitude > 0) {
$normalizedEmbedding1024 = array_map(function ($x) use ($magnitude) {
return $x / $magnitude;
}, $embedding["embedding_1024"]);
}
}
$normalizedEmbedding2048 = null;
if (isset($embedding["embedding_2048"])) {
$sumSquares = 0;
foreach ($embedding["embedding_2048"] as $x) {
$sumSquares += $x * $x;
}
$magnitude = sqrt($sumSquares);
if ($magnitude > 0) {
$normalizedEmbedding2048 = array_map(function ($x) use ($magnitude) {
return $x / $magnitude;
}, $embedding["embedding_2048"]);
}
}
// ✅ Запускаем поиск, передавая `facts_short` и векторные embeddings
$searchResults = searchSimilarCases([
'category' => $jsonData['category'],
'facts_short' => $jsonData['facts_short'],
'facts_full' => $jsonData['facts_full'],
'embedding_1024' => $normalizedEmbedding1024,
'embedding_2048' => $normalizedEmbedding2048
]);
logMessage("✅ Найденные судебные акты: " . json_encode($searchResults, JSON_UNESCAPED_UNICODE));
//---------------------------------------------------------------------------------------------------------------------------------------
/*
logMessage("📤 Отправляем предварительный запрос в GPT-4 для извлечения ключевых параметров...");
$prelimAnalysis = extractCaseDetailsWithGPT($threadId, ASSISTANT_ID, $vectorStoreId, $combinedContent);
if (!$prelimAnalysis) { // ✅ Теперь проверяем правильную переменную
logMessage("❌ Ошибка анализа обращения через GPT-4 (предварительный ответ).");
die("Ошибка анализа обращения через GPT-4 (предварительный ответ).");
}
function normalizeEmbedding(array $embedding) {
if (empty($embedding)) {
logMessage("Эмбеддинг пустой");
return null;
}
$sumSquares = 0;
foreach ($embedding as $value) {
if (!is_numeric($value)) {
logMessage("Невалидное значение в эмбеддинге: " . print_r($value, true));
return null;
}
$sumSquares += $value * $value;
}
$magnitude = sqrt($sumSquares);
if ($magnitude == 0) {
logMessage("Невозможно нормализовать эмбеддинг: нулевая величина.");
return null;
}
return array_map(function($x) use ($magnitude) {
return $x / $magnitude;
}, $embedding);
}
// ✅ Исправляем имя переменной
$queryParams = $prelimAnalysis["json_data"]; // JSON для поиска и анализа
logMessage("🔹 JSON для Elasticsearch: " . json_encode($queryParams, JSON_UNESCAPED_UNICODE));
// ✅ Проверяем, есть ли `facts_full`
if (!isset($queryParams['facts_full']) || empty($queryParams['facts_full'])) {
logMessage("❌ Ошибка: Пустой текст передан в векторизатор!");
die("Ошибка: `facts_full` отсутствует или пуст.");
}
// ✅ Получаем векторное представление `facts_full`
$embedding = getTextEmbedding($queryParams['facts_full']);
logMessage("📡 Векторизация facts_full:\n" . json_encode($embedding, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
// ✅ Проверяем наличие векторов и нормализуем
$normalizedEmbedding1024 = null;
if (isset($embedding["embedding_1024"])) {
$sumSquares = 0;
foreach ($embedding["embedding_1024"] as $x) {
$sumSquares += $x * $x;
}
$magnitude = sqrt($sumSquares);
if ($magnitude > 0) {
$normalizedEmbedding1024 = array_map(function ($x) use ($magnitude) {
return $x / $magnitude;
}, $embedding["embedding_1024"]);
}
}
$normalizedEmbedding2048 = null;
if (isset($embedding["embedding_2048"])) {
$sumSquares = 0;
foreach ($embedding["embedding_2048"] as $x) {
$sumSquares += $x * $x;
}
$magnitude = sqrt($sumSquares);
if ($magnitude > 0) {
$normalizedEmbedding2048 = array_map(function ($x) use ($magnitude) {
return $x / $magnitude;
}, $embedding["embedding_2048"]);
}
}
// ✅ Запускаем поиск, передавая `facts_short` и векторные embeddings
$searchResults = searchSimilarCases([
'category' => $queryParams['category'],
'facts_short' => $queryParams['facts_short'],
'facts_full' => $queryParams['facts_full'],
'embedding_1024' => $normalizedEmbedding1024,
'embedding_2048' => $normalizedEmbedding2048
]);
logMessage("✅ Найденные судебные акты: " . json_encode($searchResults, JSON_UNESCAPED_UNICODE));
*/
//---------------------------------------------------------------------------------------------------------------------------------//
/*
$embedding = getTextEmbedding($jsonForElastic['facts_full']);
logMessage("📡 вектортут:\n" . json_encode($embedding, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
$normalizedEmbedding1024 = isset($embedding["embedding_1024"]) ? normalizeEmbedding($embedding["embedding_1024"]) : null;
$normalizedEmbedding2048 = isset($embedding["embedding_2048"]) ? normalizeEmbedding($embedding["embedding_2048"]) : null;
logMessage("Нормализованный embedding_1024: " . json_encode($normalizedEmbedding1024, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
logMessage("Нормализованный embedding_2048: " . json_encode($normalizedEmbedding2048, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
// Вызов функции searchSimilarCases
$searchResults = searchSimilarCases([
'category' => $jsonForElastic['category'],
'facts' => $jsonForElastic['facts_short'],
'article' => implode(" ", $jsonForElastic['articles']),
'amount' => $jsonForElastic['claim_amount'],
'embedding_1024'=> $normalizedEmbedding1024,
'embedding_2048'=> $normalizedEmbedding2048
]);
// Логирование результатов
logMessage("Результаты поиска: " . json_encode($searchResults, JSON_UNESCAPED_UNICODE));
*/
//-------------------------------------------------------------------------------------
/*$searchResults = searchSimilarCases([
'category' => $jsonForElastic['category'],
'article' => implode(" ", $jsonForElastic['articles']),
'amount' => $jsonForElastic['claim_amount'],
'facts' => $jsonForElastic['facts'],
'embedding'=> $embedding
]);
*/
//logMessage("✅ Найденные судебные акты: " . json_encode($searchResults, JSON_UNESCAPED_UNICODE));
/*
// 6. Поиск в ElasticSearch судебных актов на основе полученных параметров
$embedding = getTextEmbedding($prelimResponse['facts']);
logMessage("🔍 Полученный эмбеддинг (предварительный, первые 10 значений): " . json_encode(array_slice($embedding["embedding_1024"], 0, 10)));
$searchResults = searchSimilarCases([
'category' => $prelimResponse['category'],
'article' => implode(" ", $prelimResponse['articles']),
'amount' => $prelimResponse['claim_amount'],
'facts' => $prelimResponse['facts'],
'embedding'=> $embedding
]);
logMessage("✅ Найденные судебные акты: " . json_encode($searchResults, JSON_UNESCAPED_UNICODE));
*/
// 7. Формирование финального запроса с добавлением контекста из ElasticSearch ---------------------------------------------------------
// 8. Отправка финального запроса в GPT и получение финального ответа ------------------------------------------------------------------
logMessage("📤 Отправляем финальный запрос в GPT-4...");
// $finalAnalysis = analyzeDocumentWithAssistantStream($threadId, ASSISTANT_ID, $fileIdCombined, $finalPrompt, $searchResults, $prelimResponse);
// $finalAnalysis = analyzeDocumentWithAssistantStream($threadId, ASSISTANT_ID, "", $finalPrompt, $searchResults);
//$finalAnalysis = analyzeDocumentWithAssistantStream($threadId, ASSISTANT_ID, $combinedContent, $finalPrompt, $searchResults);
//logVectorStoreFiles($vectorStoreId);
$finalAnalysis = analyzeDocumentWithAssistantStream($threadId, ASSISTANT_ID, $vectorStoreId, $fileId, $parsedJson, $searchResults, $id);
if (!$finalAnalysis) {
logMessage("❌ Ошибка финального анализа через GPT-4. Сырой ответ:");
logMessage("📜 Сырой ответ GPT-4 (финальный анализ): " . json_encode($finalAnalysis, JSON_UNESCAPED_UNICODE));
die("Ошибка финального анализа через GPT-4.");
}
logMessage("✅ Финальный ответ от GPT-4:\n" . json_encode($finalAnalysis, JSON_UNESCAPED_UNICODE));
// ✅ Проверяем, есть ли `content` в `finalAnalysis`
if (!isset($finalAnalysis['data']) || !is_array($finalAnalysis['data'])) {
logMessage("❌ Ошибка: В `finalAnalysis` нет `data`. Ответ:\n" . json_encode($finalAnalysis, JSON_UNESCAPED_UNICODE));
die("Ошибка в структуре данных от GPT-4.");
}
// ✅ Ищем `content`
$extractedContent = null;
foreach ($finalAnalysis['data'] as $message) {
if ($message['role'] === 'assistant' && isset($message['content']) && is_array($message['content'])) {
foreach ($message['content'] as $contentBlock) {
if ($contentBlock['type'] === 'text' && isset($contentBlock['text']['value'])) {
$extractedContent = trim($contentBlock['text']['value']);
break 2; // Выходим из обоих циклов
}
}
}
}
$saveResult = saveAnalysisToElasticSearch($id, $finalAnalysis, $filePathList);
if ($saveResult) {
logMessage("✅ Анализ успешно сохранён в ElasticSearch.");
} else {
logMessage("❌ Ошибка при сохранении анализа в ElasticSearch.");
}
// ✅ Логируем, что нашли
if ($extractedContent) {
logMessage("✅ Извлечённый `content`: " . substr($extractedContent, 0, 500) . "...");
$finalAnalysis['content'] = $extractedContent;
} else {
logMessage("⚠️ Не удалось извлечь `content`. Используем `анализ_gpt`.");
$finalAnalysis['content'] = "Анализ не выполнен";
}
// ✅ Отправляем исправленный `finalAnalysis` в CRM
sendAnalysisToCRM($id, $finalAnalysis);
logMessage("Обработка кейса завершена.");
exit;
} else {
logMessage("Ошибка: запрос должен быть POST");
die("Ошибка: запрос должен быть POST");
}
?>