PDO::ERRMODE_EXCEPTION]); } catch (PDOException $e) { logMessage("Ошибка подключения к БД: " . $e->getMessage()); die(json_encode(['status' => 'error', 'message' => 'Database connection error'])); } // Основная логика обработки POST запроса if ($_SERVER['REQUEST_METHOD'] === 'POST') { $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' => 'Invalid ID'])); } try { // Получаем данные документов $documents = fetchDocumentData($pdo, $id); if (!$documents) { throw new Exception("Documents not found"); } // Создаем массив для хранения результатов обработки $processedDocuments = []; // Обрабатываем каждый документ foreach ($documents as $document) { logMessage("Обработка документа: " . $document['title']); // Создаем тред для документа $threadId = createThread(); if (!$threadId) { logMessage("Ошибка создания треда для документа: " . $document['title']); continue; } // Загружаем файл в OpenAI $fileId = uploadFileToOpenAI($document['filepath']); if (!$fileId) { logMessage("Ошибка загрузки файла для документа: " . $document['title']); continue; } // Анализируем документ $analysis = analyzeDocumentWithAssistant($threadId, ASSISTANT_ID, $fileId, $document['content']); if ($analysis) { $processedDocuments[] = [ 'title' => $document['title'], 'analysis' => $analysis ]; } } // Формируем итоговый ответ echo json_encode([ 'status' => 'success', 'documents' => $processedDocuments ], JSON_UNESCAPED_UNICODE); } catch (Exception $e) { logMessage("Ошибка: " . $e->getMessage()); die(json_encode(['status' => 'error', 'message' => $e->getMessage()])); } } else { die(json_encode(['status' => 'error', 'message' => 'Method not allowed'])); } function logMessage($message) { if (!is_dir('logs')) { mkdir('logs', 0777, true); } $message = mb_convert_encoding($message, 'UTF-8', 'auto'); file_put_contents(LOG_FILE, date('Y-m-d H:i:s') . " - " . $message . "\n", FILE_APPEND | LOCK_EX); } // Функция транслитерации (для переименования файлов) function transliterate($text) { $cyr = ['а','б','в','г','д','е','ё','ж','з','и','й','к','л','м','н','о','п','р','с','т','у','ф','х','ц','ч','ш','щ','ъ','ы','ь','э','ю','я']; $lat = ['a','b','v','g','d','e','yo','zh','z','i','y','k','l','m','n','o','p','r','s','t','u','f','h','ts','ch','sh','shch','','y','','e','yu','ya']; return str_replace($cyr, $lat, mb_strtolower($text)); } function renameFileForProcessing($filePath, $targetFolder = "scanpdf") { $pathInfo = pathinfo($filePath); $newName = transliterate($pathInfo['filename']) . "_" . uniqid() . "." . $pathInfo['extension']; $newPath = rtrim($targetFolder, "/") . "/" . $newName; if (copy($filePath, $newPath)) { logMessage("Файл переименован: $filePath -> $newPath"); return $newPath; } else { logMessage("Ошибка при копировании файла: $filePath"); return null; } } // Извлечение текста из PDF с помощью pdftotext 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); } // Конвертация PDF в изображения (ImageMagick convert) 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"); } } // Запуск OCR с Tesseract function doOCR($filePath) { logMessage("Запуск OCR для файла: $filePath"); $outputFile = tempnam(sys_get_temp_dir(), 'ocr_') . '.txt'; $command = "tesseract " . escapeshellarg($filePath) . " " . escapeshellarg($outputFile) . " -l rus+eng"; exec($command, $output, $returnVar); if ($returnVar !== 0 || !file_exists($outputFile . ".txt")) { logMessage("Ошибка OCR для файла: $filePath"); return ''; } $text = file_get_contents($outputFile . ".txt"); unlink($outputFile . ".txt"); return trim($text); } // Запуск NudeNet для NSFW-проверки изображения function classifyImage($imagePath) { $absolutePath = realpath($imagePath); if (!$absolutePath) { logMessage("ERROR: Не удалось получить абсолютный путь для " . $imagePath); return []; } logMessage("DEBUG: Абсолютный путь для классификации: " . $absolutePath); $escapedPath = escapeshellarg($absolutePath); $command = "python3 -c \"import json; from nudenet import NudeClassifier; classifier = NudeClassifier(); print(json.dumps(classifier.classify($escapedPath)))\""; logMessage("DEBUG: Выполнение команды NudeNet: " . $command); $output = shell_exec($command); logMessage("DEBUG: Вывод NudeNet: " . $output); if ($output === null) { logMessage("ERROR: shell_exec вернул null при выполнении NudeClassifier"); return []; } return json_decode(trim($output), true); } // Локальная NSFW-проверка с использованием NudeNet function checkNSFWLocally($filePath) { logMessage("Запуск локальной проверки NSFW для файла: $filePath"); $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION)); $imageToCheck = $filePath; if ($extension === 'pdf') { $outputImage = tempnam(sys_get_temp_dir(), 'pdf_img_') . '.png'; $command = "convert -density 150 " . escapeshellarg($filePath) . "[0] -quality 90 " . escapeshellarg($outputImage); exec($command, $output, $returnVar); if ($returnVar !== 0) { logMessage("Ошибка конвертации PDF в изображение для NSFW проверки."); return null; } $imageToCheck = $outputImage; } $classification = classifyImage($imageToCheck); if (empty($classification)) { logMessage("DEBUG: Нет данных NSFW для изображения '$imageToCheck'."); return false; } $absImagePath = realpath($imageToCheck); if (isset($classification[$absImagePath])) { $unsafeProbability = $classification[$absImagePath]['unsafe'] ?? 0; logMessage("DEBUG: unsafeProbability для '$absImagePath' = " . $unsafeProbability); return $unsafeProbability > 0.8; } logMessage("DEBUG: Классификатор не вернул данные для '$absImagePath'."); return false; } // Stub для получения контекста из базы знаний function getKnowledgeBaseContext() { return "Статическая информация: нормы и законы РФ, судебные прецеденты..."; } // Функции для работы с OpenAI Assistants (как в code4) function uploadFileToOpenAI($filePath) { logMessage("Загрузка файла в OpenAI: $filePath"); $ch = curl_init(OPENAI_FILES_API); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => [ 'file' => new CURLFile($filePath), 'purpose' => 'assistants' ], CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . OPENAI_API_KEY, 'OpenAI-Beta: assistants=v2' ] ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); logMessage("Ответ OpenAI (загрузка файла): HTTP $httpCode - " . $response); $decoded = json_decode($response, true); if ($httpCode !== 200 || !isset($decoded['id'])) { logMessage("Ошибка при загрузке файла: " . json_encode($decoded, JSON_UNESCAPED_UNICODE)); return null; } return $decoded['id']; } function createVectorStore() { $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => OPENAI_VECTOR_STORES_API, CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode(['name' => 'Vector Store']), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ' . OPENAI_API_KEY, 'OpenAI-Beta: assistants=v2' ] ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); curl_close($ch); if ($curlError) { logMessage("Ошибка cURL при создании Vector Store: " . $curlError); return null; } logMessage("Ответ OpenAI (создание Vector Store): HTTP $httpCode - " . $response); $decoded = json_decode($response, true); if ($httpCode !== 200 || !isset($decoded['id'])) { logMessage("Ошибка при создании Vector Store: " . json_encode($decoded, JSON_UNESCAPED_UNICODE)); return null; } return $decoded['id']; } function addFileToVectorStore($vectorStoreId, $fileId) { $ch = curl_init(OPENAI_VECTOR_STORES_API . "/$vectorStoreId/files"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode(['file_id' => $fileId]), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ' . OPENAI_API_KEY, 'OpenAI-Beta: assistants=v2' ] ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); logMessage("Ответ OpenAI (добавление файла в Vector Store): HTTP $httpCode - " . $response); $decoded = json_decode($response, true); if ($httpCode !== 200 || !isset($decoded['id'])) { logMessage("Ошибка добавления файла: " . json_encode($decoded, JSON_UNESCAPED_UNICODE)); return false; } return true; } function updateAssistantWithVectorStore($vectorStoreId) { $data = [ 'tool_resources' => [ 'file_search' => [ 'vector_store_ids' => [$vectorStoreId] ] ] ]; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => OPENAI_ASSISTANT_API . "/" . ASSISTANT_ID, CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ' . OPENAI_API_KEY, 'OpenAI-Beta: assistants=v2' ] ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); curl_close($ch); if ($curlError) { logMessage("Ошибка обновления ассистента: " . $curlError); return false; } logMessage("Ответ OpenAI (обновление ассистента): HTTP $httpCode - " . $response); $decoded = json_decode($response, true); if ($httpCode !== 200 || !isset($decoded['id'])) { logMessage("Ошибка обновления ассистента: " . json_encode($decoded, JSON_UNESCAPED_UNICODE)); return false; } return true; } function analyzeDocumentWithAssistant($threadId, $assistantId, $fileId, $content) { logMessage("Анализ документа: thread_id=$threadId, fileId=$fileId"); $messageContent = "Проанализируй документ"; if (!empty($fileId)) { $messageContent .= " (file_id: $fileId)"; } $messageContent .= ". Содержимое для анализа:\n" . $content; $messageData = [ 'role' => 'user', 'content' => $messageContent ]; // Отправляем сообщение в тред $ch = curl_init(OPENAI_THREADS_API . "/$threadId/messages"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($messageData), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ' . OPENAI_API_KEY, 'OpenAI-Beta: assistants=v2' ] ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); logMessage("Ответ (сообщение): HTTP $httpCode - " . $response); $decoded = json_decode($response, true); if ($httpCode !== 200 || !isset($decoded['id'])) { logMessage("Ошибка отправки сообщения: " . json_encode($decoded, JSON_UNESCAPED_UNICODE)); return null; } // Запуск ассистента $runData = ['assistant_id' => $assistantId]; $ch = curl_init(OPENAI_THREADS_API . "/$threadId/runs"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($runData), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ' . OPENAI_API_KEY, 'OpenAI-Beta: assistants=v2' ] ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); logMessage("Ответ (запуск ассистента): HTTP $httpCode - " . $response); $decodedRun = json_decode($response, true); if ($httpCode !== 200 || !isset($decodedRun['id'])) { logMessage("Ошибка запуска ассистента: " . json_encode($decodedRun, JSON_UNESCAPED_UNICODE)); return null; } $runId = $decodedRun['id']; $maxIterations = 30; $iterations = 0; do { sleep(2); $iterations++; $ch = curl_init(OPENAI_THREADS_API . "/$threadId/runs/$runId"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ' . OPENAI_API_KEY, 'OpenAI-Beta: assistants=v2' ] ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); logMessage("Статус запуска (итерация $iterations): HTTP $httpCode - " . $response); $decodedStatus = json_decode($response, true); $status = $decodedStatus['status'] ?? null; if ($iterations >= $maxIterations) { logMessage("Превышен максимальный таймаут ожидания работы ассистента."); return null; } } while ($status === 'queued' || $status === 'in_progress'); if ($status !== 'completed') { logMessage("Запуск ассистента завершился с ошибкой: $status"); return null; } // Получаем результат $ch = curl_init(OPENAI_THREADS_API . "/$threadId/messages"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ' . OPENAI_API_KEY, 'OpenAI-Beta: assistants=v2' ] ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); logMessage("Ответ (сообщения): HTTP $httpCode - " . $response); $decodedMessages = json_decode($response, true); if ($httpCode !== 200 || !isset($decodedMessages['data'])) { logMessage("Ошибка получения сообщений: " . json_encode($decodedMessages, JSON_UNESCAPED_UNICODE)); return null; } logMessage("Результаты анализа: " . json_encode($decodedMessages['data'], JSON_UNESCAPED_UNICODE)); return $decodedMessages['data']; } function generateReport($allResults) { if (empty($allResults)) { logMessage("Ошибка: Нет данных для отчета"); return "Ошибка: Нет данных для отчета"; } $report = "### Итоговый отчет по документам\n\n"; foreach ($allResults as $result) { $report .= "**Документ:** " . $result['document'] . "\n"; $report .= "**Статус:** " . $result['status'] . "\n"; if (isset($result['analysis'])) { $report .= "**Анализ:** " . json_encode($result['analysis'], JSON_UNESCAPED_UNICODE) . "\n"; } else { $report .= "**Сообщение:** " . $result['message'] . "\n"; } $report .= "\n"; } return $report; } // Основной процесс: получение ID из POST-запроса, выбор файлов из БД и обработка $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."])); } /* $id = $_POST['id'] ?? null; if (!$id || !is_numeric($id)) { logMessage("Ошибка: Некорректный ID."); die(json_encode(["status" => "error", "message" => "Некорректный ID."])); } */ $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"); $stmt = $conn->prepare(" 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->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; $data = ["title" => $title]; $text = extractTextFromPDF($tempFilePath); if (!empty(trim($text)) && mb_strlen(trim($text), 'UTF-8') >= 100) { logMessage("Текст извлечён из '$title'."); $data["text"] = $text; } else { logMessage("Текст не извлечён из '$title', конвертируем в изображения."); $outputDir = $uniqueFolder . "/pdf_images_" . uniqid(); $images = convertPdfToImages($tempFilePath, $outputDir); if (!empty($images)) { $recognizedText = ""; $data["nsfw_alert"] = false; foreach ($images as $img) { if (checkNSFWLocally($img)) { $data["nsfw_alert"] = true; logMessage("NSFW обнаружен в изображении: " . $img); break; } $ocrText = doOCR($img); if (!empty(trim($ocrText))) { $recognizedText .= $ocrText . "\n"; } } if (isset($data["nsfw_alert"]) && $data["nsfw_alert"] === true) { unset($data["text"]); $data["images"] = $images; } else { if (!empty(trim($recognizedText)) && mb_strlen(trim($recognizedText), 'UTF-8') >= 100) { $data["text"] = $recognizedText; } else { $data["images"] = $images; } } } else { logMessage("Ошибка: Изображения не созданы для '$title'."); } } $data["moderation_passed"] = isset($data["nsfw_alert"]) && $data["nsfw_alert"] === true ? false : (isset($data["text"]) && !empty(trim($data["text"])) ? true : false); $files_data[] = $data; } $stmt->close(); $conn->close(); logMessage("Данные для анализа: " . json_encode($files_data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); // Загрузка файлов в Vector Store (используем методы из code4) function createVectorStoreAndUploadFiles($files_data) { $vectorStoreId = createVectorStore(); if (!$vectorStoreId) return null; $uploadedFiles = []; foreach ($files_data as $data) { if (!isset($data["filepath"])) continue; $filePath = $data["filepath"]; if (!file_exists($filePath)) { logMessage("Ошибка: Файл не существует: $filePath"); continue; } $fileId = uploadFileToOpenAI($filePath); if (!$fileId) { logMessage("Ошибка загрузки файла: $filePath"); continue; } if (!addFileToVectorStore($vectorStoreId, $fileId)) { logMessage("Ошибка добавления файла в Vector Store: $filePath"); } else { logMessage("Файл успешно добавлен в Vector Store: $filePath"); $uploadedFiles[$filePath] = $fileId; } } return ['vectorStoreId' => $vectorStoreId, 'fileIds' => $uploadedFiles]; } $uploadResult = createVectorStoreAndUploadFiles($files_data); if (!$uploadResult) { logMessage("Ошибка создания Vector Store или загрузки файлов"); die(json_encode(["status" => "error", "message" => "Ошибка создания Vector Store или загрузки файлов"])); } $vectorStoreId = $uploadResult['vectorStoreId']; $uploadedFileIds = $uploadResult['fileIds']; if (!updateAssistantWithVectorStore($vectorStoreId)) { logMessage("Ошибка обновления ассистента с Vector Store"); die(json_encode(["status" => "error", "message" => "Ошибка обновления ассистента"])); } // Формирование итогового запроса для OpenAI $task = "🔹 Отвечай по шаблону. **Задача**: Проанализируй загруженные документы, выполнив следующие действия: 1️⃣ **Список файлов и проверка соответствия названий** - Перечисли все загруженные файлы. - Внимательно анализируй изображения. - Если изображение содержит текст, сначала извлеки текст и проанализируй его содержание. - Укажи, если текст плохо читается или частично распознан. - Если изображение не содержит текста, опиши, что на нем изображено. - Обрати внимание на пометку nsfw_alert. Если она true, файл требует ручной проверки. 2️⃣ **Краткий анализ спора** - Определи истца (потребителя) и ответчика (компанию, на которую подана жалоба). - Опиши суть спора и основные аргументы сторон. 3️⃣ **Проверка на цензуру** - Проверь документы на наличие ненормативной лексики и нецензурных изображений. 4️⃣ **Выдача итогового вердикта** - Если всё соответствует, укажи: \"Вердикт: Прошло модерацию.\" - Если есть проблемы, укажи, что требуется ручная проверка. 5️⃣ **Характер спора** - Дай краткую характеристику дела (например, \"возврат денег\", \"некачественная услуга\" и т.д.). 6️⃣ **Вероятность положительного решения спора** - Укажи вероятность в процентах. 7️⃣ **Чего не хватает** - Запроси дополнительные документы, если необходимо. 📌 **Важно**: Отчет должен быть структурированным, четким и лаконичным, с указанием норм права РФ, регулирующих данный спор, и приоритетных файлов для ручной проверки."; $finalContent = ""; foreach ($files_data as $file) { $finalContent .= json_encode($file, JSON_UNESCAPED_UNICODE) . "\n"; } $payload = [ "model" => "o1", "messages" => [ ["role" => "system", "content" => "Ты юридический аналитик. Проанализируй материалы согласно инструкции."], ["role" => "user", "content" => $task], ["role" => "user", "content" => $finalContent] ], "max_completion_tokens" => 4000 ]; $payload_json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); logMessage("Отправка запроса в OpenAI: " . $payload_json); $ch = curl_init(OPENAI_API_URL); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload_json, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Authorization: Bearer ' . OPENAI_API_KEY ] ]); $response = curl_exec($ch); curl_close($ch); logMessage("Ответ от OpenAI: " . $response); $gptAnalysis = json_decode($response, true); 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."])); } if (preg_match('/Вердикт:\s*(Прошло модерацию|Не прошло модерацию)/ui', $content, $matches)) { $moderationVerdict = trim($matches[1]); } else { $moderationVerdict = ""; } logMessage("Извлеченный вердикт модерации: " . ($moderationVerdict ?: "Не найден")); $final_output = [ "status" => "complete", "analysis" => $content, "moderationVerdict" => $moderationVerdict // "files_data" => $files_data ]; logMessage("Финальный вывод: " . json_encode($final_output, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); echo json_encode($final_output, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); // Очистка: удаление рабочей папки deleteFolderAndContents($uniqueFolder); function fetchDocumentData($pdo, $id) { try { // Изменяем SQL-запрос для корректного получения данных $stmt = $pdo->prepare(" SELECT DISTINCT n.title, n.content, CONCAT(a.path, a.attachmentsid, '_', COALESCE(a.storedname, a.name)) AS filepath FROM vtiger_notes n INNER JOIN vtiger_crmentity e ON e.crmid = n.notesid INNER JOIN vtiger_senotesrel snr ON snr.notesid = n.notesid LEFT JOIN vtiger_seattachmentsrel sar ON sar.crmid = n.notesid LEFT JOIN vtiger_attachments a ON a.attachmentsid = sar.attachmentsid WHERE snr.crmid = ? AND e.deleted = 0 "); // Логируем SQL запрос logMessage("SQL запрос: " . $stmt->queryString); $stmt->execute([$id]); $documents = $stmt->fetchAll(PDO::FETCH_ASSOC); // Логируем результат запроса logMessage("Результат запроса: " . print_r($documents, true)); if (empty($documents)) { logMessage("Документы не найдены для ID = $id"); return null; } // Проверяем наличие файлов foreach ($documents as $key => $doc) { if (isset($doc['filepath']) && !file_exists($doc['filepath'])) { logMessage("Предупреждение: Файл не существует: " . $doc['filepath']); // Попробуем альтернативный путь $alternativePath = "storage/" . basename($doc['filepath']); if (file_exists($alternativePath)) { $documents[$key]['filepath'] = $alternativePath; logMessage("Найден альтернативный путь: " . $alternativePath); } } } // Логируем финальный результат logMessage("Обработанные документы: " . json_encode($documents, JSON_UNESCAPED_UNICODE)); return $documents; } catch (PDOException $e) { logMessage("Ошибка SQL: " . $e->getMessage()); logMessage("SQL State: " . $e->getCode()); return null; } } ?>