# Обновление истории чата
        history.append((user_message, bot_reply))
        chat_histories[user_id] = history

Степашка, [23.09.2024 17:26]
# Отправка ответа пользователю
        def tokenize(message):
            tokens = []
            pos = 0
            length = len(message)
            while pos < length:
                if message[pos] == '<':
                    # Это тег
                    end_tag_pos = message.find('>', pos)
                    if end_tag_pos == -1:
                        # Неполный тег, считаем остальное текстом
                        tokens.append(('text', message[pos:]))
                        break
                    else:
                        token_content = message[pos+1:end_tag_pos]
                        # Проверяем, является ли это закрывающим тегом
                        if token_content.startswith('/'):
                            tag_name = token_content[1:].split()[0]
                            tokens.append(('end_tag', tag_name, '<'+token_content+'>'))
                        else:
                            # Тег может содержать атрибуты
                            tag_name = token_content.split()[0]
                            tokens.append(('start_tag', tag_name, '<'+token_content+'>'))
                        pos = end_tag_pos + 1
                else:
                    # Это текст
                    next_tag_pos = message.find('<', pos)
                    if next_tag_pos == -1:
                        # Больше нет тегов
                        tokens.append(('text', message[pos:]))
                        break
                    else:
                        tokens.append(('text', message[pos:next_tag_pos]))
                        pos = next_tag_pos
            return tokens

        def generate_closing_tags(open_tags):
            closing_tags = ''
            for start_tag in reversed(open_tags):
                # Получаем имя тега из стартового тега
                tag_content = start_tag[1:-1].strip()
                if ' ' in tag_content:
                    tag_name = tag_content.split(' ',1)[0]
                else:
                    tag_name = tag_content
                closing_tags += '</{}>'.format(tag_name)
            return closing_tags

        async def send_large_message(message, update):
            MAX_MESSAGE_LENGTH = 4000

            tokens = tokenize(message)
            open_tags = []
            current_part = ''
            current_length = 0
            parts = []Степашка, [23.09.2024 17:26]
for token in tokens:
                if token[0] == 'start_tag':
                    tag_name = token[1]
                    tag_string = token[2]
                    token_length = len(tag_string)
                    if current_length + token_length > MAX_MESSAGE_LENGTH:
                        # Закрываем теги и начинаем новую часть
                        closing_tags = generate_closing_tags(open_tags)
                        current_part += closing_tags
                        parts.append(current_part)
                        current_part = ''
                        current_length = 0
                        # Открываем теги снова
                        opening_tags = ''.join(open_tags)
                        current_part += opening_tags
                        current_length += len(opening_tags)
                    current_part += tag_string
                    current_length += token_length
                    open_tags.append(tag_string)
                elif token[0] == 'end_tag':
                    tag_name = token[1]
                    tag_string = token[2]
                    token_length = len(tag_string)
                    if current_length + token_length > MAX_MESSAGE_LENGTH:
                        # Закрываем теги и начинаем новую часть
                        closing_tags = generate_closing_tags(open_tags)
                        current_part += closing_tags
                        parts.append(current_part)
                        current_part = ''
                        current_length = 0
                        # Открываем теги снова
                        opening_tags = ''.join(open_tags)
                        current_part += opening_tags
                        current_length += len(opening_tags)
                    current_part += tag_string
                    current_length += token_length
                    if open_tags:
                        open_tags.pop()
                elif token[0] == 'text':
                    text_content = token[1]
                    text_length = len(text_content)
                    pos = 0
                    while pos < text_length:
                        remaining_space = MAX_MESSAGE_LENGTH - current_length
                        if remaining_space <= 0:
                            # Закрываем теги и начинаем новую часть
                            closing_tags = generate_closing_tags(open_tags)
                            current_part += closing_tags
                            parts.append(current_part)
                            current_part = ''
                            current_length = 0
                            # Открываем теги снова
                            opening_tags = ''.join(open_tags)
                            current_part += opening_tags
                            current_length += len(opening_tags)
                            remaining_space = MAX_MESSAGE_LENGTH - current_length
                        take_length = min(remaining_space, text_length - pos)
                        current_part += text_content[pos:pos+take_length]
                        current_length += take_length
                        pos += take_length
                else:
                    pass

            # Закрываем оставшиеся открытые теги и добавляем последнюю часть
            if open_tags:
                closing_tags = generate_closing_tags(open_tags)
                current_part += closing_tags
            if current_part:
                parts.append(current_part)

            # Отправляем части сообщения
            for part in parts:
                await update.message.reply_text(part, parse_mode='HTML')
                
        send_bot_reply = markdown_to_telegram_html(bot_reply)

        await send_large_message(send_bot_reply, update)

    except Exception as e:
        logger.error(f"Ошибка при обработке сообщения: {e}", exc_info=True)
        await update.message.reply_text("Извините, произошла ошибка при обработке вашего запроса.", parse_mode='HTML')Степашка, [23.09.2024 17:26]
