Philip Wiki

Персональный wiki-сайт

Инструменты пользователя

Инструменты сайта


docs:blog:2018:03:ps_telegram-bot_part_2

Telegram-Bot на PowerShell (часть 2)

Ну что же. Я собрался с силами и решил, что пришло время второй части про Telegram-бота на Powershell. Если в первой части мы рассматривали основу: как «слушать» своего бота, то во второй приступим к его ответам.

В первой части уже была ссылка на статью данного блога, где я описывал функцию по отправке сообщения, тем не менее я повторюсь, почистим в ней код и сделаем его чуть более логичным.

Отправка сообщения ботом

Начнём с того, что за отправку сообщений отмечает метод sendMessage, его средствами мы и будем отправлять сообщения от имени бота.

Пример функции Send-TelegramMessage:

function Send-TelegramMessage {
    [CmdletBinding()]
    param(
        [string]$chat_id,
        [string]$text,
        [parameter(Mandatory=$true,HelpMessage="Enter Telegram Token")]
        [string]$tgm_token,
        [parameter(Mandatory = $false)]
        [ValidateSet("Markdown", "HTML")]
        [string]$parse_mode = "Markdown",
        [switch]$nopreview,
        [switch]$silent,
        [int]$replyto,
        $reply_markup
    )
 
    $parameters = @{
        "chat_id"                  = $chat_id
        "text"                     = $text
        "parse_mode"               = $parse_mode
        "disable_notification"     = $silent.ToString()
        "disable_web_page_preview" = $nopreview.ToString()
        "reply_to_message_id"      = $replyto
    }
 
    if ($reply_markup) {
        $parameters += $reply_markup
    }
 
    Invoke-WebRequest `
        -Uri ("https://api.telegram.org/bot$tgm_token/sendMessage") `
        -Method Post `
        -ContentType "application/json;charset=utf-8" `
        -Body (ConvertTo-Json -Depth 20 -Compress -InputObject $parameters)
}

Простейший пример работы функции. Отправляем markdown-сообщение в чат, при этом отключая оповещения о нём

Send-TelegramMessage -chat_id <id_чата> -text 'Какой-то *форматированный* текст и ссылка для парсинга http://yandex.ru' -silent

В ответ должны увидеть что-то вроде этого:

Подробно описывать все параметры функции смысла не вижу, это всё сделано в документаци метода, ссылку на который я дал выше.

Где взять chat_id? Ну как же? В первой части мы научились получать сообщения из чата, так вот внутри переменной $content (если конкретнее: $content.result.message.chat.id) мы и найдём номер чата.

Кнопочки!

Вот здесь уже начинается немного более вкусная история. Я намеренно убрал из функции выше параметр Уже вернул параметр reply_markup обратно, чтобы не дублировать функцию дважды, речь о котором сейчас пойдёт. Он имеет сразу несколько типов, но сейчас мы разберем самый, на мой взгляд, интересный: InlineKeyboardMarkup. Это своего рода клавиатура, которая добавляется к сообщению бота.

Как написано в документации, inline_keyboard это массив из массивов InlineKeyboardButton. Вот так это будет выглядеть на powershell (для наглядности и удобства, массив с кнопками $buttons я вынес за пределы основного $reply_markup):

Пример массива из кнопок:

$buttons = @(
    @{
        "text" = "⬅ Налево"
        "callback_data" = "Пойду налево"
    }
    @{
        "text" = "➡ Направо"
        "callback_data" = "Пойду направо"
    }
), @(
    @{
        "text" = "⛔ Тут постою"
        "callback_data" = "Останусь стоять на месте"
    }
)
 
$reply_markup = @{
    "reply_markup" = @{
        "inline_keyboard" = $buttons
    }
}
 
# а пеперь отправим массив reply_markup в нашу функцию
Send-TelegramMessage -chat_id <id_чата> -text '*Куда пойдёшь* от камня?' -silent -reply_markup

Этот пример хорош ещё и тем, что по нему понятно, как «строить» каркас из кнопок. Поле callback_data это то, что мы сможем отловить в переменной $content после нажатия на кнопку. Подробнее в описании API.

Резюме

Кажется пока всё. inline_keyboard умеет не только так, но я снова тыкаю пальцем в документацию. Основу я описал, всё остальное аналогично или очень похоже.

Обсуждение

Антон, 26.11.2019 17:21

