$newPath"); return $newPath; } else { logMessage("Ошибка при копировании файла: $filePath"); return null; } } function extractTextFromPDF($pdfPath) { $text = shell_exec("pdftotext -layout -enc UTF-8 " . escapeshellarg($pdfPath) . " -"); $text = mb_convert_encoding($text, 'UTF-8', 'auto'); logMessage("DEBUG: Извлеченный текст: " . substr($text, 0, 500)); return trim($text); } function convertPdfToImages($pdfPath, $outputDir) { if (!file_exists($outputDir)) { mkdir($outputDir, 0777, true); logMessage("Создана директория для изображений: $outputDir"); } $imagePattern = $outputDir . '/page-%03d.jpg'; $command = "convert -density 300 " . escapeshellarg($pdfPath) . " -quality 90 " . escapeshellarg($imagePattern); logMessage("Выполняем команду: " . $command); exec($command . " 2>&1", $output, $returnVar); logMessage("DEBUG: Вывод convert: " . implode("\n", $output)); if ($returnVar !== 0) { logMessage("Ошибка при конвертации PDF в изображения."); return []; } return glob($outputDir . '/*.jpg'); } function deleteFolderAndContents($folderPath) { if (is_dir($folderPath)) { $files = array_diff(scandir($folderPath), array('.', '..')); foreach ($files as $file) { $filePath = $folderPath . DIRECTORY_SEPARATOR . $file; if (is_dir($filePath)) { deleteFolderAndContents($filePath); } else { unlink($filePath); } } rmdir($folderPath); logMessage("Удалена подпапка и её содержимое: $folderPath"); } } // Подключение к БД $dbconfig = [ 'db_server' => 'localhost', 'db_port' => '3306', 'db_username' => 'ci20465_72new', 'db_password' => 'EcY979Rn', 'db_name' => 'ci20465_72new' ]; $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" => "Ошибка подключения к БД."])); } $conn->set_charset("utf8mb4"); $id = $_POST['id'] ?? null; if (!$id || !is_numeric($id)) { logMessage("Ошибка: Некорректный ID."); die(json_encode(["status" => "error", "message" => "Некорректный ID."])); } $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" => "Нет данных."])); } // Создаем уникальную рабочую папку для текущего запуска $uniqueFolder = "scanpdf/" . uniqid('run_', true); if (!file_exists($uniqueFolder)) { mkdir($uniqueFolder, 0777, true); logMessage("Создана подпапка для работы: $uniqueFolder"); } $files_data = []; while ($row = $result->fetch_assoc()) { $title = $row["title"]; $filePath = $row["filepath"]; logMessage("Обрабатываем файл: " . $filePath); $tempFilePath = renameFileForProcessing($filePath, $uniqueFolder); if (!$tempFilePath) continue; $text = extractTextFromPDF($tempFilePath); $data = ["title" => $title]; if (!empty(trim($text)) && mb_strlen(trim($text), 'UTF-8') >= 100) { logMessage("DEBUG: Текст извлечён из $title: " . substr($text, 0, 500)); $data["text"] = $text; } else { logMessage("PDF '$title' пуст или содержит слишком мало текста, конвертируем в изображения."); $outputDir = $uniqueFolder . "/pdf_images_" . uniqid(); $images = convertPdfToImages($tempFilePath, $outputDir); if (!empty($images)) { logMessage("DEBUG: Изображения созданы из $title: " . implode(", ", $images)); $recognizedText = ""; $data["nsfw_alert"] = false; // Инициализируем флаг NSFW foreach ($images as $imagePath) { logMessage("DEBUG: Отправляем изображение '$imagePath' на проверку NSFW."); $absImagePath = realpath($imagePath); logMessage("DEBUG: Абсолютный путь для проверки NSFW: " . $absImagePath); $classification = classifyImage($imagePath); if ($classification === null) { logMessage("DEBUG: Классификатор вернул null для изображения '$absImagePath'. Устанавливаем nsfw_alert в true."); $data["nsfw_alert"] = true; } elseif (isset($classification[$absImagePath])) { $unsafeProbability = $classification[$absImagePath]['unsafe']; logMessage("DEBUG: Для изображения '$absImagePath' получено unsafeProbability = " . $unsafeProbability); if ($unsafeProbability > 0.8) { logMessage("⚠️ Обнаружено NSFW-изображение: $absImagePath (unsafe = " . $unsafeProbability . ")"); $data["nsfw_alert"] = true; } else { logMessage("DEBUG: unsafeProbability для '$absImagePath' ниже порогового значения (0.8). Значение = " . $unsafeProbability); } } else { logMessage("DEBUG: Нет данных проверки NSFW для изображения '$absImagePath'."); } $ocrText = shell_exec("tesseract " . escapeshellarg($imagePath) . " stdout -l rus+eng --oem 1"); if (!empty(trim($ocrText))) { $recognizedText .= trim($ocrText) . "\n"; } } // Если обнаружен NSFW-контент, отдаем изображения вместо OCR-текста if (isset($data["nsfw_alert"]) && $data["nsfw_alert"] === true) { logMessage("DEBUG: Обнаружен NSFW-контент, поэтому вместо OCR-текста передаем изображения."); unset($data["text"]); $data["images"] = $images; } else { if (!empty(trim($recognizedText)) && mb_strlen(trim($recognizedText), 'UTF-8') >= 100) { logMessage("DEBUG: OCR-текст (LSTM) извлечён из изображений $title: " . substr($recognizedText, 0, 500)); $data["text"] = $recognizedText; } else { logMessage("PDF '$title' остаётся без читаемого текста, отправляем изображения в GPT."); $data["images"] = $images; } } } else { logMessage("Ошибка: PDF пуст, OCR не дал результатов, изображения не созданы."); } } // Добавляем новое поле moderation_passed: // Если NSFW обнаружен, модерация не пройдена, иначе, если присутствует текст, считаем, что модерация пройдена. if (isset($data["nsfw_alert"]) && $data["nsfw_alert"] === true) { $data["moderation_passed"] = false; } else { if (isset($data["text"]) && !empty(trim($data["text"]))) { $data["moderation_passed"] = true; } else { $data["moderation_passed"] = false; } } $files_data[] = $data; if (isset($data["nsfw_alert"]) && $data["nsfw_alert"] === true) { logMessage("DEBUG: Обнаружен NSFW-контент в документе '$title'."); } } logMessage("DEBUG: JSON, отправляемый в OpenAI: " . json_encode($files_data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); $task = "🔹 Отвечай по шаблону. **Задача**: Проанализируй загруженные документы, выполнив следующие действия: 1️⃣ **Список файлов и проверка соответствия названий** - Перечисли все загруженные файлы. - Внимательно анализируй изображения. - Если изображение содержит текст, сначала **извлеки текст** и **проанализируй его содержание**. - Укажи, если текст плохо читается или частично распознан. - Если изображение не содержит текста, опиши, что на нем изображено. **Особое внимание NSFW контенту в тексте и изображениях** - Обрати внимание на пометку `nsfw_alert`. Если она установлена в `true`, это значит, что файл содержит потенциально неприемлемый контент. Изучи его более внимательно. Отдельно укажи в отчете, что файл может содержать ТРЭШ-контент и требуется ручная проверка. 2️⃣ **Краткий анализ спора** - Определи **истца** (потребителя) и **ответчика** (компанию, на которую подана жалоба). - Опиши **суть спора** (что произошло и какая проблема заявлена). - Укажи **основные аргументы сторон** (что заявляет потребитель и какие возражения возможны у компании). 3️⃣ **Проверка на цензуру** - Проверь документы на наличие **ненормативной лексики** и **нецензурных изображений**. - Анализируй изображения на наличие нецензурного контента, запрещенной символики, сцен насилия и других нарушений. Если найдены такие элементы, укажи это в отчете. - Если обнаружены изображения, укажи что именно и требуется ли их ручная проверка. 4️⃣ **Выдача итогового вердикта** - Если всё соответствует, укажи: \"Вердикт: Прошло модерацию.\" - Если имеются несоответствия или потенциальные проблемы, укажи, что требуется ручная проверка. 5️⃣ **Характер спора** - Дай краткую характеристику дела (например, \”Характер спора: некачественный товар\", \" Характер спора: товар не привезли\", \" Характер спора: возврат денег\", \" Характер спора: некачественная услуга\" и т. д.). 6. **Укажи вероятность разрешения спора в пользe потребителя в %** Отвечай в формате «Вероятность положительного решения спора: _____» 7. **Чего не хватает запросить у Ответчика** Укажи, каких документов не хватает для проведения полного анализа и проведения процедуры медиации. Что необходимо получить дополнительно от контрагента или третьих лиц. Отвечай в формате «Запросить: ____» 8. **Чего не хватает запросить у Истца** Укажи, каких документов не хватает для составления более полного отчета и определения вариантов решения спора в пользу потребителя. Что необходимо получить дополнительно от заявителя или третьих лиц. Отвечай в формате «Запросить: ____» 📌 **Важно**: Отчет должен быть структурированным, четким и лаконичным. Укажи, какими нормами права РФ будет регулироваться рассмотрение данного спора. Если требуется ручная проверка, укажи приоритетные файлы для проверки. "; $body = json_encode([ //"model" => "gpt-4-turbo", "model" => "o1", "messages" => [ ["role" => "system", "content" => "Ты юридический аналитик. Проанализируй материалы согласно инструкции."], ["role" => "user", "content" => $task], ["role" => "user", "content" => json_encode($files_data, JSON_UNESCAPED_UNICODE)] ], "max_completion_tokens" => 4000 ]); logMessage("DEBUG: JSON, отправляемый в OpenAI: " . $body); $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); logMessage("Ответ от GPT-4-Turbo: " . $response); $gptAnalysis = json_decode($response, true); logMessage("Полный JSON-ответ от GPT: " . json_encode($gptAnalysis, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); if (!is_array($gptAnalysis)) { logMessage("Ошибка: JSON-декодирование не удалось."); die(json_encode(["status" => "error", "message" => "Ошибка: JSON-декодирование не удалось."])); } if (!isset($gptAnalysis['choices']) || empty($gptAnalysis['choices'])) { logMessage("Ошибка: в JSON-ответе отсутствует ключ 'choices'."); die(json_encode(["status" => "error", "message" => "Ошибка: в JSON-ответе отсутствует ключ 'choices'."])); } $content = $gptAnalysis['choices'][0]['message']['content'] ?? null; if (!$content) { logMessage("Ошибка: контент не найден в ответе от GPT."); die(json_encode(["status" => "error", "message" => "Ошибка: контент не найден в ответе от GPT."])); } //logMessage("DEBUG: Извлеченный контент: " . $content); // Извлекаем модерационный вердикт из ответа GPT. // Ищем строку, начинающуюся с "Вердикт:" и берем все, что идет после неё. $moderationVerdict = ""; // Попробуем найти строку с вердиктом if (preg_match('/Вердикт:\s*(Прошло модерацию|Не прошло модерацию)/ui', $content, $matches)) { $moderationVerdict = trim($matches[1]); // Получаем сам текст вердикта } // Логируем извлеченный вердикт модерации logMessage("DEBUG: Извлеченный вердикт модерации: " . ($moderationVerdict ?: "Не найден")); $final_output = [ "status" => "complete", "content" => $content, "moderationVerdict" => $moderationVerdict, "files_data" => $files_data ]; logMessage("DEBUG: Извлеченный контент: " . $content); logMessage("DEBUG: Извлеченный вердикт модерации: " . $moderationVerdict); echo json_encode($final_output, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); //echo json_encode(["status" => "complete", "content" => $content], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); logMessage("Отправка запроса в GPT завершена."); deleteFolderAndContents($uniqueFolder); ?>