249 lines
12 KiB
PHP
249 lines
12 KiB
PHP
|
|
<?php
|
|||
|
|
define('LOG_FILE', 'logs/CheckPDF01.log');
|
|||
|
|
define('OPENAI_API_KEY', 'sk-GS24OxHQYfq8ErW5CRLoN5F1CfJPxNsY');
|
|||
|
|
define('OPENAI_API_URL', 'https://api.proxyapi.ru/openai/v1/chat/completions');
|
|||
|
|
|
|||
|
|
// 🔹 Функция логирования
|
|||
|
|
function logMessage($message) {
|
|||
|
|
file_put_contents(LOG_FILE, date('Y-m-d H:i:s') . " - " . $message . "\n", FILE_APPEND);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 🔹 Подключение к БД
|
|||
|
|
$dbconfig = [
|
|||
|
|
'db_server' => 'localhost',
|
|||
|
|
'db_port' => '3306',
|
|||
|
|
'db_username' => 'ci20465_72new',
|
|||
|
|
'db_password' => 'EcY979Rn',
|
|||
|
|
'db_name' => 'ci20465_72new',
|
|||
|
|
'db_type' => 'mysqli'
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
$conn = new mysqli(
|
|||
|
|
$dbconfig['db_server'],
|
|||
|
|
$dbconfig['db_username'],
|
|||
|
|
$dbconfig['db_password'],
|
|||
|
|
$dbconfig['db_name'],
|
|||
|
|
$dbconfig['db_port']
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
if ($conn->connect_error) {
|
|||
|
|
logMessage("Ошибка подключения к БД: " . $conn->connect_error);
|
|||
|
|
die(json_encode(["status" => "error", "message" => "Ошибка подключения к БД."]));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Устанавливаем кодировку UTF-8
|
|||
|
|
$conn->set_charset("utf8mb4");
|
|||
|
|
|
|||
|
|
// ✅ Получаем `$id` из POST-запроса
|
|||
|
|
$id = $_POST['id'] ?? null;
|
|||
|
|
if (!$id || !is_numeric($id)) {
|
|||
|
|
logMessage("Ошибка: Некорректный ID.");
|
|||
|
|
die(json_encode(["status" => "error", "message" => "Некорректный ID."]));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
logMessage("Получен ID: $id");
|
|||
|
|
|
|||
|
|
// 🔹 SQL-запрос для получения файлов
|
|||
|
|
$sql = "
|
|||
|
|
SELECT n.title,
|
|||
|
|
CASE WHEN a.storedname IS NOT NULL
|
|||
|
|
THEN CONCAT(a.path, a.attachmentsid, '_', a.storedname)
|
|||
|
|
ELSE CONCAT(a.path, a.attachmentsid, '_', a.name)
|
|||
|
|
END AS filepath
|
|||
|
|
FROM vtiger_senotesrel r
|
|||
|
|
LEFT JOIN vtiger_notes n ON n.notesid = r.notesid
|
|||
|
|
LEFT JOIN vtiger_crmentity e ON e.crmid = r.notesid
|
|||
|
|
LEFT JOIN vtiger_seattachmentsrel r2 ON r2.crmid = r.notesid
|
|||
|
|
LEFT JOIN vtiger_attachments a ON a.attachmentsid = r2.attachmentsid
|
|||
|
|
WHERE r.crmid = ? AND e.deleted = 0
|
|||
|
|
AND (a.type = 'application/pdf' OR a.type = 'application/octet-stream')
|
|||
|
|
";
|
|||
|
|
|
|||
|
|
$stmt = $conn->prepare($sql);
|
|||
|
|
$stmt->bind_param("i", $id);
|
|||
|
|
$stmt->execute();
|
|||
|
|
$result = $stmt->get_result();
|
|||
|
|
|
|||
|
|
if ($result->num_rows == 0) {
|
|||
|
|
logMessage("Ошибка: Данные не найдены в БД.");
|
|||
|
|
die(json_encode(["status" => "error", "message" => "Нет данных."]));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 🔹 Функция временного переименования файла
|
|||
|
|
function renameFileForProcessing($filePath) {
|
|||
|
|
$pathInfo = pathinfo($filePath);
|
|||
|
|
$newName = "file_" . uniqid() . "." . $pathInfo['extension'];
|
|||
|
|
$newPath = $pathInfo['dirname'] . "/" . $newName;
|
|||
|
|
|
|||
|
|
if (rename($filePath, $newPath)) {
|
|||
|
|
logMessage("Файл переименован: $filePath -> $newPath");
|
|||
|
|
return $newPath;
|
|||
|
|
} else {
|
|||
|
|
logMessage("Ошибка при переименовании файла: $filePath");
|
|||
|
|
return $filePath;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 🔹 Функция восстановления оригинального имени файла
|
|||
|
|
function restoreOriginalFileName($originalPath, $tempPath) {
|
|||
|
|
if (rename($tempPath, $originalPath)) {
|
|||
|
|
logMessage("Файл восстановлен: $tempPath -> $originalPath");
|
|||
|
|
} else {
|
|||
|
|
logMessage("Ошибка при восстановлении имени файла: $tempPath");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 🔹 Функция анализа текста через GPT-4-Turbo
|
|||
|
|
function analyzeDocumentsWithGPT($documents) {
|
|||
|
|
logMessage("Отправка запроса в GPT-4-Turbo...");
|
|||
|
|
$task = "🔹 Отвечай по шаблону. **Задача**:
|
|||
|
|
Проанализируй загруженные документы, выполнив следующие действия:
|
|||
|
|
|
|||
|
|
1️⃣ **Список файлов и проверка соответствия названий**
|
|||
|
|
- Перечисли все загруженные файлы.
|
|||
|
|
- Определи их содержимое (например, \"договор\", \"претензия\", \"ответ на претензию\", \"подтверждение оплаты\" и т. д.).
|
|||
|
|
- Проверь, соответствует ли название файла его реальному содержимому.
|
|||
|
|
- Если обнаружено несоответствие, укажи, в чем именно проблема.
|
|||
|
|
|
|||
|
|
2️⃣ **Краткий анализ спора**
|
|||
|
|
- Определи **истца** (потребителя) и **ответчика** (компанию, на которую подана жалоба).
|
|||
|
|
- Опиши **суть спора** (что произошло и какая проблема заявлена).
|
|||
|
|
- Укажи **основные аргументы сторон** (что заявляет потребитель и какие возражения возможны у компании).
|
|||
|
|
|
|||
|
|
3️⃣ **Проверка на цензуру**
|
|||
|
|
- Проверь документы на наличие **ненормативной лексики** и **нецензурных изображений**.
|
|||
|
|
- Если обнаружены изображения, укажи, требуется ли их ручная проверка.
|
|||
|
|
|
|||
|
|
4️⃣ **Выдача итогового вердикта**
|
|||
|
|
- **Прошло модерацию** – если всё соответствует названию и нет проблем.
|
|||
|
|
- **Не прошло модерацию (требуется участие человека)** – если есть несоответствия или потенциальные проблемы (укажи, что именно требует ручной проверки).
|
|||
|
|
|
|||
|
|
5️⃣ **Характер спора**
|
|||
|
|
- Дай краткую характеристику дела (например, \"некачественный товар\", \"товар не привезли\", \"не возвращают деньги\", \"некачественная услуга\" и т. д.).
|
|||
|
|
|
|||
|
|
📌 **Важно**:
|
|||
|
|
Отчет должен быть структурированным, четким и лаконичным. Укажи, какими нормами права РФ будет регулироваться рассмотение данного спора. Если требуется ручная проверка, укажи приоритетные файлы для проверки.";
|
|||
|
|
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
$task = "🔹 **Анализ загруженных документов**:\n"
|
|||
|
|
. "1️⃣ Перечисли все загруженные файлы и проверь соответствие названий.\n"
|
|||
|
|
. "2️⃣ Определи истца и ответчика (если применимо).\n"
|
|||
|
|
. "3️⃣ Опиши суть спора и возможные аргументы сторон.\n"
|
|||
|
|
. "4️⃣ Проверь на нецензурную лексику и изображения.\n"
|
|||
|
|
. "5️⃣ Дай итоговый вердикт ('Прошло модерацию' или 'Требуется проверка').";
|
|||
|
|
*/
|
|||
|
|
$body = json_encode([
|
|||
|
|
// "model" => "o1-mini",
|
|||
|
|
"model" => "gpt-4-turbo",
|
|||
|
|
"messages" => [
|
|||
|
|
["role" => "system", "content" => "Ты юридический аналитик. Анализируй документы согласно задаче."],
|
|||
|
|
["role" => "user", "content" => $task],
|
|||
|
|
["role" => "user", "content" => json_encode($documents, JSON_UNESCAPED_UNICODE)]
|
|||
|
|
],
|
|||
|
|
"max_completion_tokens" => 4000
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
logMessage("Запрос к GPT-4-Turbo: " . substr($body, 0, 1000));
|
|||
|
|
|
|||
|
|
$curl = curl_init();
|
|||
|
|
curl_setopt_array($curl, [
|
|||
|
|
CURLOPT_URL => OPENAI_API_URL,
|
|||
|
|
CURLOPT_RETURNTRANSFER => true,
|
|||
|
|
CURLOPT_POST => true,
|
|||
|
|
CURLOPT_POSTFIELDS => $body,
|
|||
|
|
CURLOPT_HTTPHEADER => [
|
|||
|
|
'Content-Type: application/json',
|
|||
|
|
'Authorization: Bearer ' . OPENAI_API_KEY
|
|||
|
|
]
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$response = curl_exec($curl);
|
|||
|
|
curl_close($curl);
|
|||
|
|
|
|||
|
|
return json_decode($response, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 🔹 Обработка всех файлов
|
|||
|
|
$files_data = [];
|
|||
|
|
while ($row = $result->fetch_assoc()) {
|
|||
|
|
$title = $row["title"];
|
|||
|
|
$filePath = $row["filepath"];
|
|||
|
|
|
|||
|
|
logMessage("Обрабатываем файл: " . $filePath);
|
|||
|
|
|
|||
|
|
if (!file_exists($filePath)) {
|
|||
|
|
logMessage("Ошибка: Файл $filePath не найден.");
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 🔹 Временно переименовываем файл
|
|||
|
|
$tempFilePath = renameFileForProcessing($filePath);
|
|||
|
|
|
|||
|
|
// 🔹 Извлекаем текст из PDF
|
|||
|
|
$pdfText = shell_exec("pdftotext -layout -enc UTF-8 " . escapeshellarg($tempFilePath) . " -");
|
|||
|
|
|
|||
|
|
if (empty(trim($pdfText))) {
|
|||
|
|
logMessage("Файл $tempFilePath содержит только изображения или пуст. Запускаем OCR...");
|
|||
|
|
$pdfText = shell_exec("tesseract " . escapeshellarg($tempFilePath) . " stdout -l rus+eng");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (empty(trim($pdfText))) {
|
|||
|
|
logMessage("OCR не смог извлечь текст из $tempFilePath.");
|
|||
|
|
restoreOriginalFileName($filePath, $tempFilePath);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 🔹 Добавляем в список для анализа
|
|||
|
|
$files_data[] = ["title" => $title, "text" => $pdfText];
|
|||
|
|
restoreOriginalFileName($filePath, $tempFilePath);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 🔹 Отправка всех файлов в GPT
|
|||
|
|
$gptAnalysis = analyzeDocumentsWithGPT($files_data);
|
|||
|
|
logMessage("Ответ от GPT-4-Turbo: " . json_encode($gptAnalysis, JSON_UNESCAPED_UNICODE));
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Логируем JSON-ответ перед отправкой в CRM
|
|||
|
|
//logMessage("JSON-ответ в CRM: " . json_encode(["status" => "complete", "content" => $gptAnalysis['choices'][0]['message']['content']], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
|||
|
|
|
|||
|
|
logMessage("Полный JSON-ответ от GPT: " . json_encode($gptAnalysis, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
|||
|
|
|
|||
|
|
// Проверяем, является ли $gptAnalysis строкой JSON или массивом
|
|||
|
|
if (!is_string($gptAnalysis)) {
|
|||
|
|
logMessage("DEBUG: GPT-ответ уже является массивом.");
|
|||
|
|
$gptResponse = $gptAnalysis;
|
|||
|
|
} else {
|
|||
|
|
logMessage("DEBUG: Декодируем JSON-ответ от GPT.");
|
|||
|
|
$gptResponse = json_decode($gptAnalysis, true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Проверяем, корректно ли распарсился JSON
|
|||
|
|
if (!is_array($gptResponse)) {
|
|||
|
|
logMessage("Ошибка: JSON-декодирование не удалось.");
|
|||
|
|
die(json_encode(["status" => "error", "message" => "Ошибка: JSON-декодирование не удалось."]));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Проверяем, есть ли ключ 'choices'
|
|||
|
|
if (!isset($gptResponse['choices']) || empty($gptResponse['choices'])) {
|
|||
|
|
logMessage("Ошибка: в JSON-ответе отсутствует ключ 'choices'.");
|
|||
|
|
die(json_encode(["status" => "error", "message" => "Ошибка: в JSON-ответе отсутствует ключ 'choices'."]));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Получаем контент
|
|||
|
|
$content = $gptResponse['choices'][0]['message']['content'] ?? null;
|
|||
|
|
|
|||
|
|
if (!$content) {
|
|||
|
|
logMessage("Ошибка: контент не найден в ответе от GPT.");
|
|||
|
|
die(json_encode(["status" => "error", "message" => "Ошибка: контент не найден в ответе от GPT."]));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
logMessage("DEBUG: Извлеченный контент: " . $content);
|
|||
|
|
|
|||
|
|
// Возвращаем JSON с контентом
|
|||
|
|
echo json_encode(["status" => "complete", "content" => $content], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
|||
|
|
|
|||
|
|
//echo $content;
|
|||
|
|
|
|||
|
|
?>
|