Ваш собственный телеграм-секретарь: делаем вместе

У нас уже есть несколь­ко ста­тей и про­ек­тов с бота­ми для телеграма:

Но это были учеб­ные про­ек­ты — мы на них учи­лись, но реаль­ной поль­зы они не при­но­си­ли. Наста­ло вре­мя это испра­вить и напи­сать пол­но­цен­но­го рабо­че­го бота в помощь нашей редакции.

Какую задачу решаем

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

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

Реше­ние: сде­лать телеграм-бота, кото­ро­му мож­но отпра­вить сооб­ще­ние, а он пере­шлёт его куда нуж­но. Что­бы не пло­дить лич­ные сооб­ще­ния от бота, мож­но сде­лать так:

  1. Сде­лать внут­рен­ний чат новост­ной редакции
  2. Доба­вить в него бота
  3. Настро­ить бота так, что­бы он отправ­лял сооб­ще­ния поль­зо­ва­те­лей в этот чат.

Что в ито­ге: когда у отде­ла ново­стей есть вре­мя, они загля­ды­ва­ют в этот чат и видят, кто что напи­сал и что из это­го мож­но взять в рабо­ту. Лиш­ние сооб­ще­ния не при­хо­дят, лич­ные чаты не засоряются.

Сложный вариант — написать своего бота и поставить его на сервер (мы не стали так делать)

Кажет­ся, что если мы — изда­ние про тех­но­ло­гии и у нас есть про­грам­ми­сты и свои вир­ту­аль­ные сер­ве­ры, то про­ще все­го будет напи­сать бота на питоне и отпра­вить на сер­вер. Но на самом деле с таким под­хо­дом есть мно­го сложностей:

  • нуж­но най­ти про­грам­ми­ста на питоне, кото­рый смо­жет напи­сать код;
  • этот код потом нуж­но под­дер­жи­вать, если пона­до­бит­ся доба­вить новые функции;
  • нуж­но под­го­то­вить сер­вер к посто­ян­ной фоно­вой рабо­те python-кода;
  • сле­дить за тем, что­бы бот рабо­тал круг­ло­су­точ­но, а если падал, то сам умел перезапускаться;
  • сле­дить за самим сер­ве­ром и в слу­чае чего — пере­за­пус­кать его и все про­грам­мы на нём.

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

👉 Свой бот на сво­ём сер­ве­ре — это пра­виль­ный под­ход, если у вас в ком­па­нии уже настро­ен подоб­ный про­цесс и есть отдель­ная коман­да, кото­рая за это отве­ча­ет. В малень­кой коман­де раз­во­ра­чи­вать всю эту систе­му ради одно­го бота — перебор.

Простой вариант — использовать конструктор

Мы уже писа­ли про онлайн-конструкторы ботов и соби­ра­ли тесто­во­го бота в одном из них. С таким под­хо­дом мы реша­ем боль­шин­ство про­блем из пер­во­го варианта:

  • не нуж­но сле­дить за сер­ве­ром, пото­му что за это отве­ча­ет сер­вис с конструктором;
  • не нуж­но искать про­грам­ми­ста с необ­хо­ди­мой квалификацией;
  • чем мень­ше кода, тем про­ще под­дер­жи­вать гото­вый продукт.

Но появ­ля­ют­ся и свои рис­ки и особенности:

  • сер­вис может закрыть­ся, и бот пере­ста­нет работать;
  • если нуж­но доба­вить что-то, что не преду­смот­ре­но сер­ви­сом, то либо это будет слож­но и гро­мозд­ко, либо вооб­ще не полу­чит­ся сделать.

👉 Что каса­ет­ся опла­ты, то пла­тить за еже­ме­сяч­ную под­пис­ку за сер­вис в сред­нем полу­ча­ет­ся дешев­ле, чем пла­тить систем­но­му адми­ни­стра­то­ру и про­грам­ми­сту за настрой­ку и под­держ­ку всех программ.

Это наш выбор.

Логика проекта

  1. Созда­ём ново­го бота и добав­ля­ем его в чат.
  2. Полу­ча­ем нуж­ные пара­мет­ры для настрой­ки бота.
  3. Созда­ём бота в конструкторе.
  4. Настра­и­ва­ем чат для пол­но­цен­ной рабо­ты в редакции.

Сде­ла­ем всё по очереди.

Создаём нового бота и добавляем его в чат

Реги­стри­ру­ем ново­го бота через @BotFather — дела­ем это точ­но так же, как в мате­ри­а­ле про бота на питоне. Мы созда­ли бота @Eto_v_Kod_bot и назва­ли его «Это в Код»:

Создаём нового бота и добавляем его в чат Мы закра­си­ли токен для управ­ле­ния ботом, он нам пона­до­бит­ся для под­клю­че­ния к конструктору 

Теперь созда­ём пуб­лич­ный чат и добав­ля­ем в него бота. Пуб­лич­ный чат нам нужен, что­бы полу­чить ID чата, потом сде­ла­ем его при­ват­ным. Имен­но в этот чат бот будет пере­сы­лать полу­чен­ные сообщения.

Создаём нового бота и добавляем его в чат Чат редак­ции с добав­лен­ным ботом 

Узнаём ID чата

В теле­гра­ме у каж­до­го чата есть свой ID — уни­каль­ный иден­ти­фи­ка­тор, с помо­щью кото­ро­го мож­но отли­чать один чат от дру­го­го. Что­бы наш бот пере­сы­лал сооб­ще­ния в нуж­ный чат, узна­ем его ID. Для это­го сна­ча­ла пишем боту любое сооб­ще­ние (неваж­но, что он ещё не рабо­та­ет), а затем дела­ем такую магию — пере­хо­дим в бра­у­зе­ре по адресу

https://api.telegram.org/bot<ВАШ_ТОКЕН>/getUpdates

Это зна­чит, что мы должны:

  1. Взять наш токен.
  2. Под­ста­вить его вме­сто <ВАШ_ТОКЕН>. 
  3. Ско­пи­ро­вать всё, что получилось.
  4. Вста­вить резуль­тат в адрес­ную стро­ку и перей­ти по это­му адресу.

Напри­мер, в нашем слу­чае адрес будет такой:

https://api.telegram.org/bot1738394823:AAF4h6dkgjKH88lKanJ899lpH-Jqkd5k2399sjKo/getUpdates

Когда мы перей­дём по это­му адре­су, бра­у­зер нам напи­шет что-то такое:

