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 getVectorStoreStatus($vectorStoreId) { //$url = "https://api.proxyapi.ru/openai/v1/vector_stores/$vectorStoreId/files"; $url = OPENAI_VECTOR_STORES_API . "/$vectorStoreId/files"; logMessage("📡 Запрос статуса файлов в Vector Store: $vectorStoreId"); $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . OPENAI_API_KEY, "Content-Type: application/json", "OpenAI-Beta: assistants=v2" ] ]); $response = curl_exec($curl); $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_close($curl); if ($httpCode !== 200) { logMessage("❌ Ошибка HTTP при получении статуса файлов Vector Store: код $httpCode"); return "failed"; } $data = json_decode($response, true); if (!isset($data["data"])) { logMessage("❌ Ошибка: API не вернул список файлов."); return "failed"; } $completedFiles = count(array_filter($data["data"], function($file) { return isset($file["status"]) && $file["status"] === "completed"; })); if ($completedFiles > 0) { logMessage("✅ Vector Store содержит $completedFiles проиндексированных файлов."); return "ready"; } logMessage("⚠️ Файлы еще индексируются."); return "in_progress"; } // нью /* function extractCaseDetailsWithGPT($threadId, $assistantId, $vectorStoreId, $content) { logMessage("[INFO] 📌 Формируем текст запроса для GPT-4."); if (!$vectorStoreId) { logMessage("[ERROR] ❌ Ошибка: Нет доступного `Vector Store ID`!"); return null; } if (!$threadId) { logMessage("[ERROR] ❌ Ошибка: Некорректный `Thread ID`!"); return null; } if (!$content) { logMessage("[ERROR] ❌ Ошибка: Пустое содержание обращения!"); return null; } logMessage("[INFO] 📌 Отправляем текст в GPT-4: " . json_encode($content, JSON_UNESCAPED_UNICODE)); // Отправляем сообщение с текстом обращения $messagePayload = [ "role" => "user", "content" => "ТЕКСТ ОБРАЩЕНИЯ: " . $content ]; $messageJson = json_encode($messagePayload, JSON_UNESCAPED_UNICODE); if ($messageJson === false) { logMessage("[ERROR] ❌ Ошибка кодирования JSON для сообщений: " . json_last_error_msg()); return null; } $curl = curl_init(); curl_setopt_array($curl, [ //CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/messages", CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/messages", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $messageJson, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $messageResponse = curl_exec($curl); curl_close($curl); $messageData = json_decode($messageResponse, true); if (!$messageData || !isset($messageData['id'])) { logMessage("[ERROR] ❌ Ошибка при отправке сообщения в тред. Ответ: " . $messageResponse); return null; } logMessage("[INFO] ✅ Сообщение успешно добавлено в тред."); // Формируем payload для запуска Run $payload = [ "assistant_id" => $assistantId, "instructions" => "Извлеки ключевые параметры обращения и представь их в ЧЁТКОМ JSON-формате. Верни ТОЛЬКО JSON, без пояснений. СТРОГО JSON,\n\n" . "{\n" . " \"category\": \"Определи тип спора\",\n" . " \"articles\": [\"Определи применимые статьи закона\"],\n" . " \"facts_short\": \"Суть спора (одно предложение)\",\n" . " \"facts_full\": \"Развернутый анализ (до 600 символов)\",\n" . " \"claim_amount\": \"Извлеки сумму иска\",\n" . " \"document_type\": \"Определи вид документа\",\n" . " \"applicant_name\": \"Определи истца\",\n" . " \"document_client_name\": \"Определи ответчика\"\n" . "}\n\n" . "Если информация отсутствует, пиши `null`, но не оставляй поле пустым.", "tool_resources" => [ "file_search" => [ "vector_store_ids" => [$vectorStoreId] ] ] ]; $payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE); if ($payloadJson === false) { logMessage("[ERROR] ❌ Ошибка кодирования JSON: " . json_last_error_msg()); return null; } // Отправляем запрос на запуск Run $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/runs", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payloadJson, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $response = curl_exec($curl); curl_close($curl); $structuredData = json_decode($response, true); if (!$structuredData || !isset($structuredData['id'])) { logMessage("[ERROR] ❌ Ошибка запуска Run. Ответ: " . $response); return null; } $runId = $structuredData['id']; logMessage("[INFO] 🔄 GPT-4 начал обработку запроса. run_id: $runId"); // Ожидаем завершения обработки if (!waitForRunCompletion($threadId, $runId)) { return null; } // Запрашиваем сообщения (финальный ответ) $finalResponse = fetchThreadMessages($threadId); if (!$finalResponse || !isset($finalResponse['data']) || empty($finalResponse['data'])) { logMessage("[ERROR] ❌ Ошибка парсинга финального ответа. Ответ: " . json_encode($finalResponse, JSON_UNESCAPED_UNICODE)); return null; } // Ищем сообщение от ассистента $assistantMessage = null; foreach ($finalResponse['data'] as $message) { if ($message['role'] === 'assistant' && isset($message['content'][0]['text']['value'])) { $assistantMessage = $message; break; } } if (!$assistantMessage) { logMessage("[ERROR] ❌ Нет ответа от ассистента в треде. Полный ответ: " . json_encode($finalResponse, JSON_UNESCAPED_UNICODE)); return null; } $rawContent = $assistantMessage['content'][0]['text']['value']; logMessage("[INFO] 📜 Сырой контент из ответа: " . $rawContent); // Очищаем JSON от ```json ... ``` if (preg_match('/```json\s*(.*?)\s*```/s', $rawContent, $matches)) { $rawContent = $matches[1]; } else { logMessage("[ERROR] ❌ JSON не найден в формате ```json ... ```. Сырой контент: " . $rawContent); return null; } // Парсим JSON $parsedJson = json_decode($rawContent, true); if ($parsedJson === null) { logMessage("[ERROR] ❌ Ошибка декодирования JSON: " . json_last_error_msg() . ". Сырой контент: " . $rawContent); return null; } logMessage("[INFO] ✅ Успешно декодирован JSON: " . json_encode($parsedJson, JSON_UNESCAPED_UNICODE)); // Проверяем критические поля if (!isset($parsedJson['category']) || $parsedJson['category'] === '' || $parsedJson['category'] === null || !isset($parsedJson['facts_short']) || $parsedJson['facts_short'] === '' || $parsedJson['facts_short'] === null || !isset($parsedJson['facts_full']) || $parsedJson['facts_full'] === '' || $parsedJson['facts_full'] === null) { logMessage("[WARNING] ⚠️ `category`, `facts_short` или `facts_full` отсутствуют или пусты! Отправляем повторный запрос..."); return extractCaseDetailsWithGPT($threadId, $assistantId, $vectorStoreId, "Некоторые ключевые параметры (категория спора, краткие факты, полный анализ) отсутствуют или пусты. Уточни и исправь JSON, добавив недостающие значения."); } return $parsedJson; } */ /* // ✅ Функция ожидания завершения Run function waitForRunCompletion($threadId, $runId) { $maxWaitTime = 180; $waitTime = 0; $sleepInterval = 3; while ($waitTime < $maxWaitTime) { sleep($sleepInterval); $waitTime += $sleepInterval; if ($waitTime > 60) { $sleepInterval = 5; } $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/runs/$runId", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $statusResponse = curl_exec($curl); curl_close($curl); $statusData = json_decode($statusResponse, true); if (isset($statusData['status']) && $statusData['status'] === 'completed') { logMessage("[INFO] ✅ GPT-4 завершил обработку запроса."); return true; } } logMessage("❌ GPT-4 не завершил обработку за $maxWaitTime секунд."); return false; } // ✅ Функция получения сообщений из треда function fetchThreadMessages($threadId) { $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/messages", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $response = curl_exec($curl); curl_close($curl); return json_decode($response, true); } */ // ✅ Функция ожидания завершения Run function waitForRunCompletion($threadId, $runId) { $maxWaitTime = 300; $waitTime = 0; $sleepInterval = 3; while ($waitTime < $maxWaitTime) { sleep($sleepInterval); $waitTime += $sleepInterval; if ($waitTime > 60) { $sleepInterval = 5; } $curl = curl_init(); curl_setopt_array($curl, [ //CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/runs/$runId", CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/runs/$runId", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $statusResponse = curl_exec($curl); curl_close($curl); $statusData = json_decode($statusResponse, true); if (isset($statusData['status']) && $statusData['status'] === 'completed') { logMessage("[INFO] ✅ GPT-4 завершил обработку запроса."); return true; } } logMessage("❌ GPT-4 не завершил обработку за $maxWaitTime секунд."); return false; } // ✅ Функция получения сообщений из треда function fetchThreadMessages($threadId) { $curl = curl_init(); curl_setopt_array($curl, [ //CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/messages", CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/messages", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $response = curl_exec($curl); curl_close($curl); return json_decode($response, true); } function prepareEmbeddingForRefinedSearch($text) { logMessage("🧠 Подготовка эмбеддингов для уточнённого поиска..."); $embedding = getTextEmbedding($text); logMessage("📡 Эмбеддинги получены:\n" . json_encode($embedding, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); $normalize = function ($vector) { if (!is_array($vector) || empty($vector)) { return null; } $sumSquares = array_reduce($vector, function($carry, $val) { return $carry + $val * $val; }, 0); $magnitude = sqrt($sumSquares); if ($magnitude == 0) { return null; } return array_map(function($x) use ($magnitude) { return $x / $magnitude; }, $vector); }; return [ 'embedding_2048' => isset($embedding['embedding_2048']) ? $normalize($embedding['embedding_2048']) : null, 'embedding_1024' => isset($embedding['embedding_1024']) ? $normalize($embedding['embedding_1024']) : null ]; } // олд function extractCaseDetailsWithGPT($threadId, $assistantId, $vectorStoreId, $content) { logMessage("[INFO] 📌 Формируем текст запроса для GPT-4."); if (!$vectorStoreId) { logMessage("[ERROR] ❌ Ошибка: Нет доступного `Vector Store ID`!"); return null; } if (!$threadId) { logMessage("[ERROR] ❌ Ошибка: Некорректный `Thread ID`!"); return null; } if (!$content) { logMessage("[ERROR] ❌ Ошибка: Пустое содержание обращения!"); return null; } logMessage("[INFO] 📌 Отправляем текст в GPT-4: " . json_encode($content, JSON_UNESCAPED_UNICODE)); // ✅ Отправляем сообщение с текстом обращения (заменяем `messages`) $messagePayload = [ "role" => "user", "content" => "Все документы для анализа находятся в Vector Store ID: $vectorStoreId.\n" . "Все необходимые данные нужно извлечь из документов в Vector Store. Прочитай документы в PDF файлах. Если тект не измлекатеся то извлеки его с помощью OCR. Если OCR применить не удалось, то просмотри файлы и опиши их содержимое.\n\n" ]; $messageJson = json_encode($messagePayload, JSON_UNESCAPED_UNICODE); if ($messageJson === false) { logMessage("[ERROR] ❌ Ошибка кодирования JSON для сообщений: " . json_last_error_msg()); return null; } $curl = curl_init(); curl_setopt_array($curl, [ //CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/messages", CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/messages", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $messageJson, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $messageResponse = curl_exec($curl); curl_close($curl); $messageData = json_decode($messageResponse, true); if (!$messageData || !isset($messageData['id'])) { logMessage("[ERROR] ❌ Ошибка при отправке сообщения в тред. Ответ: " . $messageResponse); return null; } logMessage("[INFO] ✅ Сообщение успешно добавлено в тред."); // ✅ Формируем payload для запуска Run /* $payload = [ "assistant_id" => $assistantId, "instructions" => "Извлеки ключевые параметры обращения и представь их в ЧЁТКОМ JSON-формате. Верни ТОЛЬКО JSON, без пояснений.\n\n" . "{\n" . " \"category\": \"Определи тип спора\",\n" . " \"articles\": [\"Определи применимые статьи закона\"],\n" . " \"facts_short\": \"Суть спора (одно предложение)\",\n" . " \"facts_full\": \"Развернутый анализ (до 600 символов)\",\n" . " \"claim_amount\": \"Извлеки сумму иска\",\n" . " \"document_type\": \"Определи вид документа\",\n" . " \"applicant_name\": \"Определи истца\",\n" . " \"document_client_name\": \"Определи ответчика\"\n" . "}\n\n" . "Если информация отсутствует, пиши `null`, но не оставляй поле пустым.", "tool_resources" => [ "file_search" => [ "vector_store_ids" => [$vectorStoreId] ] ] ]; */ $payload = [ "assistant_id" => $assistantId, "instructions" => "Ты — юридический аналитик. Проанализируй документы из Vector Store и верни результат в ЧЁТКОМ JSON-формате.\n" . "Верни ТОЛЬКО JSON, без пояснений, строго по шаблону:\n\n" . "{\n" . " \"category\": \"Тип спора (например: защита прав потребителей)\",\n" . " \"articles\": [\"Список применимых статей закона\"],\n" . " \"facts_short\": \"Суть спора (одно предложение)\",\n" . " \"facts_full\": \"Развёрнутый анализ (до 600 символов)\",\n" . " \"claim_amount\": \"Сумма исковых требований в рублях (число)\",\n" . " \"document_type\": \"Тип документа (иск, претензия и т.п.)\",\n" . " \"applicant_name\": \"ФИО заявителя\",\n" . " \"document_client_name\": \"Название или ФИО ответчика\",\n" . " \"region\": \"Регион проживания заявителя\",\n" . " \"city\": \"Город (или населённый пункт)\",\n" . " \"claim_type\": \"Тип требований (например: возврат, компенсация, расторжение)\",\n" . " \"claim_reason\": \"Причина требований (например: неоказание услуги, нарушение условий)\",\n" . " \"evidence_summary\": [\n" . " {\"name\": \"Название документа\", \"content\": \"Краткое описание сути\"},\n" . " {\"name\": \"...\", \"content\": \"...\"}\n" . " ],\n" . " \"is_pretension_sent\": true,\n" . " \"has_contract\": true,\n" . " \"has_payment_proof\": true,\n" . " \"has_training_access\": true,\n" . " \"nsfw_alert\": false\n" . "}\n\n" . "Если информация отсутствует, указывай `null`, но не оставляй поле пустым.\n" . "Если данные спорные, делай наиболее вероятное предположение на основе документов.", "tool_resources" => [ "file_search" => [ "vector_store_ids" => [$vectorStoreId] ] ] ]; $payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE); if ($payloadJson === false) { logMessage("[ERROR] ❌ Ошибка кодирования JSON: " . json_last_error_msg()); return null; } // ✅ Отправляем запрос на запуск Run $curl = curl_init(); curl_setopt_array($curl, [ //CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/runs", CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/runs", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payloadJson, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $response = curl_exec($curl); curl_close($curl); $structuredData = json_decode($response, true); if (!$structuredData || !isset($structuredData['id'])) { logMessage("[ERROR] ❌ Ошибка запуска Run. Ответ: " . $response); return null; } $runId = $structuredData['id']; logMessage("[INFO] 🔄 GPT-4 начал обработку запроса. run_id: $runId"); // 🔄 Ожидаем завершения обработки (до 300 сек) $maxWaitTime = 300; $waitTime = 0; $sleepInterval = 3; while ($waitTime < $maxWaitTime) { sleep($sleepInterval); $waitTime += $sleepInterval; if ($waitTime > 60) { $sleepInterval = 5; } logMessage("[INFO] ⏳ GPT-4 всё ещё обрабатывает запрос... Оставшееся время: " . ($maxWaitTime - $waitTime) . " сек."); // ✅ Запрашиваем статус $curl = curl_init(); curl_setopt_array($curl, [ //CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/runs/$runId", CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/runs/$runId", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $statusResponse = curl_exec($curl); curl_close($curl); $statusData = json_decode($statusResponse, true); if (isset($statusData['status']) && $statusData['status'] === 'completed') { logMessage("[INFO] ✅ GPT-4 завершил обработку запроса."); break; } } if ($waitTime >= $maxWaitTime) { logMessage("[ERROR] ❌ GPT-4 не завершил обработку за $maxWaitTime секунд."); return null; } // ✅ Запрашиваем сообщения (финальный ответ) $curl = curl_init(); curl_setopt_array($curl, [ //CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/messages", CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/messages", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $finalResponse = curl_exec($curl); curl_close($curl); $finalData = json_decode($finalResponse, true); if (!$finalData || !isset($finalData['data'][0]['content'])) { logMessage("[ERROR] ❌ Ошибка парсинга финального ответа. Ответ: " . $finalResponse); return null; } logMessage("[INFO] ✅ Полученный JSON от GPT-4: " . json_encode($finalData, JSON_UNESCAPED_UNICODE)); // ✅ Парсим и проверяем JSON $parsedJson = extractCleanJsonFromGPT($finalData['data'][0]['content']); // $parsedJson = json_decode($finalData['data'][0]['content'], true); // Функция: проверка, считается ли поле "пустым" function isEmptyGPTField($value) { return !isset($value) || $value === null || trim($value) === '' || $value === 'null'; } if (!is_array($parsedJson)) { logMessage("[ERROR] ❌ Ответ GPT-4 не содержит корректный JSON."); return null; } // Проверим ключевые поля $missingFields = []; foreach (['category', 'facts_short', 'facts_full'] as $key) { if (!array_key_exists($key, $parsedJson) || isEmptyGPTField($parsedJson[$key])) { $missingFields[] = $key; } } // Если какие-то поля действительно пустые – повторный запрос if (!empty($missingFields)) { logMessage("[WARNING] ⚠️ Не заполнены ключевые поля: " . implode(', ', $missingFields) . ". Отправляем повторный запрос..."); return extractCaseDetailsWithGPT( $threadId, $assistantId, $vectorStoreId, "Некоторые ключевые параметры (" . implode(', ', $missingFields) . ") не были указаны. Уточни и исправь JSON, добавив недостающие значения." ); } return [ "json_data" => json_decode($finalData['data'][0]['content'], true) ?? [], "text_data" => $finalData['data'][0]['content'] ?? '' ]; } //function analyzeDocumentWithAssistantStream($threadId, $assistantId, $vectorStoreId, $fileId, $content, $foundCases, $caseId) function analyzeDocumentWithAssistantStream($threadId, $assistantId, $vectorStoreId, $fileId, $parsedJson, $foundCases, $casedId) { // Логируем файлы из Vector Store перед анализом // logVectorStoreFiles($vectorStoreId); // <-- Вставляем сюда вызов функции // checkFileStatus($vectorStoreId); // Проверяем статус файлов logMessage("🔹 Начинаем финальный анализ. Thread ID: $threadId, Vector Store ID: $vectorStoreId"); // ✅ Загружаем файлы судебных решений $loadedCasesDescription = ""; $newFileIds = []; foreach ($foundCases as $case) { $caseId = str_replace("/", "-", isset($case["case_id"]) ? $case["case_id"] : "Неизвестный ID"); $court = isset($case["court"]) ? $case["court"] : "Неизвестный суд"; $decision = isset($case["court_decision"]) ? $case["court_decision"] : "Текст решения отсутствует"; $filePath = "/var/www/fastuser/data/www/crm.clientright.ru/aiassist/temp/case_$caseId.txt"; file_put_contents($filePath, "Дело ID: $caseId\nСуд: $court\n\n$decision"); $fileOpenAIId = uploadFileToOpenAI($filePath); if (!$fileOpenAIId) { logMessage("❌ Ошибка загрузки файла $filePath в OpenAI."); continue; } $newFileIds[] = $fileOpenAIId; $loadedCasesDescription .= "- Дело ID: $caseId (суд: $court)\n"; } /* $loadedCasesDescription = ""; $newFileIds = []; foreach ($foundCases as $case) { $caseId = str_replace("/", "-", isset($case["case_id"]) ? $case["case_id"] : "Неизвестный ID"); $court = isset($case["court"]) ? $case["court"] : "Неизвестный суд"; $decision = isset($case["court_decision"]) ? $case["court_decision"] : "Текст решения отсутствует"; $filePath = "/var/www/fastuser/data/www/crm.clientright.ru/aiassist/temp/case_$caseId.txt"; file_put_contents($filePath, "Дело ID: $caseId\nСуд: $court\n\n$decision"); $fileOpenAIId = uploadFileToOpenAI($filePath); $loadedCasesDescription .= "- Дело ID: $caseId (суд: $court)\n"; if (!$fileOpenAIId) { logMessage("❌ Ошибка загрузки файла $filePath в OpenAI."); continue; } $newFileIds[] = $fileOpenAIId; } */ if (empty($newFileIds)) { logMessage("❌ Ошибка: Не удалось загрузить ни одно судебное решение!"); return null; } // ✅ Дозагружаем файлы в Vector Store foreach ($newFileIds as $newFileId) { if (!addFileToVectorStore($vectorStoreId, $newFileId)) { logMessage("❌ Ошибка добавления файла $newFileId в Vector Store!"); return null; } } logMessage("✅ Файлы добавлены в Vector Store ID: $vectorStoreId"); // ✅ Ожидаем 2 минуты для индексации logMessage("⏳ Ожидаем 2 минуты, пока `Vector Store` индексируется..."); sleep(120); // ✅ Проверяем статус индексации $vectorStoreStatus = getVectorStoreStatus($vectorStoreId); if ($vectorStoreStatus !== "ready") { logMessage("⚠️ Vector Store не завершил индексацию, но продолжаем анализ."); } // ✅ Формируем промпт if (!$parsedJson || !is_array($parsedJson)) { logMessage("❌ Ошибка: parsedJson пуст или некорректен!"); die("Ошибка: некорректный ответ GPT-4 (parsedJson)."); } if (!empty($loadedCasesDescription)) { $loadedCasesText = "📚 В Vector Store загружены судебные решения:\n$loadedCasesDescription\nИспользуй их для анализа судебной практики, укажи, какие из них релевантны и почему."; } else { $loadedCasesText = "📚 В Vector Store могут содержаться судебные решения. Используй их при анализе, если найдёшь релевантные."; } $userMessage = buildReportPromptFromJson($parsedJson, $vectorStoreId, $loadedCasesText); /* $userMessage = "🔹 Этап 1: Анализ документов по обращению в Клиентправ\n\n" . "Все документы для анализа находятся в Vector Store ID: $vectorStoreId.\n" . "Текст OCR не предоставлен напрямую — все необходимые данные нужно извлечь из документов в Vector Store.\n\n" . "📌 Выполни следующее:\n" . "1️⃣ Найди все документы, относящиеся к делу заявителя (исковые, договор, чеки, претензии и пр.). Исключи из анализа судебные акты (`case_*.txt`).\n" . "2️⃣ Для каждого документа:\n" . " • Укажи его название или тип (если доступно)\n" . " • Есть ли читаемый текст? (если нет — отметь, что требуется OCR)\n" . " • Выведи 200 первых знаков (если доступно)\n\n" . "📋 Извлеки обобщённую информацию:\n" . "• ФИО истца и регион (если указано)\n" . "• Ответчика (юрлицо, ИП, госорган — по возможности уточни)\n" . "• Суть спора (в 2–3 предложениях)\n" . "• Сумма исковых требований (если можно установить)\n" . "• Какие ключевые документы отсутствуют, повреждены или не читаются\n\n" . "❗ Не анализируй судебные решения на этом этапе. Только документы по конкретному делу заявителя."; */ logMessage("📡 Финальный промпт для GPT-4:\n" . $userMessage); // ✅ Отправляем сообщение в тред перед `run` $messagePayload = [ "role" => "user", "content" => $userMessage ]; $messageJson = json_encode($messagePayload, JSON_UNESCAPED_UNICODE); if ($messageJson === false) { logMessage("❌ Ошибка кодирования JSON: " . json_last_error_msg()); return null; } $curl = curl_init(); curl_setopt_array($curl, [ // CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/messages", CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/messages", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $messageJson, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $messageResponse = curl_exec($curl); curl_close($curl); $messageData = json_decode($messageResponse, true); if (!$messageData || !isset($messageData['id'])) { logMessage("❌ Ошибка при отправке сообщения в тред. Ответ: " . $messageResponse); return null; } logMessage("[INFO] ✅ Сообщение успешно добавлено в тред."); // ✅ Создаём `Run` $payload = [ "assistant_id" => $assistantId, "tool_resources" => [ "file_search" => [ "vector_store_ids" => [$vectorStoreId] ] ] ]; $payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE); if ($payloadJson === false) { logMessage("❌ Ошибка кодирования JSON: " . json_last_error_msg()); return null; } // ✅ Отправляем запрос на запуск `Run` $curl = curl_init(); curl_setopt_array($curl, [ //CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/runs", CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/runs", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payloadJson, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $response = curl_exec($curl); curl_close($curl); $structuredData = json_decode($response, true); if (!$structuredData || !isset($structuredData['id'])) { logMessage("❌ Ошибка запуска Run. Ответ: " . $response); return null; } $runId = $structuredData['id']; logMessage("[INFO] 🔄 GPT-4 начал обработку запроса. run_id: $runId"); // 🔄 Ожидаем завершения обработки if (!waitForRunCompletion($threadId, $runId)) { return null; } // ✅ Запрашиваем финальный ответ return fetchThreadMessages($threadId); } //олд /* function analyzeDocumentWithAssistantStream($threadId, $assistantId, $vectorStoreId, $fileId, $content, $foundCases, $casedId) { //logVectorStoreFiles($vectorStoreId); // Выводим информацию о всех файлах checkFileStatus($vectorStoreId); // Проверяем статус файлов logMessage("🔹 Начинаем финальный анализ. Thread ID: $threadId, Vector Store ID: $vectorStoreId"); // ✅ Загружаем файлы судебных решений $newFileIds = []; foreach ($foundCases as $case) { $caseId = str_replace("/", "-", isset($case["case_id"]) ? $case["case_id"] : "Неизвестный ID"); $court = isset($case["court"]) ? $case["court"] : "Неизвестный суд"; $decision = isset($case["court_decision"]) ? $case["court_decision"] : "Текст решения отсутствует"; $filePath = "/var/www/fastuser/data/www/crm.clientright.ru/aiassist/temp/case_$caseId.txt"; file_put_contents($filePath, "Дело ID: $caseId\nСуд: $court\n\n$decision"); $fileOpenAIId = uploadFileToOpenAI($filePath); if (!$fileOpenAIId) { logMessage("❌ Ошибка загрузки файла $filePath в OpenAI."); continue; } $newFileIds[] = $fileOpenAIId; } if (empty($newFileIds)) { logMessage("❌ Ошибка: Не удалось загрузить ни одно судебное решение!"); return null; } // ✅ Дозагружаем файлы в Vector Store foreach ($newFileIds as $newFileId) { if (!addFileToVectorStore($vectorStoreId, $newFileId)) { logMessage("❌ Ошибка добавления файла $newFileId в Vector Store!"); return null; } } logMessage("✅ Файлы добавлены в Vector Store ID: $vectorStoreId"); // ✅ Ожидаем 2 минуты для индексации logMessage("⏳ Ожидаем 2 минуты, пока `Vector Store` индексируется..."); sleep(120); // ✅ Проверяем статус индексации $vectorStoreStatus = getVectorStoreStatus($vectorStoreId); if ($vectorStoreStatus !== "ready") { logMessage("⚠️ Vector Store не завершил индексацию, но продолжаем анализ."); } $userMessage = "🔹 Этап 1: Анализ документов по обращению в Клиентправ\n\n" . "Все документы находятся в Vector Store ID: $vectorStoreId.\n" . "Документы представлены в различных форматах, включая PDF и изображения. Извлеки содержимое всех файлов в Vector Store, включая текст и изображения (с помощью OCR, если требуется).\n\n" . "📌 Выполни следующее:\n" . "1️⃣ Найди все документы, относящиеся к делу заявителя (исковые, договор, чеки, претензии и пр.). Исключи из анализа судебные акты (`case_*.txt`).\n" . "2️⃣ Для каждого документа, извлечённого из Vector Store:\n" . " • Укажи его название или тип (если доступно)\n" . " • Есть ли читаемый текст? (если нет — отметь, что требуется OCR)\n" . " • Если документ является изображением в PDF (например, скан чека, договора, скриншот), опиши, что видно, и извлеки текст через OCR, если это возможно\n\n" . "📋 Извлеки обобщённую информацию:\n" . "• ФИО истца и регион (если указано)\n" . "• Ответчика (юрлицо, ИП, госорган — по возможности уточни)\n" . "• Суть спора (в 2–3 предложениях)\n" . "• Сумма исковых требований (если можно установить)\n" . "• Какие ключевые документы отсутствуют, повреждены или не читаются\n\n" . "❗ Не анализируй судебные решения на этом этапе. Только документы по конкретному делу заявителя."; logMessage("📡 Финальный промпт для GPT-4:\n" . $userMessage); // ✅ Отправляем сообщение в тред перед `run` $messagePayload = [ "role" => "user", "content" => $userMessage ]; $messageJson = json_encode($messagePayload, JSON_UNESCAPED_UNICODE); if ($messageJson === false) { logMessage("❌ Ошибка кодирования JSON: " . json_last_error_msg()); return null; } logMessage("📤 Что мы отправляем в GPT:"); logMessage("📄 OCR / Content:\n" . mb_substr($content, 0, 2000, 'UTF-8') . (strlen($content) > 2000 ? "\n... (обрезано)" : "")); logMessage("📁 Загруженные судебные решения:"); foreach ($foundCases as $case) { $id = $case['case_id'] ?? '???'; $court = $case['court'] ?? 'не указан'; $text = mb_substr(($case['court_decision'] ?? ''), 0, 200, 'UTF-8'); logMessage("- 📌 Дело: $id | Суд: $court | Фрагмент: $text..."); } logMessage("📚 Vector Store ID: $vectorStoreId"); logMessage("📨 Полный промпт (ссылки, задачи, всё):\n" . $userMessage); $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/messages", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $messageJson, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $messageResponse = curl_exec($curl); curl_close($curl); $messageData = json_decode($messageResponse, true); if (!$messageData || !isset($messageData['id'])) { logMessage("❌ Ошибка при отправке сообщения в тред. Ответ: " . $messageResponse); return null; } logMessage("[INFO] ✅ Сообщение успешно добавлено в тред."); // ✅ Создаём `Run` $payload = [ "assistant_id" => $assistantId, "tool_resources" => [ "file_search" => [ "vector_store_ids" => [$vectorStoreId] ] ] ]; $payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE); if ($payloadJson === false) { logMessage("❌ Ошибка кодирования JSON: " . json_last_error_msg()); return null; } // ✅ Отправляем запрос на запуск `Run` $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/runs", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payloadJson, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $response = curl_exec($curl); curl_close($curl); $structuredData = json_decode($response, true); if (!$structuredData || !isset($structuredData['id'])) { logMessage("❌ Ошибка запуска Run. Ответ: " . $response); return null; } $runId = $structuredData['id']; logMessage("[INFO] 🔄 GPT-4 начал обработку запроса. run_id: $runId"); // 🔄 Ожидаем завершения обработки if (!waitForRunCompletion($threadId, $runId)) { return null; } // ✅ Запрашиваем финальный ответ return fetchThreadMessages($threadId); } */ /* $userMessage = "🔹 Отчет об анализе обращения в Клиентправ\n\n" . "📜 **Текст обращения и приложенные документы (OCR-распознанный текст из PDF):**\n" . "\"$content\"\n\n" . "⚖ **Дополнительно загруженные документы в Vector Store (включая судебные акты):**\n" . "- Дозагружены в Vector Store ID: $vectorStoreId.\n\n" . "📢 **Задача для GPT-4:**\n" . "1️⃣ **Проанализируй ВСЕ документы (из `$content` и `$vectorStoreId`).**\n" . " - Если документ уже есть в `$content`, используй его текст.\n" . " - Если документ есть только в Vector Store, проанализируй его содержимое отдельно.\n" . " - Не дублируй информацию, если один и тот же документ встречается и в `$content`, и в Vector Store.\n\n" . "2️⃣ **Извлеки данные об истце и ответчике.**\n" . " - Укажи ФИО истца и его регион проживания.\n" . " - Определи ответчика (юридическое лицо, ИП или госорган).\n\n" . "3️⃣ **Определи сумму исковых требований.**\n" . " - Если сумма фигурирует в чеках или договорах, **подтверди её документами**.\n" . " - Если сумма не указана, укажи, какие документы нужны для уточнения.\n\n" . "4️⃣ **Анализ представленных доказательств (не включая судебные решения).**\n" . " - Перечисли все представленные документы (за исключением судебных решений).\n" . " - Для каждого укажи его содержание и значимость.\n" . " - Если текст не распознан, укажи, что требуется OCR или иной метод анализа.\n\n" . "5️⃣ **Применимые нормы права.**\n" . " - Приведи законы и статьи, регулирующие этот спор.\n" . " - Включи ссылки на ГК РФ и Закон о защите прав потребителей.\n\n" . "6️⃣ **Используй загруженные судебные решения из Vector Store как прецеденты.**\n" . " - **Судебные решения находятся в файлах `case_{номер_дела}.txt`.**\n" . " - **Они используются ТОЛЬКО как прецеденты**, не как доказательства по данному делу.\n" . " - Проанализируй их и выбери те, которые наиболее релевантны к данному спору.\n" . " - Укажи номер дела, суд, дату рассмотрения и результат.\n" . " - Объясни, почему суд принял то или иное решение и как это может повлиять на рассматриваемый случай.\n\n" . "7️⃣ **Разделяй документы по категориям.**\n" . " - **Документы по текущему делу:** договор, чеки, претензии и т. д.\n" . " - **Судебные акты:** файлы `case_{номер_дела}.txt`, которые используются только для анализа прецедентов.\n\n" . "8️⃣ **Риски и слабые места.**\n" . " - Укажи, какие слабые места есть в позиции заявителя.\n" . " - Например: отсутствие доказательств, частично оказанные услуги, спорные суммы.\n" . " - Если доказательств не хватает, укажи, что необходимо запросить.\n\n" . "9️⃣ **Прогноз вероятности успеха.**\n" . " - Укажи, с какой вероятностью суд удовлетворит иск (в %).\n" . " - Обоснуй, от чего зависит исход дела.\n\n" . "🔟 **Формирование процессуальных документов.**\n" . " - Подготовь ссылки на документы:\n" . " - 📄 [Отчет](https://crm.clientright.ru/docs/cases/$casedId/report.txt)\n" . " - 📄 [Претензия](https://crm.clientright.ru/docs/cases/$casedId/claim.docx)\n" . " - 📄 [Жалоба](https://crm.clientright.ru/docs/cases/$casedId/complaint.docx)\n" . " - 📄 [Иск](https://crm.clientright.ru/docs/cases/$casedId/lawsuit.docx)\n\n" . "📌 **ВАЖНО:**\n" . "- **Если документ уже есть в `$content`, не дублируй его анализ из Vector Store.**\n" . "- **Если в Vector Store есть документы, которых нет в `$content`, анализируй их.**\n" . "- **Судебные акты (файлы `case_{номер_дела}.txt`) используются ТОЛЬКО как прецеденты.**\n" . "- **Не включай судебные решения в доказательства по делу.**\n" . "- **Всегда проверяй, есть ли текст в документах (даже если он не загружен сразу).**\n" . "- **Приводи примеры судебных решений с номерами и анализом дела.**\n" . "- **Делай чёткие выводы: какие документы нужны, что доказывает истец, что может возразить ответчик.**\n"; */ // нью /* function analyzeDocumentWithAssistantStream($threadId, $assistantId, $vectorStoreId, $fileId, $content, $foundCases, $casedId) { logMessage("🔹 Начинаем финальный анализ. Thread ID: $threadId, Vector Store ID: $vectorStoreId"); // Загружаем файлы судебных решений $newFileIds = []; foreach ($foundCases as $case) { $caseIdSafe = str_replace("/", "-", $case["case_id"] ?? "Неизвестный ID"); $court = $case["court"] ?? "Неизвестный суд"; $decision = $case["court_decision"] ?? "Текст решения отсутствует"; $filePath = "/var/www/fastuser/data/www/crm.clientright.ru/aiassist/temp/case_$caseIdSafe.txt"; file_put_contents($filePath, "Дело ID: $caseIdSafe\nСуд: $court\n\n$decision"); $fileOpenAIId = uploadFileToOpenAI($filePath); if (!$fileOpenAIId) { logMessage("❌ Ошибка загрузки файла $filePath в OpenAI."); continue; } $newFileIds[] = $fileOpenAIId; } if (empty($newFileIds)) { logMessage("❌ Ошибка: Не удалось загрузить ни одно судебное решение!"); return null; } // Дозагружаем файлы в Vector Store foreach ($newFileIds as $newFileId) { if (!addFileToVectorStore($vectorStoreId, $newFileId)) { logMessage("❌ Ошибка добавления файла $newFileId в Vector Store!"); return null; } } logMessage("✅ Файлы добавлены в Vector Store ID: $vectorStoreId"); // Ожидаем индексацию logMessage("⏳ Ожидаем 2 минуты, пока `Vector Store` индексируется..."); sleep(120); $vectorStoreStatus = getVectorStoreStatus($vectorStoreId); if ($vectorStoreStatus !== "ready") { logMessage("⚠️ Vector Store не завершил индексацию, но продолжаем анализ."); } // Формируем промпт $userMessage = "🔹 Финальный анализ обращения в Клиентправ\n\n" . "📜 **Текст обращения и документы:**\n" . "\"$content\"\n\n" . "⚖ **Дополнительные документы в Vector Store:**\n" . "- ID: $vectorStoreId (включает судебные акты в формате `case_{номер_дела}.txt`).\n\n" . "📢 **Задача:**\n" . "Проанализируй ВСЕ документы из `$content` и `$vectorStoreId` и предоставь полный текстовый отчёт по пунктам ниже. " . "Не пиши 'требуется уточнение' или 'нужна ручная проверка' — извлекай данные сам из всех доступных файлов. " . "Если информация отсутствует, пиши 'не указано'. Ответ должен быть чётким, без лишних пояснений вне структуры.\n\n" . "1️⃣ **Данные об истце и ответчике:**\n" . "- ФИО истца и регион проживания.\n" . "- Название/ФИО ответчика и тип (юрлицо, ИП, госорган).\n\n" . "2️⃣ **Сумма исковых требований:**\n" . "- Укажи сумму и документ, где она указана.\n" . "- Если суммы нет, пиши 'не указано'.\n\n" . "3️⃣ **Анализ доказательств (кроме судебных решений):**\n" . "- Перечисли документы из `$content` и `$vectorStoreId` (кроме `case_*.txt`).\n" . "- Для каждого: название, краткое содержание, значимость.\n\n" . "4️⃣ **Применимые нормы права:**\n" . "- Укажи статьи из ГК РФ и Закона о защите прав потребителей, которые подходят.\n\n" . "5️⃣ **Судебные прецеденты:**\n" . "- Проанализируй файлы `case_{номер_дела}.txt` из `$vectorStoreId`.\n" . "- Для каждого: номер дела, суд, дата, результат, почему релевантно.\n" . "- Используй их ТОЛЬКО как прецеденты, а не доказательства.\n\n" . "6️⃣ **Риски и слабые места:**\n" . "- Укажи конкретные проблемы в позиции истца (например, отсутствие доказательств).\n\n" . "7️⃣ **Прогноз вероятности успеха:**\n" . "- Оцени в процентах на основе документов и прецедентов.\n" . "- Объясни, от чего зависит исход.\n\n" . "📌 **Инструкции:**\n" . "- Обрабатывай ВСЕ файлы из `$content` и `$vectorStoreId`. Не дублируй данные.\n" . "- Судебные акты (`case_*.txt`) — только для прецедентов.\n" . "- Если текст не читаем, пиши 'текст не распознан' в содержании документа.\n" . "- Отвечай строго по структуре, без лишних фраз."; logMessage("📡 Финальный промпт для GPT-4:\n" . $userMessage); // Отправляем сообщение в тред $messagePayload = [ "role" => "user", "content" => $userMessage ]; $messageJson = json_encode($messagePayload, JSON_UNESCAPED_UNICODE); if ($messageJson === false) { logMessage("❌ Ошибка кодирования JSON: " . json_last_error_msg()); return null; } $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/messages", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $messageJson, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $messageResponse = curl_exec($curl); curl_close($curl); $messageData = json_decode($messageResponse, true); if (!$messageData || !isset($messageData['id'])) { logMessage("❌ Ошибка при отправке сообщения в тред. Ответ: " . $messageResponse); return null; } logMessage("[INFO] ✅ Сообщение успешно добавлено в тред."); // Создаём Run $payload = [ "assistant_id" => $assistantId, "tool_resources" => [ "file_search" => [ "vector_store_ids" => [$vectorStoreId] ] ] ]; $payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE); if ($payloadJson === false) { logMessage("❌ Ошибка кодирования JSON: " . json_last_error_msg()); return null; } $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$threadId/runs", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payloadJson, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "Authorization: Bearer " . OPENAI_API_KEY, "OpenAI-Beta: assistants=v2" ] ]); $response = curl_exec($curl); curl_close($curl); $structuredData = json_decode($response, true); if (!$structuredData || !isset($structuredData['id'])) { logMessage("❌ Ошибка запуска Run. Ответ: " . $response); return null; } $runId = $structuredData['id']; logMessage("[INFO] 🔄 GPT-4 начал обработку запроса. run_id: $runId"); // Ожидаем завершения обработки if (!waitForRunCompletion($threadId, $runId)) { return null; } // Запрашиваем финальный ответ $finalResponse = fetchThreadMessages($threadId); if (!$finalResponse || !isset($finalResponse['data']) || empty($finalResponse['data'])) { logMessage("[ERROR] ❌ Ошибка парсинга финального ответа. Ответ: " . json_encode($finalResponse, JSON_UNESCAPED_UNICODE)); return null; } // Извлекаем текст из ответа ассистента $assistantMessage = null; foreach ($finalResponse['data'] as $message) { if ($message['role'] === 'assistant' && isset($message['content'][0]['text']['value'])) { $assistantMessage = $message; break; } } if (!$assistantMessage) { logMessage("[ERROR] ❌ Нет ответа от ассистента. Полный ответ: " . json_encode($finalResponse, JSON_UNESCAPED_UNICODE)); return null; } $finalText = $assistantMessage['content'][0]['text']['value']; logMessage("[INFO] ✅ Финальный текстовый отчёт:\n" . $finalText); return $finalText; } */ function analyzeDocumentWithKnowledgeBase($knowledgeThreadId, $documentThreadId) { logMessage("📡 Начало анализа документов (новый тред `$documentThreadId`, база знаний `$knowledgeThreadId`)"); $payload = json_encode([ "role" => "user", "content" => [ [ "type" => "text", "text" => "Проанализируй документы в этом `thread_id` ($documentThreadId), " . "используя законы из базы знаний (`thread_id` $knowledgeThreadId). " . "Отвечай исключительно на основе информации из базы знаний." ] ] ]); logMessage("📡 Отправляем запрос в API с `thread_id` базы знаний `$knowledgeThreadId` " . "и `thread_id` с новыми документами `$documentThreadId`"); logMessage("📄 JSON-запрос:\n" . $payload); $ch = curl_init(); curl_setopt_array($ch, [ //CURLOPT_URL => "https://api.proxyapi.ru/openai/v1/threads/$documentThreadId/messages", CURLOPT_URL => OPENAI_THREADS_API . "/$threadId/messages", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . OPENAI_API_KEY, 'Content-Type: application/json', "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 при анализе: $curlError"); die("❌ Ошибка cURL при анализе: $curlError\n"); } logMessage("📡 Ответ API (HTTP $httpCode): $response"); $decoded = json_decode($response, true); if ($httpCode !== 200 || !isset($decoded['data'])) { logMessage("❌ Ошибка анализа! API ответил: " . json_encode($decoded, JSON_UNESCAPED_UNICODE)); die("❌ Ошибка анализа! Ответ API: " . json_encode($decoded, JSON_UNESCAPED_UNICODE) . "\n"); } logMessage("✅ Анализ завершён! Получен ответ от ассистента."); return end($decoded['data'])['content']; // Получаем последний ответ ассистента } ?>