feat(logging): migrate AI tasks to ai channel

This commit is contained in:
F4ilji
2026-07-05 23:29:39 +05:00
parent 49dd578e50
commit cd9b682994
7 changed files with 51 additions and 51 deletions
@@ -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(),
]);
@@ -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(),
]);
@@ -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;
}
@@ -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,
]);
@@ -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 ?? ''),
]);
@@ -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();
@@ -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 "ОШИБКА ДЕБАГА при очистке текста.";
}
}