diff --git a/app/Containers/Dashboard/Tasks/AI/CallAiServiceForFileSelectionTask.php b/app/Containers/Dashboard/Tasks/AI/CallAiServiceForFileSelectionTask.php index 1dfe8ab..5b0f91e 100644 --- a/app/Containers/Dashboard/Tasks/AI/CallAiServiceForFileSelectionTask.php +++ b/app/Containers/Dashboard/Tasks/AI/CallAiServiceForFileSelectionTask.php @@ -20,13 +20,13 @@ class CallAiServiceForFileSelectionTask */ public function run(array $fragments): ?array { - Log::info('[CallAiServiceForFileSelectionTask] Начало LLM запроса', [ + Log::channel('ai')->info('Начало LLM запроса', [ 'fragments_count' => count($fragments), ]); $credential = $this->getCredentialTask->run('qwen'); if (!$credential) { - Log::error('[CallAiServiceForFileSelectionTask] API ключ не настроен', [ + Log::channel('ai')->error('API ключ не настроен', [ 'provider' => 'qwen', ]); return null; @@ -35,7 +35,7 @@ class CallAiServiceForFileSelectionTask $prompt = $this->buildPrompt($fragments); - Log::info('[CallAiServiceForFileSelectionTask] Отправка запроса к AI'); + Log::channel('ai')->info('Отправка запроса к AI'); try { $response = Http::timeout(30) // Таймаут 30 секунд @@ -52,7 +52,7 @@ class CallAiServiceForFileSelectionTask 'max_tokens' => 500, ]); - Log::info('[CallAiServiceForFileSelectionTask] Ответ от AI', [ + Log::channel('ai')->info('Ответ от AI', [ 'status' => $response->status(), 'successful' => $response->successful(), ]); @@ -61,19 +61,19 @@ class CallAiServiceForFileSelectionTask $result = $response->json(); $llmResponse = json_decode($result['choices'][0]['message']['content'], true); - Log::info('[CallAiServiceForFileSelectionTask] Распознан ответ', [ + Log::channel('ai')->info('Распознан ответ', [ 'main_file' => $llmResponse['main_file'] ?? null, ]); return $llmResponse; } else { - Log::error('[CallAiServiceForFileSelectionTask] Ошибка AI запроса', [ + Log::channel('ai')->error('Ошибка AI запроса', [ 'status' => $response->status(), 'body' => $response->body(), ]); } } catch (\Exception $e) { - Log::error('[CallAiServiceForFileSelectionTask] Исключение при запросе к AI', [ + Log::channel('ai')->error('Исключение при запросе к AI', [ 'message' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); diff --git a/app/Containers/Dashboard/Tasks/AI/CallAiServiceTask.php b/app/Containers/Dashboard/Tasks/AI/CallAiServiceTask.php index 438c567..f6077fd 100644 --- a/app/Containers/Dashboard/Tasks/AI/CallAiServiceTask.php +++ b/app/Containers/Dashboard/Tasks/AI/CallAiServiceTask.php @@ -23,14 +23,14 @@ class CallAiServiceTask public function run(string $text, Collection $categories): ?array { try { - Log::info('[CallAiServiceTask] Начало AI запроса', [ + Log::channel('ai')->info('Начало AI запроса', [ 'text_length' => strlen($text), 'categories_count' => $categories->count(), ]); $credential = $this->getCredentialTask->run('qwen'); if (!$credential) { - Log::error('[CallAiServiceTask] API ключ не настроен', [ + Log::channel('ai')->error('API ключ не настроен', [ 'provider' => 'qwen', ]); throw new \RuntimeException('AI API ключ не настроен'); @@ -43,7 +43,7 @@ class CallAiServiceTask $systemPrompt = $this->buildSystemPrompt($categoryList); - Log::info('[CallAiServiceTask] Отправка запроса к AI', [ + Log::channel('ai')->info('Отправка запроса к AI', [ 'url' => 'https://routerai.ru/api/v1/chat/completions', 'model' => 'qwen/qwen3.5-flash-02-23', ]); @@ -58,7 +58,7 @@ class CallAiServiceTask if ($response && $response->successful()) { return false; } - Log::warning('[CallAiServiceTask] Попытка не удалась, повтор...', [ + Log::channel('ai')->warning('Попытка не удалась, повтор...', [ 'exception' => $exception->getMessage(), ]); return true; @@ -75,7 +75,7 @@ class CallAiServiceTask 'max_tokens' => 2000, ]); - Log::info('[CallAiServiceTask] Ответ от AI', [ + Log::channel('ai')->info('Ответ от AI', [ 'status' => $response->status(), 'successful' => $response->successful(), ]); @@ -85,7 +85,7 @@ class CallAiServiceTask $content = $result['choices'][0]['message']['content'] ?? null; if (empty($content)) { - Log::error('[CallAiServiceTask] Пустой ответ от AI', [ + Log::channel('ai')->error('Пустой ответ от AI', [ 'response' => $result, ]); return null; @@ -94,14 +94,14 @@ class CallAiServiceTask $data = json_decode($content, true); if (json_last_error() !== JSON_ERROR_NONE) { - Log::error('[CallAiServiceTask] Ошибка парсинга JSON ответа', [ + Log::channel('ai')->error('Ошибка парсинга JSON ответа', [ 'error' => json_last_error_msg(), 'content' => substr($content, 0, 500), ]); return null; } - Log::info('[CallAiServiceTask] AI данные успешно распознаны', [ + Log::channel('ai')->info('AI данные успешно распознаны', [ 'title' => $data['title'] ?? 'N/A', 'has_body' => isset($data['body']), 'category_id' => $data['category_id'] ?? 'N/A', @@ -110,7 +110,7 @@ class CallAiServiceTask return $data; } - Log::error('[CallAiServiceTask] AI запрос не удался', [ + Log::channel('ai')->error('AI запрос не удался', [ 'status' => $response->status(), 'body' => $response->body(), 'headers' => $response->headers(), @@ -118,7 +118,7 @@ class CallAiServiceTask return null; } catch (\Exception $e) { - Log::error('[CallAiServiceTask] Критическая ошибка AI запроса', [ + Log::channel('ai')->error('Критическая ошибка AI запроса', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); diff --git a/app/Containers/Dashboard/Tasks/AI/ConvertDocToDocxTask.php b/app/Containers/Dashboard/Tasks/AI/ConvertDocToDocxTask.php index 610d776..0188a39 100644 --- a/app/Containers/Dashboard/Tasks/AI/ConvertDocToDocxTask.php +++ b/app/Containers/Dashboard/Tasks/AI/ConvertDocToDocxTask.php @@ -17,13 +17,13 @@ class ConvertDocToDocxTask */ public function run(UploadedFile $file): ?string { - Log::info('[ConvertDocToDocxTask] Начало конвертации', [ + Log::channel('ai')->info('Начало конвертации', [ 'file' => $file->getClientOriginalName(), 'extension' => $file->getClientOriginalExtension(), ]); if (strtolower($file->getClientOriginalExtension()) !== 'doc') { - Log::warning('[ConvertDocToDocxTask] Неверное расширение', ['extension' => $file->getClientOriginalExtension()]); + Log::channel('ai')->warning('Неверное расширение', ['extension' => $file->getClientOriginalExtension()]); return null; } @@ -32,7 +32,7 @@ class ConvertDocToDocxTask $absoluteOriginalPath = Storage::disk('local')->path($originalPath); if (!file_exists($absoluteOriginalPath)) { - Log::error('[ConvertDocToDocxTask] Файл не сохранен', ['path' => $absoluteOriginalPath]); + Log::channel('ai')->error('Файл не сохранен', ['path' => $absoluteOriginalPath]); return null; } @@ -50,7 +50,7 @@ class ConvertDocToDocxTask escapeshellarg($absoluteOriginalPath) ); - Log::info('[ConvertDocToDocxTask] Выполнение команды', ['command' => $command]); + Log::channel('ai')->info('Выполнение команды', ['command' => $command]); $output = shell_exec($command); @@ -63,7 +63,7 @@ class ConvertDocToDocxTask } if (!file_exists($docxPath)) { - Log::error('[ConvertDocToDocxTask] Конвертация не удалась', [ + Log::channel('ai')->error('Конвертация не удалась', [ 'file' => $file->getClientOriginalName(), 'output' => $output, 'expected_path' => $docxPath, @@ -78,7 +78,7 @@ class ConvertDocToDocxTask $relativeDocxPath = preg_replace('/\.doc$/i', '.docx', $originalPath); - Log::info('[ConvertDocToDocxTask] Конвертация успешна', ['result_path' => $relativeDocxPath]); + Log::channel('ai')->info('Конвертация успешна', ['result_path' => $relativeDocxPath]); return $relativeDocxPath; } diff --git a/app/Containers/Dashboard/Tasks/AI/ExtractTextFragmentTask.php b/app/Containers/Dashboard/Tasks/AI/ExtractTextFragmentTask.php index 858ffdb..dd950b2 100644 --- a/app/Containers/Dashboard/Tasks/AI/ExtractTextFragmentTask.php +++ b/app/Containers/Dashboard/Tasks/AI/ExtractTextFragmentTask.php @@ -13,7 +13,7 @@ class ExtractTextFragmentTask */ public function run(UploadedFile $file, int $maxLength = 300): string { - Log::info('[ExtractTextFragmentTask] Начало извлечения фрагмента', [ + Log::channel('ai')->info('Начало извлечения фрагмента', [ 'file' => $file->getClientOriginalName(), 'extension' => $file->getClientOriginalExtension(), ]); @@ -30,7 +30,7 @@ class ExtractTextFragmentTask return $this->extractFromDoc($file, $maxLength); } - Log::warning('[ExtractTextFragmentTask] Неизвестный формат', [ + Log::channel('ai')->warning('Неизвестный формат', [ 'extension' => $extension, ]); diff --git a/app/Containers/Dashboard/Tasks/AI/ExtractTextFromDocumentTask.php b/app/Containers/Dashboard/Tasks/AI/ExtractTextFromDocumentTask.php index d34ec5f..5610c75 100644 --- a/app/Containers/Dashboard/Tasks/AI/ExtractTextFromDocumentTask.php +++ b/app/Containers/Dashboard/Tasks/AI/ExtractTextFromDocumentTask.php @@ -23,7 +23,7 @@ class ExtractTextFromDocumentTask { $extension = strtolower($file->getClientOriginalExtension()); - Log::info('[ExtractTextFromDocumentTask] Начало извлечения текста', [ + Log::channel('ai')->info('Начало извлечения текста', [ 'file' => $file->getClientOriginalName(), 'extension' => $extension, 'size' => $file->getSize(), @@ -31,17 +31,17 @@ class ExtractTextFromDocumentTask // Если DOCX — парсим напрямую if ($extension === 'docx') { - Log::info('[ExtractTextFromDocumentTask] Обработка DOCX файла'); + Log::channel('ai')->info('Обработка DOCX файла'); return $this->extractFromDocx($file); } // Если DOC — конвертируем в DOCX, затем парсим if ($extension === 'doc') { - Log::info('[ExtractTextFromDocumentTask] Обработка DOC файла (требуется конвертация)'); + Log::channel('ai')->info('Обработка DOC файла (требуется конвертация)'); return $this->extractFromDoc($file); } - Log::warning('[ExtractTextFromDocumentTask] Неизвестный формат файла', [ + Log::channel('ai')->warning('Неизвестный формат файла', [ 'extension' => $extension, ]); @@ -53,13 +53,13 @@ class ExtractTextFromDocumentTask */ private function extractFromDocx(UploadedFile $file): ?string { - Log::info('[ExtractTextFromDocumentTask:extractFromDocx] Начало'); + Log::channel('ai')->info('Начало'); // Сохраняем во временную директорию $tempPath = $file->storeAs('temp', 'temp_doc_' . time() . '.docx', 'local'); $absoluteTempPath = Storage::disk('local')->path($tempPath); - Log::info('[ExtractTextFromDocumentTask:extractFromDocx] Файл сохранен', [ + Log::channel('ai')->info('Файл сохранен', [ 'path' => $tempPath, 'absolute_path' => $absoluteTempPath, ]); @@ -67,7 +67,7 @@ class ExtractTextFromDocumentTask // Парсим файл $extractedText = $this->parseDocxTask->run($absoluteTempPath); - Log::info('[ExtractTextFromDocumentTask:extractFromDocx] Результат парсинга', [ + Log::channel('ai')->info('Результат парсинга', [ 'text_length' => strlen($extractedText ?? ''), ]); @@ -82,19 +82,19 @@ class ExtractTextFromDocumentTask */ private function extractFromDoc(UploadedFile $file): ?string { - Log::info('[ExtractTextFromDocumentTask:extractFromDoc] Начало конвертации'); + Log::channel('ai')->info('Начало конвертации'); // Конвертируем DOC → DOCX $docxPath = $this->convertDocToDocxTask->run($file); if (!$docxPath) { - Log::error('[ExtractTextFromDocumentTask:extractFromDoc] Не удалось конвертировать DOC файл', [ + Log::channel('ai')->error('Не удалось конвертировать DOC файл', [ 'file' => $file->getClientOriginalName(), ]); return null; } - Log::info('[ExtractTextFromDocumentTask:extractFromDoc] Конвертация успешна', [ + Log::channel('ai')->info('Конвертация успешна', [ 'docx_path' => $docxPath, ]); @@ -104,7 +104,7 @@ class ExtractTextFromDocumentTask // Парсим конвертированный файл $extractedText = $this->parseDocxTask->run($absoluteDocxPath); - Log::info('[ExtractTextFromDocumentTask:extractFromDoc] Результат парсинга', [ + Log::channel('ai')->info('Результат парсинга', [ 'text_length' => strlen($extractedText ?? ''), ]); diff --git a/app/Containers/Dashboard/Tasks/AI/FindMainNewsFileTask.php b/app/Containers/Dashboard/Tasks/AI/FindMainNewsFileTask.php index c3613db..0d09056 100644 --- a/app/Containers/Dashboard/Tasks/AI/FindMainNewsFileTask.php +++ b/app/Containers/Dashboard/Tasks/AI/FindMainNewsFileTask.php @@ -26,7 +26,7 @@ class FindMainNewsFileTask */ public function run(Collection $files): ?UploadedFile { - Log::info('[FindMainNewsFileTask] Начало поиска основного файла', [ + Log::channel('ai')->info('Начало поиска основного файла', [ 'files_count' => $files->count(), 'files' => $files->map(function($f) { return $f->getClientOriginalName() . ' (' . $f->getClientOriginalExtension() . ')'; @@ -61,19 +61,19 @@ class FindMainNewsFileTask return false; }); - Log::info('[FindMainNewsFileTask] Найдено DOC/DOCX файлов', [ + Log::channel('ai')->info('Найдено DOC/DOCX файлов', [ 'count' => $docFiles->count(), 'files' => $docFiles->map(fn($f) => $f->getClientOriginalName())->toArray(), ]); if ($docFiles->isEmpty()) { - Log::warning('[FindMainNewsFileTask] Не найдено DOC/DOCX файлов'); + Log::channel('ai')->warning('Не найдено DOC/DOCX файлов'); return null; } // Если только один файл — используем его if ($docFiles->count() === 1) { - Log::info('[FindMainNewsFileTask] Найден один файл, используем его', [ + Log::channel('ai')->info('Найден один файл, используем его', [ 'file' => $docFiles->first()->getClientOriginalName(), ]); return $docFiles->first(); @@ -84,7 +84,7 @@ class FindMainNewsFileTask $filename = mb_strtolower($file->getClientOriginalName()); foreach (self::NEWS_KEYWORDS as $keyword) { if (str_contains($filename, $keyword)) { - Log::info('[FindMainNewsFileTask] Найден файл по ключевому слову', [ + Log::channel('ai')->info('Найден файл по ключевому слову', [ 'file' => $file->getClientOriginalName(), 'keyword' => $keyword, ]); @@ -93,7 +93,7 @@ class FindMainNewsFileTask } } - Log::info('[FindMainNewsFileTask] Не найдено файлов по ключевым словам, используем LLM'); + Log::channel('ai')->info('Не найдено файлов по ключевым словам, используем LLM'); // Если не нашли по ключевым словам — используем LLM return $this->findViaLLM($docFiles); @@ -104,7 +104,7 @@ class FindMainNewsFileTask */ private function findViaLLM(Collection $docFiles): ?UploadedFile { - Log::info('[FindMainNewsFileTask:findViaLLM] Начало LLM определения', [ + Log::channel('ai')->info('Начало LLM определения', [ 'files_count' => $docFiles->count(), ]); @@ -119,7 +119,7 @@ class FindMainNewsFileTask // Собираем фрагменты текста из каждого файла $fragments = []; foreach ($docFiles as $file) { - Log::info('[FindMainNewsFileTask:findViaLLM] Извлечение фрагмента', [ + Log::channel('ai')->info('Извлечение фрагмента', [ 'file' => $file->getClientOriginalName(), ]); @@ -131,11 +131,11 @@ class FindMainNewsFileTask } // Отправляем запрос к LLM - Log::info('[FindMainNewsFileTask:findViaLLM] Отправка запроса к LLM'); + Log::channel('ai')->info('Отправка запроса к LLM'); $llmResponse = app(CallAiServiceForFileSelectionTask::class)->run($fragments); if ($llmResponse && isset($llmResponse['main_file'])) { - Log::info('[FindMainNewsFileTask:findViaLLM] LLM вернула результат', [ + Log::channel('ai')->info('LLM вернула результат', [ 'main_file' => $llmResponse['main_file'], ]); @@ -147,7 +147,7 @@ class FindMainNewsFileTask } } - Log::warning('[FindMainNewsFileTask:findViaLLM] LLM не помогла, используем первый файл'); + Log::channel('ai')->warning('LLM не помогла, используем первый файл'); // Fallback — первый файл return $docFiles->first(); diff --git a/app/Containers/Dashboard/Tasks/AI/ParseDocxTask.php b/app/Containers/Dashboard/Tasks/AI/ParseDocxTask.php index e4cb803..b11e319 100755 --- a/app/Containers/Dashboard/Tasks/AI/ParseDocxTask.php +++ b/app/Containers/Dashboard/Tasks/AI/ParseDocxTask.php @@ -14,7 +14,7 @@ class ParseDocxTask { // 1. Проверяем, существует ли физически файл по этому пути if (!file_exists($filePath)) { - Log::error("[ParseDocxTask] Файл не найден по пути: {$filePath}"); + Log::channel('ai')->error('Файл не найден по пути: {$filePath}"); return "ОШИБКА ДЕБАГА: Файл не найден на сервере."; } @@ -26,7 +26,7 @@ class ParseDocxTask // Если не true, значит произошла ошибка if ($res !== true) { $errorMsg = $this->getZipError($res); - Log::error("[ParseDocxTask] Ошибка ZipArchive: {$errorMsg} | Путь: {$filePath}"); + Log::channel('ai')->error('Ошибка ZipArchive: {$errorMsg} | Путь: {$filePath}"); // Возвращаем текст ошибки прямо на фронт, чтобы сразу увидеть причину! return "ОШИБКА ДЕБАГА ZipArchive: {$errorMsg}"; @@ -39,7 +39,7 @@ class ParseDocxTask $zip->close(); if ($xmlString === false) { - Log::error("[ParseDocxTask] Файл word/document.xml не найден внутри архива. Возможно, это не настоящий DOCX."); + Log::channel('ai')->error('Файл word/document.xml не найден внутри архива. Возможно, это не настоящий DOCX."); return "ОШИБКА ДЕБАГА: Внутри архива нет word/document.xml"; } @@ -49,7 +49,7 @@ class ParseDocxTask $text = strip_tags($text); return trim($text); } catch (\Exception $e) { - Log::error("[ParseDocxTask] Ошибка очистки тегов: " . $e->getMessage()); + Log::channel('ai')->error('Ошибка очистки тегов: " . $e->getMessage()); return "ОШИБКА ДЕБАГА при очистке текста."; } }