diff --git a/bot.py b/bot.py index f2784a9..209936c 100644 --- a/bot.py +++ b/bot.py @@ -964,17 +964,13 @@ async def handle_local_session_input(update: Update, text: str, session: LocalSe cleaned_output = clean_ansi_codes(session.output_buffer) cleaned_output = normalize_output(cleaned_output) - # Форматируем длинный вывод: первые 5 и последние 10 строк - formatted_output = format_long_output(cleaned_output.strip(), max_lines=15, head_lines=5, tail_lines=10) - if len(formatted_output) > 4000: - formatted_output = formatted_output[:4000] + "\n... (вывод обрезан)" + # Формируем полный вывод БЕЗ обрезки — send_long_message сам разобьёт + full_output = f"✅ *Результат:*\n\n" \ + f"```\n{session.command}\n```\n\n" \ + f"```\n{cleaned_output.strip()}\n```" - await update.message.reply_text( - f"✅ *Результат:*\n\n" - f"```\n{session.command}\n```\n\n" - f"```\n{formatted_output}\n```", - parse_mode="Markdown" - ) + # Отправляем длинный вывод с разбивкой на сообщения + await send_long_message(update, full_output, parse_mode="Markdown") local_session_manager.close_session(user_id) except Exception as e: diff --git a/bot/utils/formatters.py b/bot/utils/formatters.py index 4b1fb09..988f2a4 100644 --- a/bot/utils/formatters.py +++ b/bot/utils/formatters.py @@ -14,6 +14,25 @@ MAX_MESSAGE_LENGTH = 4096 # Максимальная длина сообщен RESERVED_FOR_HEADER = 20 # Резервируем место для "(N/N) " +def escape_code_block_content(text: str) -> str: + """ + Экранировать спецсимволы Markdown внутри блоков кода. + Нужно для случаев когда сообщение содержит ```блок кода``` и текст с Markdown. + Telegram пытается интерпретировать [text](url) внутри блока кода как ссылку. + """ + # Находим все блоки кода + parts = text.split("```") + result_parts = [] + + for i, part in enumerate(parts): + if i % 2 == 1: + # Внутри блока кода — экранируем [ и ] + part = part.replace('[', '\\[').replace(']', '\\]') + result_parts.append(part) + + return "```".join(result_parts) + + def escape_markdown(text: str) -> str: """ Экранирование специальных символов Markdown для Telegram API. @@ -227,16 +246,32 @@ async def send_long_message(update: Update, text: str, parse_mode: str = None, p # Начинаем с указанного сообщения for i in range(start_from, total): part, has_code, code_opened, code_closed = parts[i] - - # Определяем parse_mode для этого сообщения + + # Проверяем был ли блок кода открыт в предыдущем сообщении prev_closed = parts[i-1][3] if i > 0 else True + + # Определяем находимся ли внутри блока кода (между ``` и ```) in_code_block = not prev_closed or (code_opened and not code_closed) - actual_parse_mode = parse_mode if parse_mode and (has_code or in_code_block) else None - + + # Проверяем будем ли добавлять ``` к этому сообщению + will_add_opening = total > 1 and i > 0 and not prev_closed and not code_closed + will_add_closing = total > 1 and i < total - 1 and not code_closed + + # КЛЮЧЕВОЕ ИСПРАВЛЕНИЕ: + # Отключаем parse_mode если: + # 1. Это промежуточная часть блока кода (in_code_block=True, но нет ``` в этом сообщении) + # 2. Это сообщение содержит ``` (has_code=True) + # 3. Мы добавляем искусственные ``` (will_add_opening или will_add_closing) + if in_code_block or has_code or will_add_opening or will_add_closing: + actual_parse_mode = None + else: + # Обычный текст без блоков кода — используем Markdown + actual_parse_mode = parse_mode + # Логика работы с блоками кода между сообщениями if total > 1 and i > 0 and not prev_closed: part = "```\n" + part - + if total > 1 and i < total - 1 and not code_closed: part = part + "\n```" diff --git a/bot/utils/qwen_oauth.py b/bot/utils/qwen_oauth.py index 34913ca..239e7f9 100644 --- a/bot/utils/qwen_oauth.py +++ b/bot/utils/qwen_oauth.py @@ -4,6 +4,7 @@ Qwen OAuth 2.0 Device Flow клиент. Реализует авторизацию через Device Authorization Grant (RFC 8628). """ +import asyncio import os import json import hashlib