Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[SnowOne 2025] Алексей Овсянников: Библиотеки д...

Avatar for jugnsk jugnsk
May 07, 2025
2

[SnowOne 2025] Алексей Овсянников: Библиотеки для Telegram-ботов

Рассмотрим существующие библиотеки для работы с Telegram Bots API на Java и Kotlin.

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

Видео: https://youtu.be/mHGGKX3HKDc

Avatar for jugnsk

jugnsk

May 07, 2025
Tweet

More Decks by jugnsk

Transcript

  1. 2 Обо мне Я: Овсянников Алексей Кодил на: • Java

    • Kotlin • JS • Python • Etc… 7 годиков с Bot API
  2. 5 Как обычно работает бот? • Аккаунт – регистрация в

    BotFather • Поведение • HTTP запросы GET/POST к Bot API
  3. 6 Как обычно работает бот? getMe https://api.telegram.org/botTOKEN/getMe 1 { 2

    "ok": true, 3 "result": 4 { 5 "id": 1234567890, 6 "is_bot": true, 7 "first_name": "Имя бота", 8 "username": "юзернейм", 9 "can_join_groups": true, 10 "can_read_all_group_messages": true, 11 "supports_inline_queries": true, 12 "can_connect_to_business": true, 13 "has_main_web_app": false 14 } 15 }
  4. 7 Как обычно работает бот? • Аккаунт – регистрация в

    BotFather • Поведение • Запросы GET/POST к Bot API • Получение обновлений • LongPolling • WebHooks
  5. 8 LongPolling + Не нужен домен, белый IP и другие

    сложности - Может забирать 100 обновлений за раз и не больше
  6. 9 WebHook + Скорость получения обновлений по-большей части зависит от

    мощности сервера - Нужен белый IP + сертификат/домен с сертификатом
  7. 16 Почему библиотеки • Готовое решение • Огораживание от проблем

    оригинального API • Помощь в написании кода
  8. 21 Костыли и грабли • Галереи – не галереи •

    Если за них не платят • А топиков не существует • И вообще, 429 Too Many Requests
  9. 22 Библиотеки на Java/Kotlin • DEHuckaKpyT/telegram-bot • vendelieu/telegram-bot • InsanusMokrassar/ktgbotapi

    • rubenlagus/TelegramBots • pengrad/java-telegram-bot-api • Teleight/TeleightBots Источник: https://core.telegram.org/bots/samples
  10. 24 rubenlagus/TelegramBots • Реализована как минимум бОльшая часть API •

    Есть надстройка для создания ботов как отдельных сущностей • Спорные моменты в коде
  11. 25 rubenlagus/TelegramBots // Отправка сообщения: 1 SendMessage sendMessage = SendMessage

    2 .builder() 3 .chatId(chatId) 4 .text("Ваш заказ готов").replyMarkup(keyboard) 6 .build(); 7 telegramClient.execute(sendMessage); // Создание инлайн кнопки 1 InlineKeyboardButton 2 .builder() 3 .text("Открыть заказ") 4 .url("google.com") 5 .build() 6 )
  12. 26 pengrad/java-telegram-bot-api • Реализована как минимум бОльшая часть API •

    Простой как табуретка (вызовы через execute, простые биндинги к сущностями и методам телеги)
  13. 27 pengrad/java-telegram-bot-api // Отправка сообщения: 1 SendMessage sendMessage = new

    SendMessage(chatId, "Ваш заказ готов") 2 .parseMode(ParseMode.Markdown) 3 .replyToMessageId(1) 4 .replyMarkup(keyboard); 5 bot.execute(sendMessage); // Создание инлайн кнопки 1 new InlineKeyboardButton("Открыть заказ") 2 .url("google.com")
  14. 28 Teleight/TeleightBots • Пишут, что `lightweight, high-performance, easy to use`,

    но все так говорят • Пока кажется, что ребята очень хотят сделать удобно • Какие-то попытки в DSL • +- На бейдже поддержка Bot API 7.10, в коммитах видел 8.11 • - `early development`, последний коммит был в день проверки 19.12
  15. 29 Teleight/TeleightBots // Отправка сообщения (здесь menu – результат построения

    меню из DSL): 1 SendMessage sendMessage = SendMessage.ofBuilder(chatId, "Ваш заказ готов") 2 .replyMarkup(menu.getKeyboard()) 3 .parseMode(ParseMode.Markdown) 4 .build(); 5 bot.execute(sendMessage); // Создание инлайн кнопки 1 InlineKeyboardButton.ofBuilder("Открыть заказ") 2 .url("google.com") 3 .build()
  16. 30 Teleight/TeleightBots 1 Menu menu = bot.createMenu((context, rootMenu) -> {

    2 Menu subMenu = context.createMenu("subMenu2"); 3 rootMenu.setText("Root menu"); 4 subMenu.setText("SubMenu"); 5 InlineKeyboardButton button1 = InlineKeyboardButton .ofBuilder("menu 1 – button 1").destinationMenu(subMenu2).build(); 6 InlineKeyboardButton button2 = InlineKeyboardButton .ofBuilder("menu 2 – button 2").destinationMenu(rootMenu).build(); 7 rootMenu.addRow(button1); 8 subMenu2.addRow(button2); 9 }
  17. 32 DEHuckaKpyT/telegram-bot • Поддержка бОльшей части API • Есть привязки

    к другим библиотекам • Много документации KDocs • Нет поддержки вебхуков • Сложнорасширяемый API
  18. 33 DEHuckaKpyT/telegram-bot // Отправка сообщения: 1 bot.sendMessage( 2 chatId, 3

    "Ваш заказ готов", 4 replyParameters = ReplyParameters(messageId = 1), 5 parseMode = “markdown” // дада, просто строка 6 ) // Создание инлайн кнопки 1 InlineKeyboardButton("Открыть заказ", url = "google.com")
  19. 34 vendelieu/telegram-bot • Поддержка как минимум бОльшей части API •

    Есть DSL для создания бота • Не всегда очевидный API
  20. 36 vendelieu/telegram-bot // Подключение либы в модуль 1 plugins {

    2 id("com.google.devtools.ksp") version "2.1.0-1.0.29" 3 id("eu.vendeli.telegram-bot") version "7.8.0" 4 }
  21. 37 vendelieu/telegram-bot // Подключение либы в модуль 1 plugins {

    2 id("com.google.devtools.ksp") version "2.1.0-1.0.29" 3 id("eu.vendeli.telegram-bot") version "7.8.0" 4 } 1 @InputHandler(["conversation"]) 2 @Guard(UserPresentGuard::class) 3 suspend fun startConversation( 4 update: ProcessedUpdate, 5 user: User, 6 bot: TelegramBot 7 ) { 8 message { "Nice to meet you, ${update.text}" } 9 .send(user, bot) 10 message { "What is your favorite food?" } 11 .send(user, bot) 12 bot.inputListener.set(user) { "conversation-2step" } 13 }
  22. 38 vendelieu/telegram-bot // Отправка сообщения: 1 message { "Some your

    message." } 2 .options { 3 parseMode = ParseMode.Markdown, 4 replyParameters = ReplyParameters(messageId = 1) 5 } 6 .inlineKeyboardMarkup { /* тут собираем клавиатуру */ } 7 .sendReturning(chatId, bot) // Создание инлайн кнопки 1 url(name = "Открыть заказ") { 2 "google.com" 3 }
  23. 39 InsanusMokrassar/ktgbotapi • Поддержка всего API (включая WebApp API в

    Kotlin/JS) • Есть разные DSL • Местами не самые очевидные решения • Редко обновляемая кодовая база вокруг • IDE не всегда справляется с либой
  24. 40 InsanusMokrassar/ktgbotapi // Отправка сообщения: 1 bot.reply( 2 chatId, 3

    toMessageId = 1, 4 text = “Ваш заказ готов”, 5 parseMode = MarkdownParseMode, 7 ) // Создание инлайн кнопки 1 urlButton("Открыть заказ", "google.com")
  25. 41 Итоги по известным либам Язык Поддержка API Удобства /

    вкусовщина Активность репозитория Web Github ⭐ rubenlagus/TelegramBots Java + + - - 4952 pengrad/java-telegram-bot-api Java + - +- - 1854 Teleight/TeleightBots Java +- +- + - 35 DEHuckaKpyT/telegram-bot Kotlin + +- + - 30 vendelieu/telegram-bot Kotlin + + + + 208 InsanusMokrassar/ktgbotapi Kotlin + + +- + 374 • Если хочется Java – TeleightBots • Странности – rubenlagus или vendelieu • WebApp – vendelieu или ktgbotapi 24.02.2025
  26. 45 О галереях в ktgbotapi 1 onContentMessage { 2 val

    content = it.content 3 content.whenMediaCollectionContent { 4 // List<TelegramMediaFile> 5 it.mediaCollection 6 } 7 }
  27. 46 О галереях в ktgbotapi 1 onMediaCollection { 2 //

    List<TelegramMediaFile> 3 it.content.mediaCollection 4 }
  28. 47 Бот для заказов 1 sealed interface OrderState : State

    { 2 override val context: OrderId 3 data class Created( 4 override val context: OrderId 5 ) : OrderState 6 data class Confirmed( 7 override val context: OrderId 8 ) : OrderState 9 data class Prepared( 10 override val context: OrderId 11 ) : OrderState 12 }
  29. 48 Бот для заказов 1 suspend fun onStateUpdate( 2 state:

    OrderState, 3 userId: UserId 4 ) { 5 // Тут будет наш код 6 }
  30. 49 Бот для заказов 1 val text = when (state)

    { 2 is OrderState.Created -> "Ваш заказ создан" 3 is OrderState.Confirmed -> "Ваш заказ принят" 4 is OrderState.Prepared -> "Ваш заказ готов" 5 }
  31. 50 Бот для заказов 1 val keyboard = flatInlineKeyboard {

    2 dataButton("Открыть заказ", "google.com") 3 }
  32. 52 Бот для заказов 1 suspend fun onStateUpdate(state: OrderState, userId:

    UserId) { 2 val text = when (state) { 3 is OrderState.Confirmed -> "Ваш заказ принят" 4 is OrderState.Created -> "Ваш заказ создан" 5 is OrderState.Prepared -> "Ваш заказ готов" 6 } 7 val keyboard = flatInlineKeyboard { 8 dataButton("Открыть заказ", "google.com") 9 } 10 bot.send( 11 userId, 12 text, 13 replyMarkup = keyboard 14 ) 15 }
  33. 54 Бот для заказов 1 val stateSuffix = when (state)

    { 2 is OrderState.Created -> "создан" 3 is OrderState.Confirmed -> "принят" 4 is OrderState.Prepared -> "готов" 5 }
  34. 55 Бот для заказов 1 val text = buildEntities(" ")

    { 2 regular("Ваш заказ") 3 link("#${state.id}", "google.com") 4 bold(stateSuffix) 5 }
  35. 58 Бот для заказов 1 val liveLocationMessage = sendLiveLocation( 2

    chatId = userId, 3 latitude = 0.0, 4 longitude = 0.0, 5 livePeriod = 120 6 ) 7 editLiveLocation( 8 message = liveLocationMessage, 9 latitude = 1.0, 10 longitude = 1.0 11 )
  36. 59 Бот для заказов // flow: Flow<Pair<Double, Double>> 1 bot.handleLiveLocation(

    2 userId, 3 flow.map { (latitude, longitude) -> 4 EditLiveLocationInfo( 5 latitude = latitude, 6 longitude = longitude, 7 ) 8 } 9 )
  37. 61 Бот для заказов 1 bot.sendInvoice( 2 userId, 3 price

    = LabeledPrice("1", 1L), 4 title = "Чаевые курьеру", 5 description = "Вы можете оставить чаевые курьеру", 6 payload = "order_tips_42", 7 replyMarkup = flatInlineKeyboard { 8 payButton("Оплатить") 9 } 10 )
  38. 65 Бот для заказов 1 onPreCheckoutQuery( 2 initialFilter = {

    3 it.invoicePayload 4 .startsWith("order_tips") 5 } 6 ) { 7 answerPreCheckoutQueryOk(it) 8 }
  39. 68 Выводы • Telegram Bots API полон сюрпризов и нюансов

    • Лучше писать ботов на развитых языках со строгой типизацией
  40. 69 Выводы • Telegram Bots API полон сюрпризов и нюансов

    • Лучше писать ботов на развитых языках со строгой типизацией • Ищите актуальную библиотеку
  41. 70 Выводы • Telegram Bots API полон сюрпризов и нюансов

    • Лучше писать ботов на развитых языках со строгой типизацией • Ищите актуальную библиотеку • Экспериментируйте