- 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.
521 lines
20 KiB
PHP
521 lines
20 KiB
PHP
<?php
|
||
// aiassist/gptAssistant.php
|
||
require_once 'config.php';
|
||
require_once 'logger.php';
|
||
|
||
function createNewThread() {
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_THREADS_API,
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_POST => true,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Authorization: Bearer ' . OPENAI_API_KEY,
|
||
'OpenAI-Beta: assistants=v2'
|
||
]
|
||
]);
|
||
$response = curl_exec($curl);
|
||
$decoded = json_decode($response, true);
|
||
curl_close($curl);
|
||
|
||
if (isset($decoded['id'])) {
|
||
logMessage("🔄 Создан новый thread_id: " . $decoded['id']);
|
||
return $decoded['id'];
|
||
} else {
|
||
logMessage("❌ Ошибка создания нового треда: " . json_encode($decoded));
|
||
return null;
|
||
}
|
||
}
|
||
|
||
function extractCaseDetailsWithGPT($threadId, $assistantId, $fileId, $content) {
|
||
logMessage("\ud83d\udccc Формируем текст запроса для GPT-4 (анализ + проверка заказчика и суммы).");
|
||
|
||
$userMessage = <<<PROMPT
|
||
🔹 **Анализ обращения + проверка загруженных документов**
|
||
Проанализируй файлы и выдели ключевые параметры дела.
|
||
|
||
---
|
||
|
||
### **1️⃣ Модерация документов**
|
||
- Перечисли все загруженные файлы.
|
||
- Проверь, содержат ли изображения текст.
|
||
- Если изображение **без текста**, опиши, что на нём изображено.
|
||
- Укажи, если в файле есть **ненормативная лексика**, сцены насилия, запрещённая символика.
|
||
- Если требуется **ручная проверка**, напиши `"⚠️ Требуется ручная проверка: [название файла]"`.
|
||
|
||
---
|
||
|
||
### **2️⃣ Проверка заказчика (истца) в заявлении и документах**
|
||
- Определи **ФИО или название компании заказчика в заявлении**.
|
||
- Определи **ФИО или название компании в документах (договорах, платежах, актах)**.
|
||
- Если есть **расхождения**, напиши: `"⚠️ Заказчик в заявлении и документах различается! Проверьте соответствие."`
|
||
|
||
---
|
||
|
||
### **3️⃣ Проверка суммы договора**
|
||
- Найди сумму, указанную **в заявлении**.
|
||
- Найди сумму, указанную **в платежных документах**.
|
||
- Если суммы **не совпадают**, напиши: `"⚠️ Сумма в заявлении (___ руб.) не совпадает с платежами (___ руб.). Проверьте!"`
|
||
|
||
---
|
||
|
||
### **4️⃣ Краткий анализ спора**
|
||
- **Истец:** (ФИО или название компании)
|
||
- **Ответчик:** (ФИО или название компании)
|
||
- **Суть спора:** (Опиши проблему)
|
||
- **Основные аргументы сторон:** (Что заявляет истец и какие возражения у ответчика)
|
||
|
||
---
|
||
|
||
### **📌 Верни два блока ответа:**
|
||
✅ **1️⃣ JSON-формат для Elasticsearch:**
|
||
```json
|
||
{
|
||
"category": "",
|
||
"articles": [""],
|
||
"facts": "",
|
||
"claim_amount": "",
|
||
"document_type": "",
|
||
"applicant_name": "",
|
||
"document_client_name": "",
|
||
"discrepancy_alert": "",
|
||
"stated_amount": "",
|
||
"document_amount": ""
|
||
}
|
||
✅ 2️⃣ Читаемый текст для CRM:
|
||
🔹 Краткий анализ: ...
|
||
🔹 Заказчик: ...
|
||
🔹 Сумма договора: ...
|
||
PROMPT;
|
||
|
||
**Файлы:** $fileId
|
||
**Содержимое:** $content
|
||
PROMPT;
|
||
|
||
logMessage("\ud83d\udce1 Отправляем запрос в GPT-4: " . $userMessage);
|
||
|
||
$payload = [
|
||
"assistant_id" => $assistantId,
|
||
"thread" => [
|
||
"messages" => [
|
||
["role" => "user", "content" => $userMessage]
|
||
]
|
||
],
|
||
"stream" => true
|
||
];
|
||
|
||
$payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||
|
||
$finalMessage = "";
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_THREADS_API . "/runs",
|
||
CURLOPT_RETURNTRANSFER => false,
|
||
CURLOPT_POST => true,
|
||
CURLOPT_POSTFIELDS => $payloadJson,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Content-Type: application/json',
|
||
'Authorization: Bearer ' . OPENAI_API_KEY,
|
||
'OpenAI-Beta: assistants=v2'
|
||
],
|
||
CURLOPT_WRITEFUNCTION => function($ch, $data) use (&$finalMessage) {
|
||
$finalMessage .= $data;
|
||
return strlen($data);
|
||
}
|
||
]);
|
||
|
||
curl_exec($curl);
|
||
$curlError = curl_error($curl);
|
||
if ($curlError) {
|
||
logMessage("\u274c Ошибка cURL в extractCaseDetailsWithGPT: " . $curlError);
|
||
curl_close($curl);
|
||
return null;
|
||
}
|
||
curl_close($curl);
|
||
|
||
logMessage("\ud83d\udcc2 Сырой потоковый ответ от GPT-4:\n" . $finalMessage);
|
||
|
||
$parsedMessage = "";
|
||
$lines = explode("\n", $finalMessage);
|
||
foreach ($lines as $line) {
|
||
$line = trim($line);
|
||
if (strpos($line, "data: ") === 0) {
|
||
$dataPart = substr($line, 6);
|
||
if ($dataPart === "[DONE]") {
|
||
break;
|
||
}
|
||
$json = json_decode($dataPart, true);
|
||
if (is_array($json) && isset($json['delta']['content'])) {
|
||
$contentPiece = "";
|
||
foreach ($json['delta']['content'] as $segment) {
|
||
if (isset($segment['text']['value'])) {
|
||
$contentPiece .= $segment['text']['value'];
|
||
}
|
||
}
|
||
$parsedMessage .= $contentPiece;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (empty(trim($parsedMessage))) {
|
||
logMessage("\u26a0\ufe0f Парсинг не дал результата, используем сырой ответ.");
|
||
$parsedMessage = $finalMessage;
|
||
}
|
||
|
||
logMessage("\u2705 Итоговый ответ от GPT-4:\n" . $parsedMessage);
|
||
|
||
$structuredData = json_decode($parsedMessage, true);
|
||
if (!$structuredData) {
|
||
logMessage("\u274c Ошибка парсинга JSON, возвращаем сырой ответ.");
|
||
return ["error" => "Ошибка обработки данных"];
|
||
}
|
||
|
||
return $structuredData;
|
||
}
|
||
|
||
|
||
|
||
|
||
/*function extractCaseDetailsWithGPT($threadId, $assistantId, $fileId, $content) {
|
||
logMessage("📌 Предварительный анализ обращения через GPT-4 (stream): thread_id=$threadId, fileId=$fileId");
|
||
$userMessage = "🔹 Разбери обращение и выдели ключевые параметры:
|
||
|
||
1️⃣ **Категория дела**:
|
||
Определи, к какому типу спора относится это обращение.
|
||
|
||
2️⃣ **Применимые статьи закона**:
|
||
Выяви, какие нормы права могут быть применимы.
|
||
|
||
3️⃣ **Основные обстоятельства дела**:
|
||
Выдели важные факты из обращения и приложенных документов.
|
||
|
||
4️⃣ **Сумма требований (если указана)**:
|
||
Извлеки сумму требований, если она присутствует.
|
||
|
||
5️⃣ **Тип запрашиваемого документа**:
|
||
Определи, нужно ли составлять иск, претензию, жалобу или ходатайство.
|
||
|
||
6️⃣ **Оценка вероятности выигрыша**:
|
||
Оцени шансы на положительное решение (в %).
|
||
|
||
🔹 **Формат ответа (JSON)**:
|
||
{
|
||
\"category\": \"\",
|
||
\"articles\": [\"\"],
|
||
\"facts\": \"\",
|
||
\"claim_amount\": \"\",
|
||
\"document_type\": \"\",
|
||
\"win_probability\": \"\"
|
||
}
|
||
|
||
📌 Файлы: " . $fileId . "\n
|
||
📌 Содержимое для анализа:\n" . $content;
|
||
|
||
logMessage("📌 Формируем запрос к GPT-4: " . $userMessage);
|
||
|
||
$payload = [
|
||
"assistant_id" => $assistantId,
|
||
"thread" => [
|
||
"messages" => [
|
||
["role" => "user", "content" => $userMessage]
|
||
]
|
||
],
|
||
"stream" => true
|
||
];
|
||
|
||
$payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||
logMessage("🔹 Отправляем запрос в GPT-4 (Payload):\n" . $payloadJson);
|
||
|
||
$finalMessage = "";
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_THREADS_API . "/runs",
|
||
CURLOPT_RETURNTRANSFER => false,
|
||
CURLOPT_POST => true,
|
||
CURLOPT_POSTFIELDS => $payloadJson,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Content-Type: application/json',
|
||
'Authorization: Bearer ' . OPENAI_API_KEY,
|
||
'OpenAI-Beta: assistants=v2'
|
||
],
|
||
CURLOPT_WRITEFUNCTION => function($ch, $data) use (&$finalMessage) {
|
||
$finalMessage .= $data;
|
||
return strlen($data);
|
||
}
|
||
]);
|
||
|
||
curl_exec($curl);
|
||
$curlError = curl_error($curl);
|
||
if ($curlError) {
|
||
logMessage("❌ Ошибка cURL в extractCaseDetailsWithGPT: " . $curlError);
|
||
curl_close($curl);
|
||
return null;
|
||
}
|
||
curl_close($curl);
|
||
|
||
logMessage("📌 Сырой потоковый ответ (raw stream):\n" . $finalMessage);
|
||
|
||
$parsedMessage = "";
|
||
$lines = explode("\n", $finalMessage);
|
||
foreach ($lines as $line) {
|
||
$line = trim($line);
|
||
if (strpos($line, "data: ") === 0) {
|
||
$dataPart = substr($line, 6);
|
||
if ($dataPart === "[DONE]") {
|
||
break;
|
||
}
|
||
$json = json_decode($dataPart, true);
|
||
logMessage("🔹 DEBUG: Распарсенный фрагмент: " . print_r($json, true));
|
||
if (is_array($json) && isset($json['delta']['content'])) {
|
||
$contentPiece = "";
|
||
foreach ($json['delta']['content'] as $segment) {
|
||
if (isset($segment['text']['value'])) {
|
||
$contentPiece .= $segment['text']['value'];
|
||
}
|
||
}
|
||
$parsedMessage .= $contentPiece;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (empty(trim($parsedMessage))) {
|
||
logMessage("❌ Парсинг не дал результата, используем сырой ответ.");
|
||
$parsedMessage = $finalMessage;
|
||
}
|
||
|
||
logMessage("✅ Итоговый ответ от GPT-4 (stream):\n" . $parsedMessage);
|
||
|
||
$structuredData = json_decode($parsedMessage, true);
|
||
if (!$structuredData) {
|
||
logMessage("❌ Ошибка парсинга JSON, возвращаем сырой ответ.");
|
||
return ["error" => "Ошибка обработки данных"];
|
||
}
|
||
|
||
return $structuredData;
|
||
}
|
||
*/
|
||
function analyzeDocumentWithAssistantStream($threadId, $assistantId, $fileId, $content, $foundCases) {
|
||
logMessage("🔹 Анализ документа через GPT-4 (stream) + судебные решения: thread_id=$threadId, fileId=$fileId");
|
||
|
||
$casesSummary = "";
|
||
foreach ($foundCases as $index => $case) {
|
||
$caseId = $case["case_id"] ?? "Неизвестный ID";
|
||
$court = $case["court"] ?? "Неизвестный суд";
|
||
$decision = mb_substr($case["court_decision"] ?? "Текст отсутствует", 0, 1000, "UTF-8");
|
||
$casesSummary .= "📌 Дело #".($index + 1)." (ID: $caseId, Суд: $court):\n$decision\n\n";
|
||
}
|
||
|
||
$userMessage = <<<PROMPT
|
||
🔹 **Анализ юридического обращения**
|
||
Текст обращения: "$content"
|
||
|
||
📌 **Найденные судебные решения в базе:**
|
||
$casesSummary
|
||
|
||
📢 **Задача для GPT-4:**
|
||
1️⃣ Проанализируй найденные судебные дела и их исходы.
|
||
2️⃣ Определи вероятность успеха аналогичного иска.
|
||
3️⃣ Выяви основные аргументы, на которые можно опираться.
|
||
4️⃣ Укажи возможные риски и слабые места в иске.
|
||
|
||
Файлы пользователя: $fileId
|
||
PROMPT;
|
||
|
||
logMessage("📢 Промпт для GPT-4:\n" . $userMessage);
|
||
|
||
$payload = [
|
||
"assistant_id" => $assistantId,
|
||
"thread" => [
|
||
"messages" => [
|
||
["role" => "user", "content" => $userMessage]
|
||
]
|
||
],
|
||
"stream" => true
|
||
];
|
||
$payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||
logMessage("📡 Отправка запроса в GPT-4: " . $payloadJson);
|
||
|
||
$finalMessage = "";
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_THREADS_API . "/runs",
|
||
CURLOPT_RETURNTRANSFER => false,
|
||
CURLOPT_POST => true,
|
||
CURLOPT_POSTFIELDS => $payloadJson,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Content-Type: application/json',
|
||
'Authorization: Bearer ' . OPENAI_API_KEY,
|
||
'OpenAI-Beta: assistants=v2'
|
||
],
|
||
CURLOPT_WRITEFUNCTION => function($ch, $data) use (&$finalMessage) {
|
||
$finalMessage .= $data;
|
||
return strlen($data);
|
||
}
|
||
]);
|
||
|
||
curl_exec($curl);
|
||
$curlError = curl_error($curl);
|
||
if ($curlError) {
|
||
logMessage("❌ Ошибка cURL в analyzeDocumentWithAssistantStream: " . $curlError);
|
||
curl_close($curl);
|
||
return null;
|
||
}
|
||
curl_close($curl);
|
||
|
||
logMessage("📥 Сырой потоковый ответ от GPT-4:\n" . $finalMessage);
|
||
|
||
$parsedMessage = "";
|
||
$lines = explode("\n", $finalMessage);
|
||
foreach ($lines as $line) {
|
||
$line = trim($line);
|
||
if (strpos($line, "data: ") === 0) {
|
||
$dataPart = substr($line, 6);
|
||
if ($dataPart === "[DONE]") {
|
||
break;
|
||
}
|
||
$json = json_decode($dataPart, true);
|
||
if (is_array($json) && isset($json['delta']['content'])) {
|
||
$contentPiece = "";
|
||
foreach ($json['delta']['content'] as $segment) {
|
||
if (isset($segment['text']['value'])) {
|
||
$contentPiece .= $segment['text']['value'];
|
||
}
|
||
}
|
||
$parsedMessage .= $contentPiece;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (empty(trim($parsedMessage))) {
|
||
logMessage("⚠️ Парсинг не дал результата, используем сырой ответ.");
|
||
$parsedMessage = $finalMessage;
|
||
}
|
||
|
||
logMessage("✅ Итоговый анализ от GPT-4:\n" . $parsedMessage);
|
||
|
||
return [
|
||
"status" => "complete",
|
||
"content" => $parsedMessage
|
||
];
|
||
}
|
||
|
||
|
||
/*function analyzeDocumentWithAssistantStream($threadId, $assistantId, $fileId, $content, $foundCases, $prelimResponse = null) {
|
||
logMessage("🔹 Анализ документа через GPT-4 (stream) + судебные решения: thread_id=$threadId, fileId=$fileId");
|
||
|
||
$casesSummary = "";
|
||
foreach ($foundCases as $index => $case) {
|
||
$caseId = $case["case_id"] ?? "Неизвестный ID";
|
||
$court = $case["court"] ?? "Неизвестный суд";
|
||
$decision = mb_substr($case["court_decision"] ?? "Текст отсутствует", 0, 1000, "UTF-8");
|
||
$casesSummary .= "📌 Дело #".($index + 1)." (ID: $caseId, Суд: $court):\n$decision\n\n";
|
||
}
|
||
|
||
// Если предварительный анализ был выполнен, включаем его полностью
|
||
$prevAnalysisText = "";
|
||
if ($prelimResponse) {
|
||
// Можно форматировать предварительный ответ как JSON или, если он уже строка, использовать напрямую
|
||
if (is_array($prelimResponse)) {
|
||
$prevAnalysisText = json_encode($prelimResponse, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||
} else {
|
||
$prevAnalysisText = $prelimResponse;
|
||
}
|
||
}
|
||
|
||
// Формируем финальный промпт, включающий первоначальный текст обращения, предварительный анализ и контекст судебных решений
|
||
$userMessage = <<<PROMPT
|
||
🔹 **Анализ юридического обращения**
|
||
Текст обращения: "$content"
|
||
|
||
📌 **Найденные судебные решения в базе:**
|
||
$casesSummary
|
||
|
||
📢 **Задача для GPT-4:**
|
||
1️⃣ Проанализируй найденные судебные дела и их исходы.
|
||
2️⃣ Определи вероятность успеха аналогичного иска, основанного на данных из обращения. Укажи
|
||
3️⃣ Выяви основные аргументы, на которые можно опираться.
|
||
4️⃣ Укажи возможные риски и слабые места в иске.
|
||
|
||
Файлы пользователя: $fileId
|
||
PROMPT;
|
||
|
||
logMessage("📢 Промпт для GPT-4:\n" . $userMessage);
|
||
|
||
$payload = [
|
||
"assistant_id" => $assistantId,
|
||
"thread" => [
|
||
"messages" => [
|
||
["role" => "user", "content" => $userMessage]
|
||
]
|
||
],
|
||
"stream" => true
|
||
];
|
||
$payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||
logMessage("📡 Отправка запроса в GPT-4: " . $payloadJson);
|
||
|
||
$finalMessage = "";
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => OPENAI_THREADS_API . "/runs",
|
||
CURLOPT_RETURNTRANSFER => false,
|
||
CURLOPT_POST => true,
|
||
CURLOPT_POSTFIELDS => $payloadJson,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Content-Type: application/json',
|
||
'Authorization: Bearer ' . OPENAI_API_KEY,
|
||
'OpenAI-Beta: assistants=v2'
|
||
],
|
||
CURLOPT_WRITEFUNCTION => function($ch, $data) use (&$finalMessage) {
|
||
$finalMessage .= $data;
|
||
return strlen($data);
|
||
}
|
||
]);
|
||
|
||
curl_exec($curl);
|
||
$curlError = curl_error($curl);
|
||
if ($curlError) {
|
||
logMessage("❌ Ошибка cURL в analyzeDocumentWithAssistantStream: " . $curlError);
|
||
curl_close($curl);
|
||
return null;
|
||
}
|
||
curl_close($curl);
|
||
|
||
logMessage("📥 Сырой потоковый ответ от GPT-4:\n" . $finalMessage);
|
||
|
||
$parsedMessage = "";
|
||
$lines = explode("\n", $finalMessage);
|
||
foreach ($lines as $line) {
|
||
$line = trim($line);
|
||
if (strpos($line, "data: ") === 0) {
|
||
$dataPart = substr($line, 6);
|
||
if ($dataPart === "[DONE]") {
|
||
break;
|
||
}
|
||
$json = json_decode($dataPart, true);
|
||
if (is_array($json) && isset($json['delta']['content'])) {
|
||
$contentPiece = "";
|
||
foreach ($json['delta']['content'] as $segment) {
|
||
if (isset($segment['text']['value'])) {
|
||
$contentPiece .= $segment['text']['value'];
|
||
}
|
||
}
|
||
$parsedMessage .= $contentPiece;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (empty(trim($parsedMessage))) {
|
||
logMessage("⚠️ Парсинг не дал результата, используем сырой ответ.");
|
||
$parsedMessage = $finalMessage;
|
||
}
|
||
|
||
logMessage("✅ Итоговый анализ от GPT-4:\n" . $parsedMessage);
|
||
|
||
return [
|
||
"status" => "complete",
|
||
"content" => $parsedMessage
|
||
];
|
||
}
|
||
*/
|
||
?>
|