{"update_id":8393,"message":{"message_id":3,"from":{"id":7474,"first_name":"AAA"},"chat":{"id"-1034423424553:,"title":"Eto_v_Kod"},"date":25497,"new_chat_participant":{"id":71,"first_name":"NAME","username":"Eto_v_Kod"_bot"}}}

Нам нуж­но то, что напи­са­но после chat id: -1034423424553 — это и есть ID наше­го чата, дефис перед чис­лом тоже важен.

👉 Теперь чат сно­ва мож­но сде­лать при­ват­ным, на ID это не повлияет.

Собираем бота в конструкторе — стартовый экран

Мы исполь­зу­ем кон­струк­тор BotMother — мы уже рас­ска­зы­ва­ли, как с ним рабо­тать и собрать сво­е­го тесто­во­го бота. Если что-то по ходу опи­са­ния будет непо­нят­но, почи­тай­те сна­ча­ла ту статью.

Стар­то­вый экран — это то, что выпол­ня­ет бот по коман­де /start. Сде­ла­ем на стар­то­вом экране выбор из двух кно­пок: отпра­вить новость и отпра­вить статью:

Собираем бота в конструкторе — стартовый экран Здесь три ком­по­нен­та: тек­сто­вый блок и две кнопки 

Теперь нам нуж­но сде­лать так, что­бы при нажа­тии на каж­дую из этих кно­пок бот делал то, что нам нуж­но. Для это­го созда­ём два экра­на: «Пред­ло­жить новость» и «Пред­ло­жить ста­тью» и настра­и­ва­ем дей­ствия по кнопкам:

Собираем бота в конструкторе — стартовый экран Всё, стар­то­вый экран готов, идём к новостям 

Собираем экраны «Предложить новость» и «Предложить статью»

Логи­ка экра­на будет такой:

  1. Пишем текст с пояс­не­ни­ем, что нуж­но сде­лать — напи­сать текст ново­сти или дать ссыл­ку на неё.
  2. Сохра­ня­ем ответ в отдель­ной пере­мен­ной news1.
  3. Отправ­ля­ем в наш новост­ной чат сооб­ще­ние от бота с име­нем посе­ти­те­ля, кото­рый напи­сал новость, и текст самой новости.
  4. Что­бы сооб­ще­ния не сли­па­лись, вдо­гон­ку отправ­ля­ем в тот же чат отбив­ку — линию-разделитель из несколь­ких дефисов.
  5. Если мы дошли до послед­не­го пунк­та и всё про­шло без оши­бок — пока­зы­ва­ем посе­ти­те­лю экран «Всё хоро­шо», а если на каком-то эта­пе была ошиб­ка — сра­зу пере­бра­сы­ва­ем его на экран «Что-то не так».

Сна­ча­ла посмот­рим на гото­вый экран, а потом раз­бе­рём его по шагам:

Собираем экраны «Предложить новость» и «Предложить статью» Пер­вые два экра­на соот­вет­ству­ют тому, что мы писа­ли в алго­рит­ме, а два осталь­ных — это и есть наша отправ­ка сооб­ще­ний в чат 

Каж­дую отправ­ку мы сде­ла­ли через запрос POST к API теле­гра­ма. Когда сер­вер теле­гра­ма полу­ча­ет спе­ци­аль­ным обра­зом под­го­тов­лен­ный запрос, он выпол­ня­ет какое-то дей­ствие — это назы­ва­ет­ся рабо­та по API и про это у нас есть отдель­ная ста­тья.

В нашем слу­чае все запро­сы исполь­зу­ют метод sendMessage, у кото­ро­го все­гда есть два параметра:

  1. ID полу­ча­те­ля.
  2. Текст сооб­ще­ния.

В общем виде коман­да выгля­дит так:

https://api.telegram.org/bot<ТОКЕН_БОТА>/sendMessage?chat_id=<ID_чата>&text=<Сообщение>

Мы уже зна­ем токен бота и ID чата, куда хотим отпра­вить сооб­ще­ние — это ID наше­го чата, кото­рый мы выяс­ни­ли до это­го. Под­став­ля­ем эти зна­че­ния и полу­ча­ем команду:

https://api.telegram.org/bot1738394823:AAF4h6dkgjKH88lKanJ899lpH-Jqkd5k2399sjKo/sendMessage?chat_id=-1034423424553&text=<Сообщение>

Пер­вым сооб­ще­ни­ем мы отправ­ля­ем имя того, кто пред­ло­жил новость, и сам текст ново­сти, поэто­му сооб­ще­ние будет выгля­деть так:

Новость, отправил @{{this_user.username}} → {{news1}}

Здесь {{this_user.username}} и {{news1}} — это пере­мен­ные. Пер­вая пере­мен­ная стан­дарт­ная в кон­струк­то­ре BotMother, а вто­рую сде­ла­ли мы сами на этом же экране. Пол­ный текст запро­са выгля­дит так:

https://api.telegram.org/bot1738394823:AAF4h6dkgjKH88lKanJ899lpH-Jqkd5k2399sjKo/sendMessage?chat_id=-1034423424553&text=Новость, отправил @{{this_user.username}} → {{news1}}

Сде­ла­ем по ана­ло­гии вто­рую коман­ду, кото­рая при­сы­ла­ет отбив­ку в чат, что­бы отде­лить одну новость от другой:

https://api.telegram.org/bot1738394823:AAF4h6dkgjKH88lKanJ899lpH-Jqkd5k2399sjKo/sendMessage?chat_id=-1034423424553&text=------------

👉 Вме­сто двух запро­сов на отправ­ку сооб­ще­ния мож­но было исполь­зо­вать функ­цию API теле­гра­ма forvardMessage, кото­рая про­сто пере­сы­ла­ет сооб­ще­ния. Для это­го нам пона­до­бил­ся бы поряд­ко­вый номер сооб­ще­ния в пере­пис­ке. Если бы мы писа­ли бота на питоне, с этим бы не было ника­ких про­блем, но в этом кон­струк­то­ре про­ще сде­лать отправ­кой, как у нас.

Точ­но так же соби­ра­ем экран «Пред­ло­жить статью»:

Собираем экраны «Предложить новость» и «Предложить статью» Един­ствен­ное, что поме­ня­лось на этом экране — при­вет­ствен­ный текст и имя переменной 

Собираем экраны успеха и ошибки

Что­бы было что пока­зы­вать поль­зо­ва­те­лям в слу­чае успе­ха и ошиб­ки, собе­рём два новых экра­на. Экран успе­ха будем пока­зы­вать толь­ко в кон­це послед­не­го дей­ствия — это зна­чит, что всё выпол­ни­лось хоро­шо. Пере­ход на экран ошиб­ки доба­вим к каж­до­му дей­ствию в запро­се, кото­рое реа­ги­ру­ет на ошибку.

В кон­це обо­их экра­нов доба­вим пере­ход на стар­то­вый экран. Так поль­зо­ва­тель смо­жет сра­зу отпра­вить ещё одну новость или ста­тью без лиш­них команд боту:

Собираем экраны «Предложить новость» и «Предложить статью»

Финальная схема

У нас полу­чил­ся очень про­стой бот, кото­рый реша­ет глав­ную зада­чу редак­ции на этом эта­пе: бот пере­сы­ла­ет все сооб­ще­ния поль­зо­ва­те­лей в один чат, что­бы все внеш­ние мате­ри­а­лы соби­ра­лись в одном месте.

Финальная схема

Что дальше

Нажи­ма­ем кноп­ку «Сохра­нить» в кон­струк­то­ре, и всё — бот готов к рабо­те. Теперь мож­но доба­вить кар­тин­ку и описание.

Текст и редактура:

Миха­ил Полянин

Худож­ник:

Даня Бер­ков­ский

Кор­рек­тор:

Ири­на Михеева

Вёрст­ка:

Мария Дро­но­ва

Соц­се­ти:

Олег Веш­кур­цев