Keyboa: клавиатуры на максималках для ботов в Telegram

    Боты - одна из особенностей Telegram, сделавших мессенджер столь популярным. А его встроенные клавиатуры дают разработчикам большую свободу взаимодействия с пользователями.

    Keyboa помогает создавать встроенные клавиатуры любой сложности для ботов, разработанных на базе pyTelegramBotAPI.

    В этой статье рассмотрим базовые возможности модуля - создание клавиатур из разных наборов данных, автоматическое и ручное распределение кнопок по рядам, объединение нескольких клавиатур в одну. Научимся создавать сложные, динамические callback, сохраняя в них информацию о выборе пользователя.

    Статья рассчитана на тех, кто знает основы Telegram Bot API и хотя бы немного знаком с фреймворком pyTelegramBotAPI.

    Модуль требует > Python 3.5 и ставится через pip:

    pip install keyboa

    В официальной документации Telegram объект inline_keyboard определен как массив, состоящий из массивов кнопок (Array of Array of InlineKeyboardButton). То есть основной массив (список) - это клавиатура в целом, а его элементы (вложенные списки) - это ряды кнопок. Не переживайте, если определение кажется сложным - позже мы разберём его на простом примере.

    Предположим, что сам бот у нас уже настроен:

    import os
    from telebot import TeleBot
    from keyboa import keyboa_maker
    
    token = os.environ["TELEGRAM_BOT_TOKEN"]
    uid = os.environ["TELEGRAM_USER_ID"] 
    bot = TeleBot(token=token)

    Создаём клавиатуру

    Предположим, нам нужно отправить пользователю на выбор список фруктов.

    fruits = [
      "banana", "coconut", "orange",
      "peach", "apricot", "apple",
      "pineapple", "avocado", "melon"
    ]

    Создадим самую простую клавиатуру, в которой каждый элемент встанет на отдельный ряд:

    kb_fruits = keyboa_maker(items=fruits, copy_text_to_callback=True)

    Всё, что потребовалось - передать список в items. Оставить пустой сallback_data (ответную часть кнопки) мы не можем, ведь иначе не узнаем, что нажал пользователь. Поэтому добавляем текст каждой кнопки в её callback_data, устанавливая параметр copy_text_to_callback.

    Отправим сообщение пользователю:

    bot.send_message(
      chat_id=uid, reply_markup=kb_fruits,
      text="Please select one of the fruit:")

    Распределяем кнопки по рядам

    Разместить несколько кнопок в ряд можно любым из трёх способов.

    Указать количество кнопок в ряду

    Определите параметр items_in_row, чтобы задать количество кнопок в ряду. Их число должно быть от одного до восьми. Больше кнопок нам не позволит добавить сам Telegram.

    Создадим клавиатуру и отправим обновлённое сообщение:

    kb_fruits = keyboa_maker(items=fruits, copy_text_to_callback=True, items_in_row=3)
    
    bot.send_message(
      chat_id=uid, reply_markup=kb_fruits,
      text="Please select one of the fruit:")

    Использовать автоподбор

    Если клавиатура создается динамически, мы не всегда знаем, сколько в ней окажется кнопок. Чтобы автоматически равномерно распределить их по рядам, установите параметр auto_alignment. Если выставить True, Keyboa попробует подобрать делитель в диапазоне от трёх до пяти, а можно задать свой диапазон в виде списка чисел от одного до восьми, например, [2, 3, 7].

    Параметр reverse_alignment_range определяет, будет ли Keyboa искать делитель с начала или с конца диапазона, указанного в auto_alignment.

    Распределить кнопки вручную

    С помощью Keyboa можно легко вручную задать количество кнопок в каждом ряду клавиатуры с помощью вложенных списков. Для примера объединим в ряды часть наших фруктов. Принцип остался прежним: каждый элемент основного списка - отдельный ряд клавиатуры, только теперь состоящий из нескольких элементов - кнопок.

    fruitscomplex = [
      "banana",
      ["coconut", "orange"],
      ["peach", "apricot", "apple"],
      "pineapple",
      ["avocado", "melon"],
    ]
    
    kb_fruits_complex = keyboa_maker(items=fruits_complex, copy_text_to_callback=True)
    
    bot.send_message(
      chat_id=uid, reply_markup=kb_fruits_complex,
      text="Please select one of the fruit:")

    Таким способом удобно создавать меню или любые другие клавиатуры со статичной, но сложной структурой.

    Управляем содержимым callback

    Мы упоминали, что callback_data - это строка, которую Telegram отправляет вам после нажатия кнопки пользователем. По её содержимому вы можете понять, какая именно кнопка была нажата.

    Порой необходимо записать в callback_data дополнительные данные, например, идентификатор или другие свойства элемента. Чтобы задать кнопкам уникальные callback_data с требуемой информацией воспользуемся списком словарей или списком кортежей.

    fruits_with_ids = [
      {"banana": "101"}, {"coconut": "102"}, {"orange": "103"},
      {"peach": "104"}, {"apricot": "105"}, {"apple": "106"},
      {"pineapple": "107"}, {"avocado": "108"}, {"melon": "109"}, ]
    
    # or [
    # ("banana", "101"), ("coconut", "102"), ("orange", "103"),
    # ("peach", "104"), ("apricot", "105"), ("apple", "106"),
    # ("pineapple", "107"), ("avocado", "108"), ("melon", "109"), ]

    В этом случае ключ каждого словаря станет текстом кнопки, а его значение пойдет в callback_data. Для кортежей это будут нулевой и первый элементы соответственно. И поскольку мы явно указываем, что добавить в callback_data, параметр copy_text_to_callback больше не нужен.

    kb_fruits = keyboa_maker(items=fruits_with_ids, items_in_row=3)
    
    bot.send_message(
      chat_id=uid, reply_markup=kb_fruits,
    	text="Please select one of the fruit:")

    Теперь, после нажатия пользователем одной из кнопок, мы получим в ответ не название фрукта, а его id номер, записанный в callback_data.

    {"text": "banana", "callback_data": "101"}, ...

    Этого достаточно, если мы используем числа только для обозначения фруктовых id. А если нужно принимать разные числовые параметры, например вес или цену? Как определить, к чему относится полученное число?

    С Keyboa мы можем явно указать это при создании клавиатуры. Параметр front_marker добавляет одинаковый текст в начало callback_data каждой кнопки, а back_marker, соответственно, в конец. Рассмотрим на примере:

    kb_fruits = keyboa_maker(items=fruits_with_ids, front_marker="&fruit_id=")

    Теперь callback_data кнопок будет состоять из текста формата front_marker + value, например: '&fruit_id=101', '&fruit_id=102' и т. д. Такой подход позволит нам легко расшифровать строку и понять, какие получены данные и с какими значениями.

    Представим, что на следующем шаге пользователю предлагают выбрать желаемый вес выбранного фрукта:

    # коллбек, полученный после нажатия на кнопку, например "&fruit_id=102"
    selected_fruit_id = call.data
    
    available_weight = [1, 2, 5, 10, 100, ]
    
    kb_available_weight = keyboa_maker(
    items=available_weight, copy_text_to_callback=True,
     front_marker="&weight=", back_marker=selected_fruit_id)

    Теперь callback_data каждой кнопки будет выглядеть так:

    '&weight=1&fruit_id=102', '&weight=2&fruit_id=102', '&weight=5&fruit_id=102'

    Здесь мы используем front_marker и back_marker, чтобы обернуть передаваемое значение, указав тип текущего значения и добавив в callback_data уже полученную информацию. Имейте в виду, что у Telegram есть ограничение на длину callback_data в 64 байта, поэтому, если передаваемых параметров будет много - придётся сокращать названия или использовать аббревиатуры.

    Объединение нескольких клавиатур в одну

    Иногда в одну клавиатуру могут входить статические и динамические элементы, например, навигационное меню и меняющийся набор элементов. Тогда возникает потребность собрать клавиатуру из нескольких частей. Специально для этого у нас есть функция keyboa_combiner().

    У нее есть только один параметр - keyboards, представляющий собой набор уже созданных клавиатур. Вот, как это работает:

    from keyboa import keyboa_maker, keyboa_combiner
    
    controls = [["⏹️", "⏪️", "⏏️", "⏩️", "▶️"], ]
    tracks = list(range(1, 13))
    
    keyboard_controls = keyboa_maker(items=controls, copy_text_to_callback=True)
    keyboard_tracks = keyboa_maker(items=tracks, items_in_row=4, copy_text_to_callback=True)
    
    keyboard = keyboa_combiner(keyboards=(keyboard_tracks, keyboard_controls))
    
    bot.send_message(
      chat_id=uid, reply_markup=keyboard, 
      text="Please select the track number:")

    Можно объединить сразу много клавиатур - главное, чтобы общее количество кнопок было не больше ста. Это ограничение Telegram.

    Итог

    В этой статье мы кратко рассмотрели создание клавиатур для ботов в Telegram с помощью Keyboa. Больше информации и описание остальных параметров можно найти на странице проекта в Github.

    Буду рад вашим отзывам, идеям и конструктивной критике по развитию проекта.

    Комментарии 4

    • НЛО прилетело и опубликовало эту надпись здесь
        0
        Навскидку, это может быть оглавление книги или список аудиозаписей, статей.
        Даже выбрать день месяца — уже 30 кнопок.
        0

        Это очень… Инновационно и достойно Хабра… я полагаю?
        Я не особо понимаю в чём достоинство, как говорится, тема женской груди не раскрыта

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое