- Added comprehensive AI Assistant system (aiassist/ directory): * Vector search and embedding capabilities * Typebot proxy integration * Elastic search functionality * Message classification and chat history * MCP proxy for external integrations - Implemented Court Status API (GetCourtStatus.php): * Real-time court document status checking * Integration with external court systems * Comprehensive error handling and logging - Enhanced S3 integration: * Improved file backup system with metadata * Batch processing capabilities * Enhanced error logging and recovery * Copy operations with URL fixing - Added Telegram contact creation API - Improved error logging across all modules - Enhanced callback system for AI responses - Extensive backup file storage with timestamps - Updated documentation and README files - File storage improvements: * Thousands of backup files with proper metadata * Fix operations for broken file references * Project-specific backup and recovery systems * Comprehensive file integrity checking Total: 26,461+ files added/modified including AWS SDK, vendor dependencies, and extensive backup system.
627 lines
25 KiB
PHP
627 lines
25 KiB
PHP
<?php
|
||
|
||
// Настройки OpenAI API
|
||
const OPENAI_API_KEY = 'sk-GS24OxHQYfq8ErW5CRLoN5F1CfJPxNsY';
|
||
const OPENAI_ASSISTANT_API = 'https://api.proxyapi.ru/openai/v1/assistants';
|
||
const OPENAI_FILES_API = 'https://api.proxyapi.ru/openai/v1/files';
|
||
const OPENAI_THREADS_API = 'https://api.proxyapi.ru/openai/v1/threads';
|
||
const OPENAI_VECTOR_STORES_API = 'https://api.proxyapi.ru/openai/v1/vector_stores';
|
||
const OPENAI_NSFW_API = 'https://api.proxyapi.ru/openai/v1/vision';
|
||
|
||
//const OPENAI_NSFW_API = 'https://api.proxyapi.ru/openai/v1/chat/completions';
|
||
//const OPENAI_VISION_API = 'https://api.proxyapi.ru/openai/v1/vision';
|
||
const LOG_FILE = 'logs/scriptDS99.log';
|
||
|
||
// ID и имя ассистента
|
||
const ASSISTANT_ID = 'asst_suGt51aoepXUkJiC0t3vobeG';
|
||
const ASSISTANT_NAME = 'Clientright';
|
||
|
||
// Подключение к базе данных Vtiger CRM
|
||
$dsn = 'mysql:host=localhost;port=3306;dbname=ci20465_72new;charset=utf8mb4';
|
||
$user = 'ci20465_72new';
|
||
$password = 'EcY979Rn';
|
||
|
||
try {
|
||
$pdo = new PDO($dsn, $user, $password, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
||
} catch (PDOException $e) {
|
||
logMessage("Ошибка подключения к БД: " . $e->getMessage());
|
||
die("Ошибка подключения к БД");
|
||
}
|
||
|
||
// Функция логирования
|
||
function logMessage($message) {
|
||
if (!is_dir('logs')) {
|
||
mkdir('logs', 0777, true);
|
||
}
|
||
file_put_contents(LOG_FILE, date('Y-m-d H:i:s') . " - " . $message . "\n", FILE_APPEND | LOCK_EX);
|
||
}
|
||
|
||
// Основной скрипт
|
||
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
$input = json_decode(file_get_contents('php://input'), true);
|
||
$id = $input['id'] ?? null;
|
||
|
||
if (!$id) {
|
||
logMessage("Ошибка: отсутствует ID документа");
|
||
die("Ошибка: отсутствует ID документа");
|
||
}
|
||
|
||
logMessage("Начало обработки документа с ID: $id");
|
||
|
||
// Получаем документы из базы данных
|
||
$documents = fetchDocumentData($pdo, $id);
|
||
if (empty($documents)) {
|
||
logMessage("Документы не найдены для ID: $id");
|
||
die("Документы не найдены для ID: $id");
|
||
}
|
||
|
||
logMessage("Документы получены из БД: " . json_encode($documents, JSON_UNESCAPED_UNICODE));
|
||
|
||
// Извлекаем пути файлов
|
||
$filePaths = array_column($documents, 'filepath');
|
||
|
||
// Создаем Vector Store и загружаем файлы, получая ассоциативный массив fileIds (путь => file_id)
|
||
$uploadResult = createVectorStoreAndUploadFiles($filePaths);
|
||
if (!$uploadResult) {
|
||
logMessage("Ошибка создания Vector Store или загрузки файлов");
|
||
die("Ошибка создания Vector Store или загрузки файлов");
|
||
}
|
||
$vectorStoreId = $uploadResult['vectorStoreId'];
|
||
$uploadedFileIds = $uploadResult['fileIds'];
|
||
|
||
// Обновляем ассистента с Vector Store
|
||
if (!updateAssistantWithVectorStore($vectorStoreId)) {
|
||
logMessage("Ошибка обновления ассистента с Vector Store");
|
||
die("Ошибка обновления ассистента");
|
||
}
|
||
|
||
// Анализ документов – теперь передаем также $uploadedFileIds для связи файла с анализом
|
||
$allResults = analyzeDocuments($documents, $uploadedFileIds);
|
||
|
||
if (empty($allResults)) {
|
||
logMessage("Ошибка: анализ документов не вернул результатов");
|
||
die("Ошибка: анализ документов не вернул результатов");
|
||
}
|
||
|
||
// Формирование итогового отчета
|
||
$report = generateReport($allResults);
|
||
logMessage("Итоговый отчет:\n" . $report);
|
||
echo $report;
|
||
|
||
logMessage("Обработка всех документов завершена.");
|
||
} else {
|
||
logMessage("Ошибка: запрос должен быть POST");
|
||
die("Ошибка: запрос должен быть POST");
|
||
}
|
||
|
||
// Функция для получения данных из базы Vtiger CRM
|
||
function fetchDocumentData($pdo, $id) {
|
||
logMessage("Получение данных документа из CRM по ID: $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')
|
||
";
|
||
|
||
try {
|
||
$stmt = $pdo->prepare($sql);
|
||
$stmt->execute([$id]);
|
||
$documents = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||
logMessage("Документы получены из CRM: " . json_encode($documents, JSON_UNESCAPED_UNICODE));
|
||
return $documents;
|
||
} catch (PDOException $e) {
|
||
logMessage("Ошибка при выполнении запроса к CRM: " . $e->getMessage());
|
||
return [];
|
||
}
|
||
}
|
||
|
||
// Функция для создания Vector Store и загрузки файлов
|
||
// Теперь возвращается массив с ключами 'vectorStoreId' и 'fileIds' (mapping путь => file_id)
|
||
function createVectorStoreAndUploadFiles($filePaths) {
|
||
logMessage("Создание Vector Store и загрузка файлов...");
|
||
|
||
$vectorStoreId = createVectorStore();
|
||
if (!$vectorStoreId) {
|
||
return null;
|
||
}
|
||
|
||
$uploadedFiles = []; // массив: путь => file_id
|
||
|
||
foreach ($filePaths as $filePath) {
|
||
logMessage("Загрузка файла: $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];
|
||
}
|
||
|
||
// Функция для создания Vector Store
|
||
function createVectorStore() {
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
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($curl);
|
||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($curl);
|
||
curl_close($curl);
|
||
|
||
if ($curlError) {
|
||
logMessage("Ошибка cURL при создании Vector Store: " . $curlError);
|
||
return null;
|
||
}
|
||
|
||
logMessage("Ответ OpenAI (создание Vector Store): HTTP $httpCode - " . $response);
|
||
|
||
$decodedResponse = json_decode($response, true);
|
||
if ($httpCode !== 200 || !isset($decodedResponse['id'])) {
|
||
logMessage("Ошибка при создании Vector Store: " . json_encode($decodedResponse, JSON_UNESCAPED_UNICODE));
|
||
return null;
|
||
}
|
||
|
||
return $decodedResponse['id'];
|
||
}
|
||
|
||
// Функция для загрузки файла в OpenAI
|
||
function uploadFileToOpenAI($filePath) {
|
||
logMessage("Загрузка файла в OpenAI: $filePath");
|
||
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_FILES_API,
|
||
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($curl);
|
||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($curl);
|
||
curl_close($curl);
|
||
|
||
if ($curlError) {
|
||
logMessage("Ошибка cURL при загрузке файла: " . $curlError);
|
||
return null;
|
||
}
|
||
|
||
logMessage("Ответ OpenAI (загрузка файла): HTTP $httpCode - " . $response);
|
||
$decodedResponse = json_decode($response, true);
|
||
if ($httpCode !== 200 || !isset($decodedResponse['id'])) {
|
||
logMessage("Ошибка при загрузке файла: " . json_encode($decodedResponse, JSON_UNESCAPED_UNICODE));
|
||
return null;
|
||
}
|
||
|
||
return $decodedResponse['id'];
|
||
}
|
||
|
||
// Функция для добавления файла в Vector Store
|
||
function addFileToVectorStore($vectorStoreId, $fileId) {
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_VECTOR_STORES_API . "/$vectorStoreId/files",
|
||
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($curl);
|
||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($curl);
|
||
curl_close($curl);
|
||
|
||
if ($curlError) {
|
||
logMessage("Ошибка cURL при добавлении файла в Vector Store: " . $curlError);
|
||
return false;
|
||
}
|
||
|
||
logMessage("Ответ OpenAI (добавление файла в Vector Store): HTTP $httpCode - " . $response);
|
||
$decodedResponse = json_decode($response, true);
|
||
if ($httpCode !== 200 || !isset($decodedResponse['id'])) {
|
||
logMessage("Ошибка при добавлении файла в Vector Store: " . json_encode($decodedResponse, JSON_UNESCAPED_UNICODE));
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
// Функция для обновления ассистента с Vector Store
|
||
function updateAssistantWithVectorStore($vectorStoreId) {
|
||
$updateData = [
|
||
'tool_resources' => [
|
||
'file_search' => [
|
||
'vector_store_ids' => [$vectorStoreId]
|
||
]
|
||
]
|
||
];
|
||
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_ASSISTANT_API . "/" . ASSISTANT_ID,
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_CUSTOMREQUEST => 'POST',
|
||
CURLOPT_POSTFIELDS => json_encode($updateData),
|
||
CURLOPT_HTTPHEADER => [
|
||
'Content-Type: application/json',
|
||
'Authorization: Bearer ' . OPENAI_API_KEY,
|
||
'OpenAI-Beta: assistants=v2'
|
||
]
|
||
]);
|
||
|
||
$response = curl_exec($curl);
|
||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($curl);
|
||
curl_close($curl);
|
||
if ($curlError) {
|
||
logMessage("Ошибка cURL при обновлении ассистента: " . $curlError);
|
||
return false;
|
||
}
|
||
logMessage("Ответ OpenAI (обновление ассистента): HTTP $httpCode - " . $response);
|
||
$decodedResponse = json_decode($response, true);
|
||
if ($httpCode !== 200 || !isset($decodedResponse['id'])) {
|
||
logMessage("Ошибка при обновлении ассистента: " . json_encode($decodedResponse, JSON_UNESCAPED_UNICODE));
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// Функция для анализа документов
|
||
// Теперь принимает второй параметр — массив fileIds
|
||
|
||
function analyzeDocuments($documents, $uploadedFileIds) {
|
||
$combinedFileIds = [];
|
||
$allResults = [];
|
||
|
||
// Собираем file_id для всех документов, прошедших NSFW-проверку
|
||
foreach ($documents as $doc) {
|
||
if (empty($doc['filepath']) || strpos($doc['filepath'], '_') === 0) {
|
||
logMessage("Ошибка: Путь к файлу пуст или некорректен: " . json_encode($doc, JSON_UNESCAPED_UNICODE));
|
||
continue;
|
||
}
|
||
|
||
// Проверка на NSFW
|
||
$isNSFW = checkNSFWWithOpenAI($doc['filepath']);
|
||
if ($isNSFW === null) {
|
||
$isNSFW = checkNSFWLocally($doc['filepath']);
|
||
}
|
||
if ($isNSFW) {
|
||
logMessage("⚠️ Файл содержит NSFW-контент: " . $doc['filepath']);
|
||
$allResults[] = [
|
||
'document' => $doc['title'],
|
||
'status' => 'NSFW',
|
||
'message' => 'Файл содержит NSFW-контент и отправлен на ручную модерацию.'
|
||
];
|
||
continue;
|
||
}
|
||
|
||
// Получаем file_id из массива загруженных файлов
|
||
$fileId = $uploadedFileIds[$doc['filepath']] ?? '';
|
||
if (!$fileId) {
|
||
logMessage("Ошибка: Не найден file_id для файла " . $doc['filepath']);
|
||
continue;
|
||
}
|
||
$combinedFileIds[] = $fileId;
|
||
}
|
||
|
||
// Если есть файлы для анализа, выполняем совокупный анализ
|
||
if (!empty($combinedFileIds)) {
|
||
$threadId = createThread();
|
||
if (!$threadId) {
|
||
logMessage("Ошибка создания треда в OpenAI");
|
||
die("Ошибка создания треда в OpenAI");
|
||
}
|
||
|
||
// Собираем строку из всех file_id
|
||
$fileIdsString = implode(", ", $combinedFileIds);
|
||
|
||
// Формируем сообщение для совокупного анализа
|
||
// Можно также уточнить в сообщении, что анализ проводится по совокупности документов
|
||
$analysis = analyzeDocumentWithAssistant($threadId, ASSISTANT_ID, $fileIdsString);
|
||
if ($analysis) {
|
||
logMessage("Анализ документов завершен: " . json_encode($analysis, JSON_UNESCAPED_UNICODE));
|
||
$allResults[] = [
|
||
'document' => 'Совокупный анализ',
|
||
'status' => 'Анализ завершен',
|
||
'analysis' => $analysis
|
||
];
|
||
} else {
|
||
logMessage("Ошибка анализа документов");
|
||
$allResults[] = [
|
||
'document' => 'Совокупный анализ',
|
||
'status' => 'Ошибка анализа',
|
||
'message' => 'Не удалось проанализировать документы.'
|
||
];
|
||
}
|
||
}
|
||
|
||
return $allResults;
|
||
}
|
||
|
||
|
||
// Функция для создания треда
|
||
function createThread() {
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_THREADS_API,
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_POST => true,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Content-Type: application/json',
|
||
'Authorization: Bearer ' . OPENAI_API_KEY,
|
||
'OpenAI-Beta: assistants=v2'
|
||
]
|
||
]);
|
||
$response = curl_exec($curl);
|
||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($curl);
|
||
curl_close($curl);
|
||
if ($curlError) {
|
||
logMessage("Ошибка cURL при создании треда: " . $curlError);
|
||
return null;
|
||
}
|
||
logMessage("Ответ OpenAI (создание треда): HTTP $httpCode - " . $response);
|
||
$decodedResponse = json_decode($response, true);
|
||
if ($httpCode !== 200 || !isset($decodedResponse['id'])) {
|
||
logMessage("Ошибка при создании треда: " . json_encode($decodedResponse, JSON_UNESCAPED_UNICODE));
|
||
return null;
|
||
}
|
||
return $decodedResponse['id'];
|
||
}
|
||
|
||
// Функция для анализа документа с использованием ассистента
|
||
// Теперь принимает третий параметр $fileId и передает его в сообщение
|
||
function analyzeDocumentWithAssistant($threadId, $assistantId, $fileId) {
|
||
logMessage("Анализ документа с использованием ассистента: thread_id=$threadId, assistant_id=$assistantId, fileId=$fileId");
|
||
|
||
$messageContent = "Проанализируй документ";
|
||
if (!empty($fileId)) {
|
||
$messageContent .= " с файлом id: " . $fileId;
|
||
}
|
||
$messageData = [
|
||
'role' => 'user',
|
||
'content' => $messageContent
|
||
];
|
||
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/messages",
|
||
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($curl);
|
||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($curl);
|
||
curl_close($curl);
|
||
if ($curlError) {
|
||
logMessage("Ошибка cURL при отправке сообщения в тред: " . $curlError);
|
||
return null;
|
||
}
|
||
logMessage("Ответ OpenAI (сообщение в тред): HTTP $httpCode - " . $response);
|
||
$decodedResponse = json_decode($response, true);
|
||
if ($httpCode !== 200 || !isset($decodedResponse['id'])) {
|
||
logMessage("Ошибка при отправке сообщения в тред: " . json_encode($decodedResponse, JSON_UNESCAPED_UNICODE));
|
||
return null;
|
||
}
|
||
// Запуск ассистента для обработки треда
|
||
$runData = ['assistant_id' => $assistantId];
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/runs",
|
||
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($curl);
|
||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($curl);
|
||
curl_close($curl);
|
||
if ($curlError) {
|
||
logMessage("Ошибка cURL при запуске ассистента: " . $curlError);
|
||
return null;
|
||
}
|
||
logMessage("Ответ OpenAI (запуск ассистента): HTTP $httpCode - " . $response);
|
||
$decodedResponse = json_decode($response, true);
|
||
if ($httpCode !== 200 || !isset($decodedResponse['id'])) {
|
||
logMessage("Ошибка при запуске ассистента: " . json_encode($decodedResponse, JSON_UNESCAPED_UNICODE));
|
||
return null;
|
||
}
|
||
$runId = $decodedResponse['id'];
|
||
// Ожидание завершения обработки ассистентом
|
||
do {
|
||
sleep(2);
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/runs/$runId",
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Content-Type: application/json',
|
||
'Authorization: Bearer ' . OPENAI_API_KEY,
|
||
'OpenAI-Beta: assistants=v2'
|
||
]
|
||
]);
|
||
$response = curl_exec($curl);
|
||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($curl);
|
||
curl_close($curl);
|
||
if ($curlError) {
|
||
logMessage("Ошибка cURL при проверке статуса запуска: " . $curlError);
|
||
return null;
|
||
}
|
||
logMessage("Ответ OpenAI (статус запуска): HTTP $httpCode - " . $response);
|
||
$decodedResponse = json_decode($response, true);
|
||
$status = $decodedResponse['status'] ?? null;
|
||
} while ($status === 'queued' || $status === 'in_progress');
|
||
if ($status !== 'completed') {
|
||
logMessage("Ошибка: статус запуска ассистента - $status");
|
||
return null;
|
||
}
|
||
// Получение результата анализа
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/messages",
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Content-Type: application/json',
|
||
'Authorization: Bearer ' . OPENAI_API_KEY,
|
||
'OpenAI-Beta: assistants=v2'
|
||
]
|
||
]);
|
||
$response = curl_exec($curl);
|
||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($curl);
|
||
curl_close($curl);
|
||
if ($curlError) {
|
||
logMessage("Ошибка cURL при получении сообщений: " . $curlError);
|
||
return null;
|
||
}
|
||
logMessage("Ответ OpenAI (сообщения): HTTP $httpCode - " . $response);
|
||
$decodedResponse = json_decode($response, true);
|
||
if ($httpCode !== 200 || !isset($decodedResponse['data'])) {
|
||
logMessage("Ошибка при получении сообщений: " . json_encode($decodedResponse, JSON_UNESCAPED_UNICODE));
|
||
return null;
|
||
}
|
||
logMessage("Результаты анализа: " . json_encode($decodedResponse['data'], JSON_UNESCAPED_UNICODE));
|
||
return $decodedResponse['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;
|
||
}
|
||
|
||
/* ===================== NSFW-фильтрация и OCR ===================== */
|
||
|
||
function checkNSFWWithOpenAI($filePath) {
|
||
logMessage("Запуск NSFW-проверки через OpenAI для файла: $filePath");
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_NSFW_API,
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_POST => true,
|
||
CURLOPT_POSTFIELDS => [
|
||
'file' => new CURLFile($filePath),
|
||
'purpose' => 'nsfw'
|
||
],
|
||
CURLOPT_HTTPHEADER => [
|
||
'Authorization: Bearer ' . OPENAI_API_KEY,
|
||
'OpenAI-Beta: assistants=v2'
|
||
]
|
||
]);
|
||
$response = curl_exec($curl);
|
||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||
$curlError = curl_error($curl);
|
||
curl_close($curl);
|
||
if ($curlError) {
|
||
logMessage("Ошибка cURL при проверке NSFW через OpenAI: " . $curlError);
|
||
return null;
|
||
}
|
||
logMessage("Ответ OpenAI (NSFW-проверка): HTTP $httpCode - " . $response);
|
||
$decodedResponse = json_decode($response, true);
|
||
if ($httpCode === 200 && isset($decodedResponse['nsfw'])) {
|
||
return $decodedResponse['nsfw'];
|
||
} else {
|
||
logMessage("Ошибка проверки NSFW через OpenAI: " . json_encode($decodedResponse, JSON_UNESCAPED_UNICODE));
|
||
return null;
|
||
}
|
||
}
|
||
|
||
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;
|
||
}
|
||
logMessage("Локальная NSFW-проверка завершена: NSFW не обнаружен для файла: $imageToCheck");
|
||
return false;
|
||
}
|