331 lines
12 KiB
PHP
331 lines
12 KiB
PHP
|
|
<?php
|
|||
|
|
if (!defined('ELASTIC_URL')) {
|
|||
|
|
define('ELASTIC_URL', 'http://localhost:9200');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ Проверка истории анализа в ElasticSearch
|
|||
|
|
/*function checkPreviousAnalysis($caseId, $fileList) {
|
|||
|
|
$es_url = ELASTIC_URL . "/cases/_search";
|
|||
|
|
$query = [
|
|||
|
|
"query" => ["match" => ["case_id" => $caseId]]
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
$ch = curl_init($es_url);
|
|||
|
|
curl_setopt_array($ch, [
|
|||
|
|
CURLOPT_RETURNTRANSFER => true,
|
|||
|
|
CURLOPT_POST => true,
|
|||
|
|
CURLOPT_POSTFIELDS => json_encode($query),
|
|||
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json']
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$response = curl_exec($ch);
|
|||
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|||
|
|
curl_close($ch);
|
|||
|
|
|
|||
|
|
if ($httpCode !== 200) {
|
|||
|
|
logMessage("Ошибка ElasticSearch: HTTP $httpCode - " . $response);
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
logMessage("ElasticSearch (проверка истории): " . $response);
|
|||
|
|
$data = json_decode($response, true);
|
|||
|
|
|
|||
|
|
if (!isset($data["hits"]["total"]["value"])) {
|
|||
|
|
logMessage("Неверная структура ответа от ElasticSearch: " . json_encode($data));
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ($data["hits"]["total"]["value"] > 0) {
|
|||
|
|
$previousCase = $data["hits"]["hits"][0]["_source"];
|
|||
|
|
$previousHashes = array_column($previousCase["файлы"], "checksum");
|
|||
|
|
|
|||
|
|
$currentHashes = array_map(function($file) {
|
|||
|
|
if (is_string($file) && file_exists($file)) {
|
|||
|
|
return hash_file('sha256', $file);
|
|||
|
|
}
|
|||
|
|
logMessage("Ошибка: hash_file получил некорректный путь: " . json_encode($file));
|
|||
|
|
return null;
|
|||
|
|
}, $fileList);
|
|||
|
|
|
|||
|
|
// Используем diff для сравнения хешей
|
|||
|
|
if (count(array_diff($previousHashes, $currentHashes)) === 0) {
|
|||
|
|
logMessage("✅ Файлы не изменились, используем старый результат.");
|
|||
|
|
return $previousCase;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
*/
|
|||
|
|
function checkPreviousAnalysis($caseId, $fileList) {
|
|||
|
|
$es_url = ELASTIC_URL . "/cases/_search";
|
|||
|
|
$query = [
|
|||
|
|
"query" => ["match" => ["case_id" => $caseId]]
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
$ch = curl_init($es_url);
|
|||
|
|
curl_setopt_array($ch, [
|
|||
|
|
CURLOPT_RETURNTRANSFER => true,
|
|||
|
|
CURLOPT_POST => true,
|
|||
|
|
CURLOPT_POSTFIELDS => json_encode($query),
|
|||
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json']
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$response = curl_exec($ch);
|
|||
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|||
|
|
curl_close($ch);
|
|||
|
|
|
|||
|
|
if ($httpCode !== 200) {
|
|||
|
|
logMessage("Ошибка ElasticSearch: HTTP $httpCode - " . $response);
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
logMessage("ElasticSearch (проверка истории): " . $response);
|
|||
|
|
$data = json_decode($response, true);
|
|||
|
|
|
|||
|
|
// Проверяем, корректен ли ответ
|
|||
|
|
if (!isset($data["hits"]["total"]["value"])) {
|
|||
|
|
logMessage("Неверная структура ответа от ElasticSearch: " . json_encode($data));
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Если запись найдена, достаём checksum
|
|||
|
|
if ($data["hits"]["total"]["value"] > 0) {
|
|||
|
|
$previousCase = $data["hits"]["hits"][0]["_source"];
|
|||
|
|
|
|||
|
|
// Старые хэши
|
|||
|
|
$previousHashes = array_column($previousCase["файлы"], "checksum");
|
|||
|
|
sort($previousHashes);
|
|||
|
|
|
|||
|
|
// Текущие хэши
|
|||
|
|
$currentHashes = [];
|
|||
|
|
foreach ($fileList as $file) {
|
|||
|
|
if (is_string($file) && file_exists($file)) {
|
|||
|
|
$currentHashes[] = hash_file('sha256', $file);
|
|||
|
|
} else {
|
|||
|
|
logMessage("Ошибка: hash_file получил некорректный путь: " . json_encode($file));
|
|||
|
|
// Можем решить, как обрабатывать ситуацию — например, return null
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
sort($currentHashes);
|
|||
|
|
|
|||
|
|
// Сравниваем отсортированные массивы
|
|||
|
|
if ($previousHashes === $currentHashes) {
|
|||
|
|
logMessage("✅ Файлы не изменились, используем старый результат.");
|
|||
|
|
return $previousCase;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// ✅ Сохранение анализа в ElasticSearch (для индекса cases)
|
|||
|
|
function saveAnalysisToElasticSearch($caseId, $analysis, $fileList) {
|
|||
|
|
if (!is_array($fileList) || empty($fileList)) {
|
|||
|
|
logMessage("❌ Ошибка: передан пустой или некорректный массив файлов в saveAnalysisToElasticSearch.");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ Проверяем, нет ли уже идентичного анализа в ElasticSearch
|
|||
|
|
$existingAnalysis = checkPreviousAnalysis($caseId, $fileList);
|
|||
|
|
if ($existingAnalysis) {
|
|||
|
|
logMessage("✅ Анализ уже существует в базе. Повторная запись не требуется.");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$es_url = ELASTIC_URL . "/cases/_doc/$caseId";
|
|||
|
|
|
|||
|
|
// Извлекаем детали кейса из содержания анализа с помощью функции extractCaseDetails()
|
|||
|
|
$caseDetails = extractCaseDetails($analysis['content'] ?? '');
|
|||
|
|
|
|||
|
|
$payload = [
|
|||
|
|
"case_id" => $caseId,
|
|||
|
|
"истец" => $caseDetails['истец'] ?? 'Не определено',
|
|||
|
|
"ответчик" => $caseDetails['ответчик'] ?? 'Не определено',
|
|||
|
|
"суть_спора" => $caseDetails['суть_спора'] ?? 'Не определено',
|
|||
|
|
"анализ_gpt" => isset($analysis['content']) ? $analysis['content'] : 'Анализ не выполнен',
|
|||
|
|
"вывод_gpt" => isset($analysis['moderationVerdict']) ? $analysis['moderationVerdict'] : 'Не определен',
|
|||
|
|
"дата" => date('c'),
|
|||
|
|
"файлы" => array_map(function($file) {
|
|||
|
|
if (is_string($file) && file_exists($file)) {
|
|||
|
|
return [
|
|||
|
|
"filename" => basename($file),
|
|||
|
|
"checksum" => hash_file('sha256', $file)
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
logMessage("Ошибка: hash_file получил некорректный путь: " . json_encode($file));
|
|||
|
|
return [
|
|||
|
|
"filename" => "Неизвестно",
|
|||
|
|
"checksum" => null
|
|||
|
|
];
|
|||
|
|
}, $fileList)
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
$ch = curl_init($es_url);
|
|||
|
|
curl_setopt_array($ch, [
|
|||
|
|
CURLOPT_RETURNTRANSFER => true,
|
|||
|
|
CURLOPT_CUSTOMREQUEST => "PUT",
|
|||
|
|
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
|
|||
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json']
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$response = curl_exec($ch);
|
|||
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|||
|
|
$curlError = curl_error($ch);
|
|||
|
|
curl_close($ch);
|
|||
|
|
|
|||
|
|
if ($curlError) {
|
|||
|
|
logMessage("❌ Ошибка cURL при сохранении анализа в ElasticSearch: " . $curlError);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ($httpCode !== 200 && $httpCode !== 201) {
|
|||
|
|
logMessage("❌ Ошибка ElasticSearch: HTTP $httpCode - " . $response);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
logMessage("✅ ElasticSearch (анализ сохранён): " . $response);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ Функция сохранения судебных решений в отдельный индекс (court_decisions)
|
|||
|
|
function saveCourtDecisionToElastic($caseId, $filename, $content) {
|
|||
|
|
$es_url = ELASTIC_URL . "/court_decisions/_doc/";
|
|||
|
|
// Формируем уникальный ID на основе md5 от caseId и filename
|
|||
|
|
$docId = md5($caseId . $filename);
|
|||
|
|
|
|||
|
|
$payload = [
|
|||
|
|
"case_id" => $caseId,
|
|||
|
|
"filename" => $filename,
|
|||
|
|
"text" => $content,
|
|||
|
|
"created_at"=> date('c')
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
$ch = curl_init($es_url . $docId);
|
|||
|
|
curl_setopt_array($ch, [
|
|||
|
|
CURLOPT_RETURNTRANSFER => true,
|
|||
|
|
CURLOPT_CUSTOMREQUEST => "PUT",
|
|||
|
|
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
|
|||
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json']
|
|||
|
|
]);
|
|||
|
|
$response = curl_exec($ch);
|
|||
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|||
|
|
$curlError = curl_error($ch);
|
|||
|
|
curl_close($ch);
|
|||
|
|
|
|||
|
|
if ($curlError) {
|
|||
|
|
logMessage("Ошибка cURL при сохранении судебного решения: " . $curlError);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
if ($httpCode !== 200 && $httpCode !== 201) {
|
|||
|
|
logMessage("❌ Ошибка ElasticSearch при сохранении судебного решения: HTTP $httpCode - " . $response);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
logMessage("✅ Судебное решение сохранено в ElasticSearch: " . $response);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ Проверка истории запросов (чтобы не отправлять дубликаты)
|
|||
|
|
function checkQueryHistory($caseId, $queryText) {
|
|||
|
|
$es_url = ELASTIC_URL . "/query_history/_search";
|
|||
|
|
$query = [
|
|||
|
|
"query" => ["match" => ["case_id" => $caseId]]
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
$ch = curl_init($es_url);
|
|||
|
|
curl_setopt_array($ch, [
|
|||
|
|
CURLOPT_RETURNTRANSFER => true,
|
|||
|
|
CURLOPT_POST => true,
|
|||
|
|
CURLOPT_POSTFIELDS => json_encode($query),
|
|||
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json']
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$response = curl_exec($ch);
|
|||
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|||
|
|
curl_close($ch);
|
|||
|
|
|
|||
|
|
if ($httpCode !== 200) {
|
|||
|
|
logMessage("Ошибка ElasticSearch: HTTP $httpCode - " . $response);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
logMessage("ElasticSearch (проверка истории запросов): " . $response);
|
|||
|
|
$data = json_decode($response, true);
|
|||
|
|
|
|||
|
|
if (!isset($data["hits"]["total"]["value"])) {
|
|||
|
|
logMessage("Неверная структура ответа от ElasticSearch: " . json_encode($data));
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ($data["hits"]["total"]["value"] > 0) {
|
|||
|
|
foreach ($data["hits"]["hits"] as $entry) {
|
|||
|
|
if ($entry["_source"]["query_text"] === $queryText) {
|
|||
|
|
logMessage("✅ Запрос уже выполнялся ранее, повторная отправка не требуется.");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ✅ Сохранение истории запроса
|
|||
|
|
function saveQueryToHistory($caseId, $queryText) {
|
|||
|
|
$es_url = ELASTIC_URL . "/query_history/_doc/";
|
|||
|
|
|
|||
|
|
$payload = [
|
|||
|
|
"case_id" => $caseId,
|
|||
|
|
"query_text" => $queryText,
|
|||
|
|
"дата" => date("Y-m-d H:i:s")
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
$ch = curl_init($es_url);
|
|||
|
|
curl_setopt_array($ch, [
|
|||
|
|
CURLOPT_RETURNTRANSFER => true,
|
|||
|
|
CURLOPT_CUSTOMREQUEST => "POST",
|
|||
|
|
CURLOPT_POSTFIELDS => json_encode($payload),
|
|||
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json']
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$response = curl_exec($ch);
|
|||
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|||
|
|
curl_close($ch);
|
|||
|
|
|
|||
|
|
if ($httpCode !== 200 && $httpCode !== 201) {
|
|||
|
|
logMessage("Ошибка ElasticSearch: HTTP $httpCode - " . $response);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
logMessage("ElasticSearch (сохранение истории запроса): " . $response);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Парсинг данных из текста анализа
|
|||
|
|
function extractCaseDetails($analysisText) {
|
|||
|
|
$details = [
|
|||
|
|
'истец' => 'Не определено',
|
|||
|
|
'ответчик' => 'Не определено',
|
|||
|
|
'суть_спора' => 'Не определено'
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// Используем модификаторы m (многострочный) и u (Unicode)
|
|||
|
|
// Парсим истца (например: "• Истец (потребитель): Гражданин Городничев И.А.")
|
|||
|
|
if (preg_match('/•\s*Истец\s*\(потребитель\):\s*(.+)/mu', $analysisText, $matches)) {
|
|||
|
|
$details['истец'] = trim($matches[1]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Парсим ответчика, учитывая варианты "компания" или "организация"
|
|||
|
|
if (preg_match('/•\s*Ответчик\s*\((?:компания|организация)\):\s*(.+)/mu', $analysisText, $matches)) {
|
|||
|
|
$details['ответчик'] = trim($matches[1]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Парсим суть или характер спора (приоритет: если есть "Суть спора", иначе "Характер спора")
|
|||
|
|
if (preg_match('/•\s*(?:Суть|Характер)\s+спора:\s*(.+)/mu', $analysisText, $matches)) {
|
|||
|
|
$details['суть_спора'] = trim($matches[1]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return $details;
|
|||
|
|
}
|
|||
|
|
?>
|