finally:
        # Останавливаем отправку индикатора
        processing = False
        await task  # Дожидаемся завершения задачи

# Команда /clear для сброса истории чата
async def clear_chat(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    user_id = update.effective_user.id
    
    # Проверка, разрешен ли доступ пользователю
    if user_id not in [item[0] for item in ALLOWED_USER_IDS]:
        await update.message.reply_text("Извините, у вас нет доступа к этому боту.")
        return
    
    chat_histories[user_id] = []
    await update.message.reply_text("Чат сброшен. Начнем с чистого листа!", parse_mode='HTML')

async def get_my_id(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    user_id = update.effective_user.id
    await update.message.reply_text(f"Ваш Telegram ID: {user_id}")

# Функция для добавления пользователя в ALLOWED_USER_IDS
async def add_user(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    # Проверяем, является ли пользователь администратором
    if update.effective_user.id != ADMIN_ID:
        await update.message.reply_text("Извините, у вас нет прав для выполнения этой команды.")
        return

    # Получаем ID пользователя и имя из аргументов команды
    args = context.args
    if len(args) < 2:
        await update.message.reply_text("Пожалуйста, используйте команду в формате /add user_id username")
        return

    try:
        user_id = int(args[0])
        username = ' '.join(args[1:])
        # Проверяем, есть ли уже пользователь в списке
        if any(user[0] == user_id for user in ALLOWED_USER_IDS):
            await update.message.reply_text(f"Пользователь с ID {user_id} уже имеет доступ.")
        else:
            ALLOWED_USER_IDS.append([user_id, username])
            await update.message.reply_text(f"Пользователь с ID {user_id} и именем {username} добавлен в список доступа.")
    except ValueError:
        await update.message.reply_text("Пожалуйста, введите корректный числовой ID пользователя.")

# Функция для удаления пользователя из ALLOWED_USER_IDS
async def remove_user(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    # Проверяем, является ли пользователь администратором
    if update.effective_user.id != ADMIN_ID:
        await update.message.reply_text("Извините, у вас нет прав для выполнения этой команды.")
        return

    # Получаем ID пользователя из аргументов команды
    args = context.args
    if len(args) != 1:
        await update.message.reply_text("Пожалуйста, используйте команду в формате /remove user_id")
        return

    try:
        user_id = int(args[0])
        # Ищем пользователя в списке и удаляем его
        for user in ALLOWED_USER_IDS:
            if user[0] == user_id:
                ALLOWED_USER_IDS.remove(user)
                await update.message.reply_text(f"Пользователь с ID {user[0]} и именем {user[1]} удалён из списка доступа.")
                break
        else:
            await update.message.reply_text(f"Пользователь с ID {user_id} не найден в списке доступа.")
    except ValueError:
        await update.message.reply_text("Пожалуйста, введите корректный числовой ID пользователя.")

# Функция для отображения списка разрешённых пользователей
async def list_users(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    # Проверяем, является ли пользователь администратором
    if update.effective_user.id != ADMIN_ID:
        await update.message.reply_text("Извините, у вас нет прав для выполнения этой команды.")
        return

    if ALLOWED_USER_IDS:
        users_list = "\n".join(f"ID: {user[0]}, Username: {user[1]}" for user in ALLOWED_USER_IDS)
        await update.message.reply_text(f"Список разрешённых пользователей:\n{users_list}")
    else:
        await update.message.reply_text("Список разрешённых пользователей пуст.")Степашка, [23.09.2024 17:26]
# (Необязательно) Функция для отображения помощи администратора
async def admin_help(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    # Проверяем, является ли пользователь администратором
    if update.effective_user.id != ADMIN_ID:
        await update.message.reply_text("Извините, у вас нет прав для выполнения этой команды.")
        return

    help_text = (
        "Доступные команды администратора:\n"
        "/add ID - добавить пользователя в список разрешённых\n"
        "/remove ID - удалить пользователя из списка разрешённых\n"
        "/list - показать список разрешённых пользователей"
    )
    await update.message.reply_text(help_text)

def main():
    # Замените 'YOUR_TELEGRAM_BOT_TOKEN' на токен вашего бота
    application = ApplicationBuilder().token(TOKEN).build()

    # Регистрируем обработчики команд администратора
    application.add_handler(CommandHandler("add", add_user))
    application.add_handler(CommandHandler("remove", remove_user))
    application.add_handler(CommandHandler("list", list_users))
    application.add_handler(CommandHandler("adminhelp", admin_help))

    # Регистрируем обработчики команд и сообщений
    application.add_handler(CommandHandler("start", start))
    application.add_handler(CommandHandler("clear", clear_chat))
    application.add_handler(CommandHandler("myid", get_my_id))
    message_handler = MessageHandler(filters.TEXT & ~filters.COMMAND, message_collector)
    application.add_handler(message_handler)

    # Запуск бота
    application.run_polling()

if name == 'main':
    main()