Добрый день. А подскажите, добавил кнопки в код своего бота, но при выполнении ругается на параметры Отсутствует аргумент для параметра «reply_markup». Укажите параметр типа «System.Object» и повторите попытку. Что может быть не так?

Антон, 26.11.2019 17:25, 26.11.2019 19:23
  1. function Say {
  2. [CmdletBinding()]
  3. param( [string]$chat_id = $(Throw "'-chat_id' argument is mandatory"),
  4. [string]$text = $(Throw "'-text' argument is mandatory"),
  5. [string]$markdown_mode ="markdown" ,
  6. [switch]$nopreview,
  7. $reply_markup
  8. )
  9. if($nopreview) { $preview_mode = "True" }
  10.  
  11.  
  12. $payload = @{ "chat_id" = $chat_id;
  13. "text" = $text
  14. "parse_mode" = $markdown_mode;
  15. "disable_web_page_preview" = $preview_mode;
  16. }
  17.  
  18.  
  19.  
  20.  
  21.  
  22. $buttons = @(
  23.  
  24. @{
  25. "text" = "⬅ Налево"
  26. "callback_data" = "Пойду налево"
  27. }
  28. @{
  29. "text" = "➡ Направо"
  30. "callback_data" = "Пойду направо"
  31. }
  32. ), @(
  33. @{
  34. "text" = "⛔ Тут постою"
  35. "callback_data" = "Останусь стоять на месте"
  36. }
  37. )
  38.  
  39. $reply_markup = @{
  40. "reply_markup" = @{
  41. "inline_keyboard" = $buttons
  42. }
  43. }
  44.  
  45.  
  46. if ($reply_markup) {
  47. $payload += $reply_markup
  48. }
  49.  
  50. $request = Invoke-WebRequest -Uri ("https://api.telegram.org/bot{0}/sendMessage" -f $token) `
  51. -Method Post -ContentType "application/json;charset=utf-8" `
  52. -Body (ConvertTo-Json -Compress -InputObject $payload)
  53.  
  54.  
  55.  
  56. }
Philip, 26.11.2019 20:07

Там наверное всё же другая ошибка была, вроде этого:

{"Bad Request: field \"inline_keyboard\" of the InlineKeyboardMarkup should be an Array of Arrays"}

Вы упустили параметр -Depth в строке 52. От отвечает за «глубину просмотра массива». По умолчанию его значение равно 2. Например:

ConvertTo-Json -InputObject $payload

В ответ получим:

{
    "reply_markup":  {
                         "inline_keyboard":  [
                                                 [
                                                     "System.Collections.Hashtable",
                                                     "System.Collections.Hashtable"
                                                 ],
                                                 [
                                                     "System.Collections.Hashtable"
                                                 ]
                                             ]
                     },
    "chat_id":  "xxxxxxx",
    "disable_web_page_preview":  null,
    "text":  "say hi",
    "parse_mode":  "Markdown"
}

Как видите, вместо «вложенных в массив кнопочек» в JSON передалось название их типов. Поэтому, если мы добавим хотя бы 10 уровней вложенности при конвертации:

ConvertTo-Json -InputObject $payload -Depth 10

В ответ получим то, что хотим:

{
    "reply_markup":  {
                         "inline_keyboard":  [
                                                 [
                                                     {
                                                         "text":  "⬅ Налево",
                                                         "callback_data":  "Пойду налево"
                                                     },
                                                     {
                                                         "text":  "➡ Направо",
                                                         "callback_data":  "Пойду направо"
                                                     }
                                                 ],
                                                 [
                                                     {
                                                         "text":  "⛔ Тут постою",
                                                         "callback_data":  "Останусь стоять на месте"
                                                     }
                                                 ]
                                             ]
                     },
    "chat_id":  "xxxxxxx",
    "disable_web_page_preview":  null,
    "text":  "say hi",
    "parse_mode":  "Markdown"
}

Так 52 строка вашего скрипта должна выглядеть следующим образом:

-Body (ConvertTo-Json -Depth 20 -Compress -InputObject $payload)
Антон, 27.11.2019 11:34

Спасибо огромное, действительно пропустил. Все работает :)

Только авторизованные участники могут оставлять комментарии.
docs/blog/2018/03/ps_telegram-bot_part_2.txt · Последнее изменение: 07.01.2019 16:16 — philip

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki