Telegram-бот на базе Power BI

Telegram-бот на базе Power BI

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

Но если вы умеете делать отчёты в Power BI и больше ничего, как тогда настроить оповещения в Telegram? Функционал получения данных в Power BI вас вполне устраивает - он довольно удобен. Можно ли обойтись им или нужны другие инструменты? 

На самом деле можно! Вы можете создать бота в Telegram на базе Power BI, который каждый день будет присылать вам оповещения.

Схема достаточно проста:

  • получаете данные из разных источников в Power BI
  • рассчитываете нужные цифры из каждого источника,
  • формируете из цифр, букв и смайликов ёмкое сообщение (сообщение можно сделать разным в зависимости от полученных чисел),
  • создаёте бота в Telegram и разрешаете ему публикацию,
  • отправляете сообщение от имени бота себе в личку или в Telegram-канал (открытый или закрытый канал - решайте сами),
  • форматируете код, чтобы набор данных обновлялся онлайн,
  • выгружаете отчёт в Power BI Service и настраиваете расписание обновлений.

Пройдёмся по схеме более детально

Какие данные получить - решать вам, этот пункт разбирать не вижу смысла.
Что касается цифр -  важно понимать, что в Telegram отправится не отчёт, а краткое сообщение. Поэтому столбцы или строки здесь не подойдут. Важно вычислить одно или несколько значений, которые и будут потом отправлены в сообщении. Удобно, что в Power Query уже есть кнопки для вычисления суммы, среднего и других общих величин. 

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

Number.From() // получить число например из текста,
Text.From() // получить текст из числа или даты, 
Date.From() // получить дату из текста или числа.

Еще несколько важных функций, которые могут помочь отфильтровать данные и посчитать расхождения:

Date.AddDays(Date.From(DateTime.LocalNow()) , -1) // вчерашний день в формате даты (если хотите фильтровать данные за вчера),
Number.Abs() // вычисление модуля числа (если требуется только положительная часть). 

Важно понимать, что вчерашнего дня (или любого другого дня) может просто не быть в статистике. Это важно предусмотреть, например с помощью конструкции try-otherwise. В любом случае если день отсутствует, ваш бот не должен ломаться. Например, мой бот отправляет в этом случае нулевые значения.

Если хотите больше узнать о функциях и преобразованиях в Power Query - у меня на канале есть целый плейлист для новичков на эту тему: https://www.youtube.com/playlist?list=PL3du-Tm1nAm6SSQOCpryquOx-6aasPARM

Когда вы посчитали нужные числа, добавьте для них новые переменные, где эти числа будут в формате текста. Тут как раз поможет Text.From(). Почему для чисел нужны отдельные текстовые переменные? Дело в том, что на основе чисел удобно писать условия (например больше / меньше / равно), но сообщение мы формируем из текстовых переменных. Поэтому для условий и для сообщения нам нужны разные переменные.

Сформировать сообщение - самое простое. Для этого вы объединяете текстовые переменные значком &. Если надо перенести строку - используете #(lf). Напоминаю, в сообщении используются только текстовые переменные, числа указываются только внутри Text.From() или берутся из ранее созданной той же функцией текстовой переменной. 

Если хотите сформировать разные сообщения по условию, это тоже несложно. Воспользуйтесь конструкцией if then else. Например:

 message = if РасходВчера > 10000 then "Большой расход" else "Маленький расход"

Переменная "РасходВчера" должна быть числом, а переменная message - будет текстом. Соответственно сегодняшнее сообщение (message) будет зависеть от вчерашнего расхода. 

Создать и настроить бота - тоже несложно. Достаточно выполнить пункт 1 инструкции: https://habr.com/ru/post/262247/. Если вы хотите отправлять сообщения от бота себе, то вам потребуется запустить диалог с ним. Для этого отправляете боту команду /start. Тоже самое может сделать и другой пользователь. Бот сможет отправлять пользователю сообщения только если тот запустит бота командой /start.

Не забудьте сохранить токен бота, он понадобится для отправки любых сообщений. Помимо токена для отправки сообщения от бота пользователю или в канал нужно знать ID пользователя или канала.

ID пользователя можно уточнить у такого же бота - userinfobot. При запуске userinfobot отправляет пользователю его ID, имя и фамилию. Именно ID нам и понадобится для отправки сообщений пользователю от бота. Сохраняем его вместе с токеном.

Другой вариант - отправка сообщений в Telegram-канал. Создайте закрытый или открытый Telegram-канал и добавьте туда бота. Дайте боту права администратора и возможность постить сообщения. После чего отправьте какое-то сообщение в этот канал от себя и перейдите по ссылке: 

https://api.telegram.org/bot1234567:AGFnH-98pywSLbAuMTDGbpOLMRiY/getupdates

Токен бота в ссылке замените на свой. 

Тут вы увидите историю сообщений бота и сможете без труда определить ID чата, который вам понадобится для отправки сообщений в Telegram-канал: 

{"ok":true,"result":[{"update_id":11234567, "my_chat_member":{"chat":{"id":-123545678990,"title":

 Если ID чата с минусом, значит так и должно быть, копируем вместе с минусом и сохраняем.

Теперь сама отправка сообщений - содержимое переменной "post" выглядит так: 

try Json.Document(Web.Contents(
"https://api.telegram.org/bot1234567:AGFnH-98pywSLbAuMTDGbpOLMRiY/sendMessage",
[Query = [chat_id="123456789",text=message], Content = Text.ToBinary("")]
))[ok] otherwise false

Назовём этот код "отправка сообщения". Токен и ID пользователя/канала заменяете на свои, а message - это текстовая переменная сообщения, которую мы вычислили ранее. Если бот не смог отправить сообщение - он выдаст false, если смог - true. Рекомендую ставить этот шаг последним и завершать запрос словами "in post". Не забывайте, что между шагами в Power Query всегда ставится запятая. Именно запятая, а не перенос строки является разделителем шагов в Power Query. 

Тут нас ждёт самое сложное - нужно заставить запрос обновляться онлайн. 
Я выявил 2 важных условия, которые помогли мне настроить онлайн-обновление:
• бот должен представлять собой 1 запрос в Power Query
• бот должен представлять собой 1 шаг в Power Query. 

Да, это неприятно, но иначе он будет постоянно ругаться и требовать перестроить эту комбинацию данных. 

На самом деле и это несложно, но требует аккуратности. Допустим, у нас есть несколько запросов, где мы вычисляем наши значения для бота:

let 
    a = 1,
    b=a*2,
    c=a*b*3
in c
let 
    x = 1,
    y=x*2,
    z=x*y*3
in z

Теперь мы начинаем строить самого бота и копируем туда их код, занося каждый из запросов в свою переменную и разделяя шаги запятыми. 
Назовём этот кусок кода "реализация бота":

let 
   first = 
     let 
         a = 1,
         b=a*2,
         c=a*b*3
     in c,
   
   second = 
     let 
         x = 1,
         y=x*2,
         z=x*y*3
     in z,
     
   message = Text.From( first) & Text.From(second), 
   post = отправка сообщения
in post

После чего весь наш запрос нужно завернуть в еще один let-in:

let
   query = реализация бота
in query

Практика показала, что лучше выгружать в power bi данные в виде таблицы, поэтому я добавляю шаг с преобразованием результата "query" в таблицу: 

let
   query = реализация бота,
   tab = #table(1, {{query}})
in tab

В результате мы получили всего 1 запрос, а все расчёты происходят в 1 шаге. Остальные запросы помогают нам писать код, но на них бот ссылаться не должен. 

Уберём наши обозначения и посмотрим что в итоге получилось:

let
   query = 
   	let 
	   first = 
    	    let 
        	 a = 1,
	         b=a*2,
	         c=a*b*3
	     in c,
   
	   second = 
	     let 
    	     x = 1,
        	 y=x*2,
	         z=x*y*3
	     in z,
     
	   message = Text.From( first) & Text.From(second), 
	   post = try Json.Document(Web.Contents(
	   		  "https://api.telegram.org/
	   		  bot1234567:AGFnH-98pywSLbAuMTDGbpOLMRiY
	   		  /sendMessage",
	  		  [Query = [chat_id="123456789",text=message], 
	   		  Content = Text.ToBinary("")]))[ok] 
	   		  otherwise false
	in post,
   tab = #table(1, {{query}})
in tab

Выгрузка в Power BI Service. На этом этапе я рекомендую сделать копию pbix файла. В этой копии вы оставляете только 1 запрос - запрос бота. Именно его мы и будем выгружать в веб. 

Если вы не пишете код вручную, для расчётов вы использовали другие запросы. Пусть эти запросы будут под рукой - они понадобятся при доработках. Но в веб я рекомендую выгружать файл pbix, содержащий 1 запрос, в котором находится всего 1 шаг. Так вы точно не ошибётесь.

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

Результат

Мне удалось сделать сделать краткие информативные сообщения по достоверности данных. Мой бот сверяет данные из нескольких источников и указывает на расхождения: 

 

Бот присылает ровно 1 сообщение в день и обновляется корректно. Если вы заметите проблемы с обновлением при таком построении запросов, скорее всего это проблемы с другими источниками в файле Power BI.

Еще раз перечислю важные моменты: 

  • Бот должен находиться в 1 запросе и 1 шаге (без ссылок на другие запросы),
  • Из Power Query в модель лучше выгружать именно таблицу,
  • В Power BI Service нужно пропустить тестирование подключение для Telegram,
  • Чтобы застраховаться от отсутствия данных за какой-то день используем try-otherwise.

 

Пишите в комментариях удалось ли вам построить бота и оставляйте скрины сообщений, которые он отправляет;)

Комментарии