Как учить Python с нуля с удовольствием: пишем своего чат-бота
Рассказываем, как быстро и просто написать бота для Telegram на Python, используя библиотеку python-telegram-bot.
Привет! Меня зовут Илья Осипов, я методист курса программирования на Python «Девман» и больше 5 лет пишу код на этом языке. Сегодня расскажу, как новичку сделать полезного чат-бота.
Python — классный язык программирования. Но многие новички учат его неправильно: почти все онлайн-курсы, тренажёры, книги и видео предлагают начинать учить Python с нуля с каких-то странных задач, вроде: «Давайте решим вот эту математическую задачку» или «Давайте напишем рекурсивный поиск чисел Фибоначчи». Вы уже тоже зеваете от скуки?
Нет, удовольствие от программирования совсем не в этом, а в том, чтобы решать реальные проблемы. Например, я втянулся в программирование, когда писал чат-бота для своего вуза. Расписание на сайте было очень неудобно смотреть. Я решил потратить время и написать чат-бота, который будет присылать мне расписание занятий в более удобном виде. Оказалось, что другим студентам тоже было неудобно, и спустя год в чат-боте накопилось 4 тысячи пользователей.
Как раз на стыке между освоением синтаксиса и решением реальных проблем, как мне кажется, и сдаются большинство начинающих программистов. Совершенно не понятно как перейти от «сложить два числа» к написанию чего-то стоящего, чем можно похвастаться родителям, друзьям, жене и собаке.
Если вы тоже обнаружили себя в этой «яме», то этот туториал для вас. Дайте себе ещё один шанс.
Шаг 1. Зайдите в Repl.it
Создайте песочницу для языка Python. Ничего устанавливать не нужно. Просто откройте эту ссылку в соседней вкладке.
Придётся зарегистрироваться, но, думаю, вы разберётесь. ?
Шаг 2. Пройдите шаг 1
Эй, хватит читать! Так дела не делаются! Чтобы научиться программировать на Python — нужно писать код своими руками, а не смотреть, как кто-то делает это за вас ?
Вы же не думаете, что можно стать альпинистом, просматривая видео, как другие люди лезут в горы? А уж инструктором вас без реального опыта и подавно никто не наймёт. С программированием то же самое.
Шаг 3. Установите библиотеку для написания ботов
Многие советуют пользоваться более сложными библиотеками для чат-ботов. Например aiogram . Она крутая и популярная, но это библиотека для асинхронного кода. Это совсем другой зверь, которого не стоит касаться новичкам. Воспринимайте асинхронные библиотеки как другой язык программирования, хотя бы на старте.
Вместо этого будем работать с куда более простой библиотекой — python-telegram-bot . Откройте меню для установки библиотек слева-снизу:
Нужна кнопка Packages.
И в появившемся окошке вбейте её название. Нажмите на «+» напротив названия и подождите загрузки. В конце появится вот такая зелёная плашка об успехе:
Название библиотеки можно скопировать прямо из статьи, не обязательно печатать. ?
Теперь сложноватый и неприятный момент, но такова разработка, за это нам и платят деньги. Нужно будет поменять версию библиотеки на более дружелюбную для новичков. Для этого нужно зайти в очень недружелюбный файл и подправить число на 13.15 . В общем-то больше ничего делать и не нужно, думаю, вы справитесь:
Очень страшно, ничего не понятно, но надо только поменять одно число.
Шаг 4. Запустите пример из документации
В документации к библиотеке есть готовые примеры кода. Давайте запустим пример эхобота.
Эхобот — это бот, который просто повторяет за вами. Отвечает вам тем же, что вы написали ему. Вот пример в документации. Я почистил его от всякого ненужного, поэтому можете взять сразу мой, он должен быть не таким страшным. Копируйте этот код в файл main.py и жмите кнопку > Run наверху. Ничего не получится, но так и нужно, об этом ниже:
from telegram import Update, ForceReply from telegram.ext import Updater, CommandHandler, MessageHandler, Filters def start(update, context): user = update.effective_user update.message.reply_text('Привет!') def echo(update, context): update.message.reply_text(update.message.text) if __name__ == '__main__': updater = Updater("TOKEN") dispatcher = updater.dispatcher dispatcher.add_handler(CommandHandler("start", start)) dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, echo)) updater.start_polling() updater.idle()
Шаг 5. Переживите шок от первой ошибки
В этом коде ошибка. Обычно новичкам от такого становится очень страшно, не хочется ни во что вникать, а поскорее закрыть консоль и больше никогда не возвращаться.
Поэтому обычно в курсах, книгах и видео ошибки от вас прячут: делают вид, что их не бывает. А вот в жизни всё совсем иначе, у программистов постоянно ошибка на ошибке, и бОльшую часть времени они тратят на то, чтобы разобраться, чего же этот Python от них хочет.
В хороших библиотеках ошибки исправлять очень легко. Они сами подсказывают вам, что делать. Давайте посмотрим, что тут написано:
Ошибка говорит, что что-то не то с токеном от Telegram. Ну и правда, вы же никаких ботов в Telegram ещё не заводили. Для запуска кода вам понадобится токен бота. Получить его можно прямо в Telegram, у официального бота @BotFather. Только не забудьте просить его с уважением!
Не переживайте, что я показываю свой токен. После публикации статьи я его удалил. .
Осталось вставить полученный токен в код и запустить его снова:
Заходите в Telegram, открывайте переписку с вашим ботом, и получайте удовольствие от беседы с цифровым другом:
Шаг 6. Начните менять код
В скопированном коде много всего страшного. Давайте коротко расскажу, как это всё работает.
Начинается исполнение кода отсюда:
if __name__ == '__main__': updater = Updater("5646004689:AAECTkuGjWo1Imwr-_6UrN-nzbo89sd3WSM") dispatcher = updater.dispatcher dispatcher.add_handler(CommandHandler("start", start)) dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, echo)) updater.start_polling() updater.idle()
Почти весь этот код можно воспринимать просто как волшебство. Это штуки, которые запускают бота. Я сам толком не уверен, что там происходит внутри. Их просто не нужно менять, почти никогда.
Единственное, что пригодится — это строчки, начинающиеся с dispatcher.add_handler . Это «интеллект» вашего бота. По ним он определяет, как ему реагировать на ваше сообщение. Вот как эти строчки расшифровываются:
А вот что внутри функции echo:
def echo(update, context): update.message.reply_text(update.message.text)
Если просто перевести код на русский, становится понятнее:
Шаг 7. Веселитесь!
В документации python-telegram-bot есть масса примеров использования библиотеки. Там же можно подсмотреть как отправить фотку в Telegram или как создать отложенную задачу.
Остаётся только придумать, что будет делать ваш бот, разбить задачу на части и понемногу кодить его, добавляя и слегка переписывая примеры из документации.
Если вы будете достаточно упорны и потратите на это хотя бы пару месяцев, то станете настоящим крутаном. Останется дополнить свой стек другими технологиями, изучая их аналогичным образом, и всё получится.
Бот в Telegram на Питоне от А до Я
В социальных сетях и мессенджерах огромную популярность набрали так называемые боты. Они пишутся на разных языках программирования, внедряются в ПО и активно применяются на практике.
В данной статье будет рассказано о том, как написать простой бот на Python. А еще – рассмотрены особенности соответствующего ЯП, преимущества и недостатки упомянутого «виджета». Примеры будут приведены на основе Telegram. Здесь bot – это весьма распространенное явление.
Бот – это…
Это специализированный робот-помощник. Он помогает выполнять любые рутинные занятия. Боты способны реализовывать программные коды, которые будут отвечать за активацию разных команд со стороны пользователей.
Переписка с таким ПО осуществляется непосредственно через чат. Клиент дает боту команды, которые он обрабатывает и выполняет в режиме 24/7. Ключевая задача “робота» – дать ответ на вопрос клиента, опираясь на заданную программу. С помощью оных удается экономить не только время, но и остальные ресурсы.
Умения
Бот Телеграмм умеет многое. Сегодня к спектру его навыков относят следующие моменты:
- проведение обучения;
- развлечение публики;
- предложение и запуск «мини-игр»;
- работа с поисковыми системами в пределах Сети;
- скачивание данных – фото, видео, аудио, документов;
- выступать в качестве напоминалки;
- участие в групповых чатах для решения заранее определенного спектра задач (пример – согласование оптимального времени встречи);
- комментирование постов и статей;
- использование функций управления умным домом и другими подобными устройствами.
Bots – это связующее звено между пользователями и интернетом, а также конкретной компанией. Пользоваться ими не очень трудно. Первое, что нужно сделать – это определиться со спектром задач, поручаемых боту. После – написать грамотный код и внедрить его в мессенджер. Это способен сделать даже начинающий разработчик.
Преимущества и недостатки
Как и любое другое ПО, bot – это «виджет», который имеет ряд сильный и слабых сторон. Их предстоит учитывать каждому, кто хочет подключить соответствующего «помощника» в своем чате/диалоге.
Сильные стороны
К преимуществам ботов Телеграм относят:
- круглосуточную помощь – функционирование bots прекратят только в случае аварий на серверах, которые случаются крайне редко;
- удобство и простоту использования – для большинства команд достаточно выбрать из предложенного списка подходящую операцию;
- мгновенное получение ответа;
- отсутствие требований к мощности задействованного устройства – это связано с тем, что для работы ботов используются возможности сторонних серверов;
- высокий уровень безопасности;
- отсутствие необходимости инициализации дополнительного ПО для запуска рассматриваемого вида «помощника».
Ботов применять удобно и интересно. Они упрощают жизнь и владельцу чата/компании, и непосредственным клиентам/участникам диалога.
Слабые стороны
Минусы у такого ПО тоже есть, но они не слишком весомые:
- составлять bot должен программист – тот, кто далек от данной сферы деятельности, будет долго разбираться в принципах коддинга;
- писать бота лучше на одном языке – через Питон;
- нужно заранее хорошо продумать навигационное меню – тем, кто раньше не имел дела с подобным контентом, может потребоваться немало времени для этого.
Бот должен быть полезным, отвечать потребностям ЦА, а также целям владельца чата. Составить его удастся «с нуля» за 15-30 минут. Особенно если придерживаться определенного алгоритма действий.
Почему Питон
Python – универсальный язык программирования с возможностью использования принципов ООП. Он обладает простым и понятным синтаксисом, освоить который еще проще, зная английский.
Бот, написанный на Python, будет отличаться скоростью, безопасностью и стабильностью. Сам ЯП предусматривает следующие преимущества:
- функциональность;
- разделение итоговой кодификации на блоки, что позволяет значительно повысить ее читаемость;
- поддержка длинной арифметики;
- кроссплатформенность;
- огромное количество библиотек, которые смогут выручить в любое время;
- понятный синтаксис.
Это – идеальный вариант для веб-разработки, приложений для мессенджеров и мелких проектов. Крупные и масштабные игры на чистом Python составить не получится. Для этого предстоит подучить Java или C++.
Составление софта
Bot – это просто и удобно. Телеграм позволяет внедрять и искать такие «виджеты» без особого труда. Хорошего бота удастся составить менее чем за час. Главное – придерживаться определенного алгоритма действий.
Принцип
Перед непосредственной разработкой необходимо разобраться в том, как все будет работать. Bot для «Телеги» функционирует по определенным принципам. Пример будет рассмотрен на компьютере и Telegram-клиенте.
Стоит обратить внимание на следующее:
- На компьютере есть интерпретатор Python. Также на устройство необходимо поставить сервер Телеграмма и клиент.
- Внутри интерпретатора будет функционировать программа-бот. Она будет отвечать за весь софт: в оной прописана логика и шаблоны, а также возможные операции.
- Внутри приложения, написанного через Питон, имеется библиотека, отвечающая за связь с сервером Telegram. В нее нужно вшить секретный ключ. Это поможет указать серверу клиента, что программа связана с конкретным ботом.
- Когда клиент с «Телегой» осуществляет запрос гороскопа, bot осуществляет выгрузку на сервер, а сервер – выводит результат на компьютер.
- Запрос будет проходить обработку через утилиту на Python, дает ответ на сервер Телеграмма.
- Сервер передает необходимый результат непосредственному пользователю.
Bot внедряется без особого труда. Описанный принцип действий актуален не только для гороскопов. Он подойдет для bot любого вида в мессенджере.
Краткий план – пошагово
Чтобы bot Телеграм работал, можно представить процедуру его подключения так:
- Провести регистрацию нового бота в мессенджере.
- Установить Питон-библиотеку для работы с Telegram.
- Добавить библиотеку в программу с гороскопом.
- Научить bot реагировать на сообщения в пределах чата.
- Прописать там же кодификацию, которая отвечает за кнопки выбора знака зодиака.
- Сделать так, чтобы при клике по кнопке отображался гороскоп выбранного варианта.
Каждый этап предусматривает собственные нюансы и особенности, о которых должен помнить каждый разраб. Иначе справиться с поставленной задачей не получится.
Регистрация
Для того, чтобы зарегистрировать нового бота в Телеграмме, нужно:
- Открыть соответствующий мессенджер.
- При помощи командной строки найти @BotFather. Он несет ответ за регистрацию нового bot.
- Кликнуть по надписи Start, а также указать команду / newbot.
- Система задаст поочередно вопросы о названии бота и его ника. Имя должно быть уникальным. С первого раза установить его не всегда получается.
На этом первый этап подготовки завершен. Можно двигаться дальше.
Библиотека и ее инициализация
Следующий этап – это установка подходящей библиотеки Python. Работать с «Телегой» можно через telebot. Второй вариант – это инициализация Webhook. Первый вариант проще, поэтому заострим внимание на нем:
- Запустить командную строку от имени администратора на устройстве.
- Набрать команду pip install pytelegrambotapi.
- Подтвердить обработку операции.
- Чтобы приложение понимало бота, в самое начало кода требуется добавить: import telebot;
- Bot = telebot.TeleBot(«токен»);.
- Вместо слова «токен» вставить настоящий токен, выданный @BotFather.
- Открыть программу гороскопа и добавить ее.
Перед тем, как импортировать приложение гороскопа, необходимо его написать. Сделать его требуется на Питоне.
Гороскоп программа
Вот так будет выглядеть код приложения, который отвечает за отображение информации о гороскопах. Создается контент в программной среде Питона:

Сразу после формирования ПО можно приступить к следующему этапу настройки.
Реакции
Bot должен реагировать на слово «Привет». После него будет выдана реакция на соответствующую фразу. Чтобы все работало нормально, необходимо добавить после строчек импорта новый метод. Он отвечает за соответствующую операцию:
@bot.message_handler(content_types=['text']) def get_text_messages(message): if message.text == "Привет": bot.send_message(message.from_user.id, "Привет, сейчас я расскажу тебе гороскоп на сегодня.") elif message.text == "/help": bot.send_message(message.from_user.id, "Напиши Привет") else: bot.send_message(message.from_user.id, "Я тебя не понимаю. Напиши /help.")

- Добавить после метода строку типа: bot.polling(none_stop=True, interval=0) .
- После ее добавления у бота будет постоянно проверяться наличие новых сообщений.
- Прописать код, который предполагает работу с кнопками. Сначала осуществляется вывод всех знаков зодиака. При клике по конкретной – отображается гороскоп оного.
- Добавить обработчик кнопок. Он будет реагировать на слово zodiac. При написании оного в программе отобразится случайный текст:
# Обработчик нажатий на кнопки @bot.callback_query_handler(func=lambda call: True) def callback_worker(call): # Если нажали на одну из 12 кнопок — выводим гороскоп if call.data == "zodiac": # Формируем гороскоп msg = random.choice(first) + ' ' + random.choice(second) + ' ' + random.choice(second_add) + ' ' + random.choice(third) # Отправляем текст в Телеграм bot.send_message(call.message.chat.id, msg)
- Можно убрать кодификацию, которая ранее отвечала за вывод знаков зодиака в консоли. После очистки получится приложение:


На этом рассматриваемый «помощник» окончен. Теперь все должно нормально работать. Остается запустить его в Телеграме и получить тот или иной результат.
Команды управления
«Помощник» имеет разные функции и команды. Они пишутся через знак «слеш» («/») прямо в сообщении чата. Вот основные операции:
- /start – начать работу помощника;
- /help – вывод помощи на экран;
- /settings – открыть настройки.
Некоторые подобные «дополнения» способны понимать команды на русском языке. Пример – запрос у робота Антона, который «подрабатывает» в Гидрометцентре. Если при общении с ним прописать «Погода Калининград», будет выведен соответствующий результат.
Почему «молчит»
Иногда бывает так, что «помощник» не отвечает. Такое наблюдается при вводе любой команды/выбора подходящего варианта из меню. Данное явление может происходить по нескольким причинам:
- Проблемы и неполадки на сервере. Пример – сбой или полный отказ оного от функционирования.
- Ошибки при написании кодификации. Распространенное явление среди новичков.
- Ввод команды, которую Телеграм бот на Python не понимает. В этом случае можно воспользоваться Google для поиска подходящих операций и их форматов.
Иногда помогает полное отключение и перезапуск «помощника».
Как быстро освоить Python
Питон и его возможности можно выучить в ВУЗе, техникуме или самостоятельно поисках материалы в Сети. Вот видео по боту в «Телеге». Самообразование – один из лучших, но долгих методов обучения.
А чтобы надписи типа examples, def get, main() и другие не доставляли хлопот, стоит пройти дистанционные курсы. Их преимущества:
- Доступность. Обучение можно проводить в любом месте и в любое время, имя под рукой интернет.
- Разнообразие направлений. Есть предложения для новичков и опытных программеров.
- Срок обучения – до 12 месяцев. За это время пользователь сможет освоить даже несколько направлений.
- Хорошо продуманная программа, подпитанная практикой и кураторством опытных разработчиков.
По завершении процесса пользователь получит сертификат, подтверждающий навыки и познания в выбранной области.
Введение, простой echo-бот
Приветствую тебя, читатель! Telegram Bot API – это мощный инструмент для вообще чего угодно. Автоматизация действий, работа с пользователями, онлайн-магазины, игры и много чего ещё. В этом учебнике мы научимся писать ботов для Telegram на языке Python.
Сразу оговорюсь: тот бот, который получится в итоге — это лишь прототип, цель всех этих постов — рассказать об основах ботостроения, показать, как можно за короткое время написать простого бота для своих нужд.
Язык программирования будет Python 3, но это не означает, что любители PHP, Ruby и т.д. в пролёте; все основные принципы совпадают. Я не буду особо останавливаться на описании самого языка, желающие могут ознакомиться с документацией по Python здесь.
Подготовка к запуску
Взаимодействие ботов с людьми основано на HTTP-запросах. Чтобы не мучаться с обработкой «сырых» данных, воспользуемся библиотекой pyTelegramBotAPI, которая берет на себя все нюансы отправки и получения запросов, позволяя сконцентрироваться непосредственно на логике. Установка библиотеки предельно простая:
pip install pytelegrambotapi python3
Скриншот из терминала с запущенным интерпретатором Python
Обратите внимание: библиотека называется pyTelegramBotAPI , а не telebot . Последнюю ставить не нужно!
Теперь можно выйти из режима Python-консоли (Ctrl+Z или Ctrl+D, или exit() )
Пишем простого echo-бота
Ну, довольно слов, перейдем к делу. В качестве практики к первому уроку, напишем бота, повторяющего присланное текстовое сообщение. Создадим каталог, а внутри него 2 файла: bot.py и config.py . Я рекомендую выносить различные константы и настройки в файл config.py , дабы не загромождать другие. В файл config.py впишем:
# Токен ненастоящий :) Подставьте свой token = '1234567890:AAE_abCDEFghijKLmNOpqRsTuVWxyz'
Теперь надо научить бота реагировать на сообщения. Напишем обработчик, который будет реагировать на все текстовые сообщения.
@bot.message_handler(content_types=["text"]) def repeat_all_messages(message): # Название функции не играет никакой роли bot.send_message(message.chat.id, message.text)
У читателя возникнет вопрос: зачем там символ “@”? Что это вообще за message_handler ? Дело в том, что после приёма сообщения от Telegram его надо обработать по-разному в зависимости от того, что это за сообщение: текст “привет” или текст “пока”, может быть, вообще стикер или музыка. Первое, что придёт в голову – написать множество конструкций if-then-else , но такой подход некрасивый и позволяет быстро запутаться.
Для решения этой проблемы автор библиотеки pyTelegramBotAPI реализовал механизм хэндлеров, которые используют питоновские декораторы (пока просто запомним это слово). В хэндлере описывается, в каком случае необходимо выполнять ту или иную функцию. Например, хэндлер @bot.message_handler(content_types=[«text»]) выполнит нижестоящую функцию, если от Telegram придёт текстовое сообщение, а хэндлер @bot.message_handler(commands=[«start»]) сработает при получении команды /start.
Теперь запустим бесконечный цикл получения новых записей со стороны Telegram:
if __name__ == '__main__': bot.infinity_polling()
Функция infinity_polling запускает т.н. Long Polling, бот должен стараться не прекращать работу при возникновении каких-либо ошибок. При этом, само собой, за ботом нужно следить, ибо сервера Telegram периодически перестают отвечать на запросы или делают это с большой задержкой приводя к ошибкам 5xx)
Итак, полный код файла bot.py выглядит следующим образом:
import config import telebot bot = telebot.TeleBot(config.token) @bot.message_handler(content_types=["text"]) def repeat_all_messages(message): # Название функции не играет никакой роли bot.send_message(message.chat.id, message.text) if __name__ == '__main__': bot.infinity_polling()
Готово! Осталось запустить бота: python3 bot.py
Бот работает
На этом первый урок окончен.
Как подключить платежную систему с Payments к Telegram
Рассказываем, как подключить платежную систему к Telegram-боту и разместить его на сервере.
Эта инструкция — часть курса «Как создавать Telegram-ботов».
Смотреть весь курс
Введение
Telegram-боты обладают широкой функциональностью и решают массу задач клиентов самых разных бизнесов. Рассказываем, как создать и разместить бота для приема платежей в Telegram на Python. Видеоверсия доступна по ссылке.
В Telegram есть встроенная система оплаты, поэтому сценариев, как использовать бота для приема платежей, достаточно много. Это может быть разовая оплата заказа или ежемесячная подписка.
Платежные системы Telegram
Сейчас мессенджер поддерживает оплату в более чем 200 странах через такие шлюзы, как: Stripe, YooMoney, Sberbank, LiqPay, PayMaster и другие.
Все начинается с установки библиотеки aiogram. Сейчас, пожалуй, это самая популярная библиотека для разработки ботов на Python.
python -m pip install aiogram
Переходим в Telegram и пишем тут BotFather’у команду /newbot. Вводим имя нового бота. Важно, чтобы оно заканчивалось словом Bot.

Получаем уникальный токен нового бота. Теперь напишем код простейшего эхо-бота, чтобы проверить его работу.
Связать бота с приложением
Создаем файл config.py и вписываем в него токен, который выдал BotFather. В основном файле main.py прописываем базовый код любого бота.
Обратите внимание на один важный момент: бот должен обрабатывать каждое сообщение с серверов Telegram. Для этого при запуске бота обязательно нужно поставить аргумент skip_updates в значение False. Это спасет от проблем при обработке платежей.
import config import logging from aiogram import Bot, Dispatcher, executor, types from aiogram.types.message import ContentType # log logging.basicConfig(level=logging.INFO) # init bot = Bot(token=config.TOKEN) dp = Dispatcher(bot) # echo bot @dp.message_handler() async def echo(message; types.Message): await message.answer (message.text) # run long-polling if __name__ == "main": executor.start_polling(dp, skip_updates=False)
Теперь можно запустить код и проверить, работает ли бот. Убедившись, что все хорошо, приступаем к подключению платежей.

Возвращаемся к BotFather’у, даем команду /mybots и выбираем из списка своего бота.
В открывшемся меню кликаем на кнопку «Payments». Из предоставленного списка выбираем нужный платежный шлюз. В качестве теста используем PayMaster. Чтобы подключить оплату в Telegram-бота, сначала нужно выполнить тест, поэтому выбираем «PayMaster Test».

Следуем простым инструкциям бота платежной системы и получаем тестовый токен PayMaster. Его сразу же можно сохранить в config.py.
TOKEN = "5432877141:AAHEwBEb2mwnZX56oaHM10o33ZBZwVkvv-s" PAYMENTS_TOKEN = "1744374395:TEST:f14d9f0d42528b780370"
Возвращаемся к коду бота. Для того, чтобы запросить оплату товаров/услуг, нужно сгенерировать invoice с деталями платежа. Отправить его клиенту и обработать результат.
Подключаем оплату
Указываем список доступных цен на продукты. В качестве цены нужно передать целочисленное значение в минимально возможных единицах валюты. Если речь идет о рублях, то стоимость нужно указывать в копейках. То есть место 500 рублей мы тут укажем 500 * 100 или же 50 000 копеек. В случае с долларами будет почти также, $1=100 центов. Если предполагается работа с другими валютами, можно использовать currencies.json от Telegram API.
Дальше в коде бота платежной системы мы создаем обработчик команды /buy. Команда будет генерировать и отправлять пользователю invoice платежа. В примере используется оплата месячной подписки.
import config import logging from aiogram import Bot, Dispatcher, executor, types from aiogram.types.message import ContentType # log logging.basicConfig(level=logging.INFO) # init bot = Bot(token=config.TOKEN) dp = Dispatcher(bot) # prices PRICE = types.LabeledPrice(label="Подписка на 1 месяц", amount=500*100) # в копейках (руб) # buy @dp.message_handler(commands=['buy']) async def buy(message: types.Message): if config.PAYMENTS_TOKEN.split(':')[1] == 'TEST': await bot.send_message(message.chat.id, "Тестовый платеж. ") await bot.send_invoice(message.chat.id, title="Подписка на бота", description="Активация подписки на бота на 1 месяц", provider_token=config.PAYMENTS_TOKEN, currency="rub", photo_url="https://www.aroged.com/wp-content/uploads/2022/06/Telegram-has-a-premium-subscription.jpg", photo_width=416, photo_height=234, photo_size=416, is_flexible=False, prices=[PRICE], start_parameter="one-month-subscription", payload="test-invoice-payload")
Сам процесс генерации invoice довольно простой. Не стоит беспокоиться большому количеству аргументов. Это названия продуктов или услуг, описания, цена, валюта и т.п.

Настройки платежей
Обратите внимание на аргумент is_flexible. Его нужно указывать в значение True только в том случае, если финальная стоимость зависит от выбранного способа доставки, если речь идет о продаже какого-то физического продукта.
О других параметрах метода send_invoice вы всегда можете прочитать в официальной документации Telegram API.
Теперь нужно создать еще два обработчика: Pre Checkout Query и Successful Payment.
Pre Checkout Query отвечает за обработку и утверждение платежа перед тем, как пользователь его совершит. Так можно проверить доступность товара на складе или уточнить стоимость.
Важно, что серверам Telegram ответ нужен в течение 10 секунд. Если его не будет, платеж не пройдет.
Successful Payment отвечает за обработку успешно проведенного платежа.
# pre checkout (must be answered in 10 seconds) @dp.pre_checkout_query_handler(lambda query: True) async def pre_checkout_query(pre_checkout_q: types.PreCheckoutQuery): await bot.answer_pre_checkout_query(pre_checkout_q.id, ok=True) # successful payment @dp.message_handler(content_types=ContentType.SUCCESSFUL_PAYMENT) async def successful_payment(message: types.Message): print("SUCCESSFUL PAYMENT:") payment_info = message.successful_payment.to_python() for k, v in payment_info.items(): print(f" = ") await bot.send_message(message.chat.id, f"Платеж на сумму прошел успешно. ") # run long-polling if __name__ == "__main__": executor.start_polling(dp, skip_updates=False)
Тут можно выдать пользователю тот самый месяц подписки, за которую он заплатил или любую другую услугу.
Как бот работает на практике
Получив invoice на оплату от бота, нажимаем «Оплатить». Поскольку сначала мы проводим тестирование бота, воспользуемся специальной тестовой картой.

Вводим данные и оплачиваем подписку — все работает. При переходе на боевой проект важно не забыть выбрать правильный счет.
Теперь возвращаемся в BotFather, чтобы получить реальный токен от выбранного платежного шлюза. Если есть запрос на разные тарифы или способы оплаты, лучше запросить сразу 2-3 токена от разных платежных шлюзов. Далее нужно будет генерировать invoice с помощью токена выбранного провайдера.
Перенос бота на боевой сервер
Чтобы бот работал 24/7 вне зависимости от того, включен компьютер или нет, зальем его на реальный сервер.
Для этого воспользуемся облачным сервером линейки Shared Line от Selectel. Калькулятор панели управления позволяет выбрать гибкую конфигурацию сервера и сразу узнать, сколько будет стоить решение. Все продукты и услуги собраны у провайдера в одном месте, поэтому ими легко управлять. Арендовать сервер можно от 10 ₽/день, а в консоли есть возможность быстро масштабировать вычислительные ресурсы при необходимости.
Регистрируемся и входим в панель управления my.selectel.ru. Переходим в раздел «Облачная платформа» и выбираем «Серверы». Создаем сервер — после этого шага он загорится в списке как «ACTIVE».
Настраиваем конфигурацию. Для примера используем 1 ядро, 512 МБ DDR4 и 5 ГБ на диске.

Теперь переходим к выгрузке бота на боевой сервер. Сначала нужно подключиться к серверу через SSH. Для этого мы можем воспользоваться программой WinSCP для Windows. В Linux и MAC для этого есть свои встроенные инструменты.
Запускаем WinSCP. В качестве имени хоста указываем IP адрес нашего нового сервера. Логин и пароль можно взять во вкладке «Консоль» в панели управления.
Теперь перенесем сюда файлы нашего бота: config.py и main.py. Далее открываем отдельное соединение с сервером по SSH в консоли.
Для этого в WinSCP нажать кнопку и открыть PuTTY. Можно также воспользоваться командной строкой, принципиальной разницы нет.
Настройка бота с Payments 2.0
Подключившись к серверу, нужно выполнить ряд простых действий.
- Обновить Python до версии 3.10.
- Установить PIP.
- Поставить библиотеку Aiogram.
Если оставить все в таком виде, то при закрытии SSH-соединения вместе с ним закроется и процесс бота. Что делать?
Есть несколько способов, как решить этот вопрос. Рассмотрим самый простой – использование команды screen.
Пишем команду screen и жмем Enter. Запускаем бота из обычного терминала и закрываем соединение.
Бот продолжит работу. Чтобы в любой момент вернуться к этому экрану, достаточно ввести команду screen -r $screen_running. На этом деплой в облаке Selectel закончен.
Заключение
Описанная схема запуска Telegram-бота не предел того, как можно настроить прием платежей. К боту всегда можно добавить дополнительные возможности: запрашивать адрес доставки или менять цену в зависимости от адреса.
Идеальное решение для pet-проектов
Сервер для решения задач, которые не требуют полной загрузки vCPU.
Особые апдейты¶
Почти все виды событий в Telegram имеют какое-то внешнее представление для юзера. Служебные сообщения, обычные, колбэки, инлайн-режим. но есть два вида апдейтов, предназначенные именно для самих ботов. Речь пойдёт о my_chat_member и chat_member
Когда-то давным-давно боты в группах существовали в «информационном вакууме»: банально на любые модераторские действия, будь то баны или ограничения, необходимо было проверять права вызывающего юзера через методы getChatMember или getChatAdministrators, да ещё и кэшировать на небольшой промежуток времени, дабы не упереться в лимиты Bot API, точные значения которых [лимитов] по-прежнему остаются тайной за семью печатями.
Или, например, какой-нибудь хитрый юзер добавлял бота в группу, убирал у того право писать и начинал дёргать команды, ожидая, что бот не обрабатывает такую ошибку и сломается. А уж с отправкой в личку вообще весело: не зная точно, какая активная аудитория бота, разработчику приходилось либо отправлять какое-нибудь сообщение по списку пользователей в своей базе, либо, что чуть гуманнее, отправлять этим юзерам какой-нибудь ChatAction, типа «печатает…»; как выяснилось, тем, кто заблокировал бота, это самое «печатает…» не придёт, вернув ошибку от Bot API.
В марте 2021 года ситуация кардинально изменилась в лучшую сторону с релизом обновления Bot API v5.1, в котором добавилось два новых типа апдейтов: my_chat_member и chat_member . Оба апдейта внутри содержат объект одного и того же типа ChatMemberUpdated. Разница между этими двумя событиями следующая:
- my_chat_member . Здесь всё, что касается непосредственно бота, либо ЛС юзера с ботом: (раз)блокировки бота юзером в ЛС, добавление бота в группу или канал, удаление оттуда, изменение прав бота и его статуса в разных чатах и т.д.
- chat_member . Содержит все изменения состояния пользователей в группах и каналах, где бот состоит в качестве администратора: приход/уход юзеров в группы, подписки/отписки в каналах, изменение прав и статусов пользователей, назначение/снятие админов и многое другое.
По умолчанию Telegram не присылает ботам апдейты chat_member , их приём надо включить отдельно. Подробнее — в соответствующем разделе
В данной главе мы попробуем рассмотреть эти апдейты на наиболее часто необходимых задачах, однако перед переходом к следующим разделам настоятельно рекомендую ознакомиться с этой страницей из документации aiogram 3.x.
Объект ChatMemberUpdated¶
Сам по себе объект ChatMemberUpdated заслуживает отдельного внимания. Чтобы изучить его поближе, предположим, в некоторой группе администратор Алиса забанила обычного участника Витю. С полями chat и date всё очевидно, их пропустим.
Поле from (в вашем Python-коде это будет from_user ) содержит информацию о субъекте действия. В нашем случае, субъект действия — это Алиса, поэтому во from ( from_user ) будет объект User с данными об Алисе.
old_chat_member и new_chat_member . Под этими полями скрываются «состояния» объекта действия ДО и ПОСЛЕ события. Соответственно, в old_chat_member будет объект с типом ChatMemberMember (это не опечатка), и полем user с информацией о Вите, а в new_chat_member — объект ChatMemberBanned с полем user всё про того же несчастного Виктора.
Наконец, если в группу или канал вступила условная Маша, то в объекте ChatMemberUpdated будет непустое поле invite_link , с типом ChatInviteLink и сведениями о том, по какой именно пригласительной ссылке она пришла.
О пригласительных ссылках
Здесь стоит сделать важную ремарку: каждый администратор группы/канала (включая ботов) может создать множество пригласительных ссылок с разными параметрами. Если бот «поймал» вступление участника по созданной им [ботом] же ссылке, то в поле invite_link объекта ChatInviteLink будет видна ссылка целиком (без https://t.me , разумеется). Но если участник пришёл по ссылке другого администратора, то бот увидит только первую часть, вторая будет заменена на многоточие.
Вероятнее всего, это сделано для того, чтобы боты не могли отправлять кому попало пригласительные ссылки, созданные другими администраторами чата.
Кстати, по какой-то странной телеграмной логике, если вступить в публичную группу по пригласительной ссылке (даже не по юзернейму), то бот не увидит ссылку (получит None ). Телега ♂️
Апдейт my_chat_member¶
Баны/разбаны в ЛС¶
В профильных чатах периодически возникает вопрос: «как сделать рассылку пользователям бота, если кто-то мог его заблокировать?». Разумеется, первым и главным советом будет: «создай канал», потому что каналы — это лучший способ информировать пользователей о чём-либо.
Но если вы всё же твёрдо решили, что будете делать рассылку пользователям прямо через бота, то существует три основных способа актуализации действующих пользователей бота:
- Непосредственно во время совершения рассылки путём отлова ошибок отправки и внесения изменений в базу данных пользователей.
- Через периодическую отправку какого-либо ChatAction, например, «печатает» по списку пользователей.
- Прослушиванием апдейта my_chat_member.
Сейчас нас интересует только п.3. Научимся с помощью my_chat_member определять, что пользователь заблокировал или разблокировал бота. Но прежде, чем попробуем «магию» aiogram, разберёмся, как упомянутые ситуации выглядят в самом Bot API. Для этого остановим процесс с ботом, откроем диалог с ним в Telegram и последовательно заблокируем и разблокируем, используя опции в UI мессенджера. Далее откроем веб-браузер или какой-нибудь Insomnia/Postman и перейдём по ссылке https://api.telegram.org/bot/getupdates , чтобы увидеть ещё не обработанные сообщения в формате JSON.
Итак, вот что приходит боту, когда кто-то его блокирует:

На что надо обратить внимание:
- Событие my_chat_member произошло в ЛС с пользователем Groosha (chat_id равен моему Telegram ID).
- Инициатор (субъект) события — тоже Groosha.
- В поле old_chat_member видно, над кем произведено действие (над ботом) и какой статус бота в ЛС был ДО: «member», т.е. бот НЕ был заблокирован ранее.
- В поле new_chat_member содержимое user то же самое, а вот статус уже «kicked», т.е. ПОСЛЕ события бот был заблокирован пользователем.
То есть, бот в ЛС с Groosha совершил переход своего состояния из «member» в «kicked». Теперь посмотрим, что пришло от Telegram после разблокировки:

Этот скриншот похож на предыдущий, но если присмотреться, то можно заметить разницу: другой update_id (увеличился на единицу), а также статусы ДО и ПОСЛЕ поменялись местами. Бот в ЛС с Groosha совершил переход из «kicked» в «member».
Кроме того, обычно рядом будет ещё один апдейт уже с типом message и с командой /start в содержимом. Официальные клиенты при разблокировке бота сразу отправляют команду /start , но не стоит на это полагаться: подобные действия остаются на откуп клиентам, которые могут вести себя по-разному.
Теперь научимся реагировать на такие события через aiogram на простом примере: пусть у нас есть список из двух активных пользователей бота с айди 111 и 222. По команде /start добавим юзера в список рассылки, а по команде /users будем выводить айди тех, кто не заблокировал бота (другими словами, при блокировке бота будем убирать айди из списка, а при разблокировке снова добавим).
Вот готовый роутер под вышеописанные условия:
handlers/in_pm.py
from aiogram import F, Router from aiogram.filters.chat_member_updated import \ ChatMemberUpdatedFilter, MEMBER, KICKED from aiogram.filters.command import \ CommandStart, Command from aiogram.types import ChatMemberUpdated, Message router = Router() router.my_chat_member.filter(F.chat.type == "private") router.message.filter(F.chat.type == "private") # Исключительно для примера! # В реальной жизни используйте более надёжные # источники айди юзеров users = 111, 222> @router.my_chat_member( ChatMemberUpdatedFilter(member_status_changed=KICKED) ) async def user_blocked_bot(event: ChatMemberUpdated): users.discard(event.from_user.id) @router.my_chat_member( ChatMemberUpdatedFilter(member_status_changed=MEMBER) ) async def user_unblocked_bot(event: ChatMemberUpdated): users.add(event.from_user.id) @router.message(CommandStart()) async def cmd_start(message: Message): await message.answer("Hello") users.add(message.from_user.id) @router.message(Command("users")) async def cmd_users(message: Message): await message.answer("\n".join(f"• user_id>" for user_id in users))
Обратите внимание: для хэндлеров на апдейт my_chat_member мы используем фильтр ChatMemberUpdatedFilter с указанием отлавливаемого результата ПОСЛЕ (т.е. атрибут new_chat_member у апдейта). Т.е. в данном случае нас не интересует, в каком состоянии был юзер ДО.
И вот как это выглядит на практике:
Добавление в группу¶
Ещё частый вопрос от начинающих разработчиков: «как поймать событие добавления бота в группу?». Что ж, давайте разбираться. Но перед этим посмотрим, какие вообще могут быть «статусы» пользователя:
- creator (он же owner) — владелец чата. Судя по всему, бот не может иметь такой статус. Владелец безальтернативно имеет все возможные права в чате, кроме «анонимности», она переключается туда-сюда свободно.
- administrator — любой другой администратор. В интерфейсе приложений можно убрать ему вообще все права, но он всё равно останется администратором и сможет, например, читать Recent Actions и игнорировать slow mode.
- member — участник чата с правами по умолчанию. Узнать эти «права по умолчанию» в случае с группами можно, вызвав API-метод getChat и посмотрев поле permissions .
- restricted — пользователь, ограниченный в каких-то правах. Например, находящийся в т.н. «read-only». ВАЖНО: в состоянии restricted юзер может как находиться в группе, так и не находиться, поэтому у ChatMemberRestricted надо дополнительно проверять флаг is_member .
- left — «он улетел, но обещал вернуться», т.е. пользователь вышел из группы, но при желании может снова зайти. И на момент выхода он не был в состоянии restricted .
- banned — пользователь забанен и не может вернуться самостоятельно, пока его не разбанят.
Имея под рукой вышеизложенную информацию, нетрудно догадаться, что событие «бота добавили в группу» — это переход из набора состояний в набор . Такой переход по-английски называется transition, и в aiogram 3.x уже есть заготовки.
Вариант №1: тупо перечислим все состояния ДО и ПОСЛЕ:
# Не забываем импорты: from aiogram.filters.chat_member_updated import \ ChatMemberUpdatedFilter, KICKED, LEFT, MEMBER, \ RESTRICTED, ADMINISTRATOR, CREATOR @router.my_chat_member( ChatMemberUpdatedFilter( member_status_changed= (KICKED | LEFT | -RESTRICTED) >> (+RESTRICTED | MEMBER | ADMINISTRATOR | CREATOR) ) )
Вертикальная черта означает «или», битовый оператор «>>» показывает направление перехода, а символы «плюс» и «минус» около RESTRICTED относятся к флагу is_member (плюс — True, минус — False).
Но разработчик aiogram пошёл дальше и обернул эти два набора в отдельные состояния IS_NOT_MEMBER и IS_MEMBER соответственно. Упростим наш код в виде варианта №2:
# Немного другие импорты from aiogram.filters.chat_member_updated import \ ChatMemberUpdatedFilter, IS_NOT_MEMBER, IS_MEMBER @router.my_chat_member( ChatMemberUpdatedFilter( member_status_changed= IS_NOT_MEMBER >> IS_MEMBER ) )
Но поскольку, повторюсь, такой переход довольно часто используется в ботах, то разработчик пошёл ещё дальше и обернул такой переход в виде переменной JOIN_TRANSITION , получив вариант №3:
# И ещё меньше импортов from aiogram.filters.chat_member_updated import \ ChatMemberUpdatedFilter, JOIN_TRANSITION @router.my_chat_member( ChatMemberUpdatedFilter( member_status_changed=JOIN_TRANSITION ) )
Настоятельно рекомендую ознакомиться со всеми наборами состояний и переходов в документации, чтобы сделать свой код чище.
Теперь создадим ещё один роутер, под которым будут два хэндлера, реагирующие на добавление бота в группу или супергруппу в роли администратора и обычного участника. При добавлении будем отправлять в чат сводную информацию о том, куда добавили бота:
handlers/bot_in_group.py
from aiogram import F, Router from aiogram.filters.chat_member_updated import \ ChatMemberUpdatedFilter, IS_NOT_MEMBER, MEMBER, ADMINISTRATOR from aiogram.types import ChatMemberUpdated router = Router() router.my_chat_member.filter(F.chat.type.in_("group", "supergroup">)) chats_variants = "group": "группу", "supergroup": "супергруппу" > # Не удалось воспроизвести случай добавления бота как Restricted, # поэтому примера с ним не будет @router.my_chat_member( ChatMemberUpdatedFilter( member_status_changed=IS_NOT_MEMBER >> ADMINISTRATOR ) ) async def bot_added_as_admin(event: ChatMemberUpdated): # Самый простой случай: бот добавлен как админ. # Легко можем отправить сообщение await event.answer( text=f"Привет! Спасибо, что добавили меня в " f'chats_variants[event.chat.type]> "event.chat.title>" ' f"как администратора. ID чата: event.chat.id>" ) @router.my_chat_member( ChatMemberUpdatedFilter( member_status_changed=IS_NOT_MEMBER >> MEMBER ) ) async def bot_added_as_member(event: ChatMemberUpdated): # Вариант посложнее: бота добавили как обычного участника. # Но может отсутствовать право написания сообщений, поэтому заранее проверим. chat_info = await bot.get_chat(event.chat.id) if chat_info.permissions.can_send_messages: await event.answer( text=f"Привет! Спасибо, что добавили меня в " f'chats_variants[event.chat.type]> "event.chat.title>" ' f"как обычного участника. ID чата: event.chat.id>" ) else: print("Как-нибудь логируем эту ситуацию")
Но, как и всегда, есть нюанс, и чтобы его увидеть, надо добавить бота в группу, а затем сконвертировать её в супергруппу. Для наглядности, я создал группу со своим ботом @my_id_bot, а затем добавил туда тестового бота с кодом, описанным выше. Внимание на картинку:

Ой, почему-то бот отреагировал так, как будто его только что добавили, хотя вроде как ничего не изменилось. На деле, конвертация группы в супергруппу для бота выглядит как добавление в новый чат. К счастью, в этом случае боту также приходит Message с непустыми полями migrate_from_chat_id и migrate_to_chat_id . А дальше дело за малым: при срабатывании события my_chat_member на добавление в супергруппу проверять, что за последнее время (скажем, за пару секунд) не было сообщений с непустым полем migrate_to_chat_id .
Решение практически полностью повторяет описанные выше примеры и более того, реализовано в моём @my_id_bot: вот так (звёздочки на гитхабе всячески приветствуются)
Группы и супергруппы
Вопреки частому заблуждению, обычные группы по-прежнему существуют и никуда исчезать не собираются. Официальные клиенты Telegram исходно создают именно обычную группу, которая неявно при наступлении некоторого события конвертируется в супергруппу. И есть серьёзные подозрения, что такое поведение в ближайшие годы не изменится, особенно в свете того, что на обычные (не-премиум) учётки действует лимит на участие в 500 супергруппах и каналах суммарно.
При конвертации, помимо смены ID чата, присутствуют также некоторые побочные эффекты, поэтому зачастую проще всего после создания группы сразу её сделать супергруппой, получить окончательный айди и не париться. Полный список действий, приводящий к конвертации группы в супергруппу, можно увидеть здесь: https://t.me/tgbeta/3424.
Апдейт chat_member¶
Следующий особый тип апдейтов chat_member — хитрый. Дело в том, что он по умолчанию не отправляется Телеграмом, и чтобы Bot API его присылал, необходимо при вызове getUpdates или setWebhook передать список нужных типов событий. Например:
# тут импорты async def main(): # тут код dp = Dispatcher() bot = Bot("токен") await dp.start_polling( bot, allowed_updates=["message", "inline_query", "chat_member"] )
Тогда после запуска бота телега начнёт присылать три указанных типа событий, но без всех остальных.
Разработчики aiogram подошли к теме изящно: если явным образом не указывать allowed_updates , то фреймворк рекурсивно пройдёт по всем роутерам, начиная с диспетчера, просмотрит хэндлеры и самостоятельно соберёт список желаемых для получения апдейтов. Хотите переопределить это поведение? Передавайте allowed_updates явно.
Почему мне не приходит апдейт .
В профильных чатах регулярно спрашивают: «Мой код не работает, не реагирует на событие, почему?»
Первое, что стоит сделать — убедиться, что нужный апдейт вообще приходит боту. Иными словами, проверить, с каким allowed_updates был вызван поллинг/вебхуки в последний раз. Проще всего это сделать прямо в браузере:
- Взять токен бота, назовём его AAAAA
- Сформировать ссылку вида https://api.telegram.org/botAAAAA/getWebhookInfo
- Перейти по ней
Далее внимательно изучить JSON в ответе. Если ключ allowed_updates присутствует, то убедиться, что желаемый тип апдейтов есть в списке. Если ключа нет, это равнозначно «приходит всё, кроме chat_member »
Актуализация списка админов в группах¶
Частая проблема ботов-модераторов: как на вызываемые команды наложить проверку прав доступа. К примеру, как сделать так, чтобы банить участников по команде /ban могли только администраторы группы.
Первая и наивная мысль — каждый раз вызывать getChatMember, чтобы определить статус вызывающего юзера в группе. Вторая мысль — закэшировать это знание на короткое время. Третья и более правильная идея — при старте бота получить список админов, а дальше слушать апдейты chat_member об изменении их состава и редактировать список самостоятельно. Бот перезапустился? Не беда, снова получили актуальный список и работаем с ним.
Напишем роутер, в котором будем следить за изменением состава админов и обновлять переданный извне список (точнее, в терминах python это будет множество, оно же Set):
handlers/admin_changes_in_group.py
from aiogram import F, Router from aiogram.filters.chat_member_updated import \ ChatMemberUpdatedFilter, KICKED, LEFT, \ RESTRICTED, MEMBER, ADMINISTRATOR, CREATOR from aiogram.types import ChatMemberUpdated from config_reader import config router = Router() router.chat_member.filter(F.chat.id == config.main_chat_id) @router.chat_member( ChatMemberUpdatedFilter( member_status_changed= (KICKED | LEFT | RESTRICTED | MEMBER) >> (ADMINISTRATOR | CREATOR) ) ) async def admin_promoted(event: ChatMemberUpdated, admins: set[int]): admins.add(event.new_chat_member.user.id) await event.answer( f"event.new_chat_member.user.first_name> " f"был(а) повышен(а) до Администратора!" ) @router.chat_member( ChatMemberUpdatedFilter( # Обратите внимание на направление стрелок # Или можно было поменять местами объекты в скобках member_status_changed= (KICKED | LEFT | RESTRICTED | MEMBER) <(ADMINISTRATOR | CREATOR) ) ) async def admin_demoted(event: ChatMemberUpdated, admins: set[int]): admins.discard(event.new_chat_member.user.id) await event.answer( f"event.new_chat_member.user.first_name> " f"был(а) понижен(а) до обычного юзера!" )
Теперь напишем другой роутер с хэндлером на команду /ban . В самом хэндлере будем проверять наличие айди вызывающего во множестве admins и исходя из этого разрешать или запрещать бан:
handlers/events_in_group.py
from aiogram import Router, F from aiogram.filters.command import Command from aiogram.types import Message router = Router() # Вообще говоря, можно на роутер навесить кастомный фильтр # с проверкой, лежит ли айди вызывающего во множестве admins. # Тогда все хэндлеры в роутере автоматически будут вызываться # только для людей из admins, это сократит код и избавит от лишнего if # Но для примера сделаем через if-else, чтобы было нагляднее @router.message(Command("ban"), F.reply_to_message) async def cmd_ban(message: Message, admins: set[int]): if message.from_user.id not in admins: await message.answer( "У вас недостаточно прав для совершения этого действия" ) else: await message.chat.ban( user_id=message.reply_to_message.from_user.id ) await message.answer("Нарушитель заблокирован")
Осталось зарегистрировать роутеры в основном файле и подгрузить список админов при старте. Собственно, вот полное содержимое, вместе со всеми предыдущими правками.
import asyncio import logging from aiogram import Bot, Dispatcher from config_reader import config from handlers import in_pm, bot_in_group, admin_changes_in_group, events_in_group async def main(): logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", ) dp = Dispatcher() bot = Bot(config.bot_token.get_secret_value(), parse_mode="HTML") dp.include_routers( in_pm.router, events_in_group.router, bot_in_group.router, admin_changes_in_group.router ) # Подгрузка списка админов admins = await bot.get_chat_administrators(config.main_chat_id) admin_ids = admin.user.id for admin in admins> await dp.start_polling(bot, admins=admin_ids) if __name__ == '__main__': asyncio.run(main())
Теперь посмотрим, что в итоге получилось. Пробуем вызвать команду /ban не-админом:

Идём в настройки группы и назначаем Артура администратором (бот увидит изменение и сообщит об этом в чате):

Отзовём права админа у подопытного пациента и попросим его ещё раз вызвать команду /ban :

Теперь вы знаете, как работать с этими «невидимыми» апдейтами, ура! Напоследок, порекомендую ознакомиться с ещё одним демонстрационным ботом, в котором используются некоторые вышеописанные фишки.
Создание Python Telegram бота и его deploy на виртуальную машину
Рынок чат-ботов в России растет с бешеной скоростью и ожидается ежегодный прирост на 30% в течение ближайших трех лет. В 2020 г. количество запросов на чат-боты увеличилось на 17% по сравнению с 2019 г. Большим спросом стали пользоваться голосовые боты, количество запросов на них выросло в четыре раза. В 2021 г. ожидается рост числа запросов на чат-боты на 15-20% от организаций из госсектора, образования, медицины, логистики, ретейла и e-commerce, промышленных и добывающих компаний.
Шаги
- Создаём нашего telegram бота.
- Пишем код под наши задачи и тестируем его работоспособность.
- Выбираем надежный сервис виртуальных машин.
- Переносим нашего бота на виртуальную машину для его дальнейшей работы.
- Настраиваем беспрерывную работу бота.
Шаг 1. Создание бота в Telegram
Первые три шага опишу максимально кратко, так как статей на эту тему много и обычно это не вызовет у пользователей никаких трудностей. Для создания бота нам понадобится написать BotFather.

Шаг 2. Напишем простейшего чат-бота и протестируем его
Для работы будем использовать библиотеку telebot, которую можно установить при помощи следующей команды:
$ pip install pytelegrambotapi
Для установки других библиотек, в случае того, если вы не ограничиваетесь базовым функционалом вам поможет господь Google.
Напишем простого бота, который будет присылать нам в ответ на различные Emoji их размытые PNG копии:
import telebot import PIL from PIL import Image from requests import get #Сюда подставляете свой токен bot = telebot.TeleBot('1653707062:AAHxX29RP5HY-nVb21SSD8ZRbKpxKseSyS4') @bot.message_handler(commands=['start']) def start_message(message): bot.send_message(message.chat.id, 'Пришли мне Emoji, который необходимо сделать размытым.) @bot.message_handler(content_types=['text']) def send_text(message): if message.text.lower() == 'нам первый смайлик': img = open('Смайлики и люди 1.png', 'rb') bot.send_document(message.chat.id, img) elif message.text.lower() == 'наш второй смайлик': img = open('Смайлики и люди 2.png', 'rb') bot.send_document(message.chat.id, img) else: bot.send_message(message.chat.id, 'Прости, но пока у меня нет этих Emoji') bot.polling() #сами смайлики прописать не могу, иначе публикация не обрабатывается на habr
Наш бот готов, теперь осталось его протестировать. Заходим по ссылке, которую прислал BotFather.

Поздравляю, наш бот теперь работает. И тут мы подходим к главной проблеме: как только мы выключим наш компьютер с запущенным кодом, бот мгновенно перестанет работать. Для решения этой проблемы нам-то и понадобится сервис предоставляющий виртуальные машины.
Шаг 3. Выбираем виртуальную машину!
Что вообще такое эта виртуальная машина?
Виртуальная машина (ВМ ) — это виртуальный компьютер, который использует выделенные ресурсы реального компьютера (процессор, диск, адаптер). Эти ресурсы хранятся в облаке и позволяют ВМ работать автономно. Простыми словами, виртуальная машина позволяет создать на одном компьютере ещё один компьютер, который будет использовать его ресурсы, но работать изолированно.
Именно виртуальная машина поможет нашему боту отвечать на все запросы и работать 24 на 7.
Как выбрать виртуальную машину?
ВМ выбирается исключительно отталкиваясь от ваших потребностей бюджета. Чем больше вам необходимо мощности и памяти, тем выше будет ее стоимость. В настоящее время есть множество хороших сервисов, предоставляющих пробный период с которым вы сможете определиться, подходит ли вам сервис.
Лично я могу рекомендовать следующие сервисы:
- Mail cloud solutions — Предоставляют 3000 р. на два месяца тестового периода. (Именно его я и буду использовать в дальнейшей работе).
- Yandex.Cloud — Представляют 2000 р. на два месяца тестового периода.
- Google Cloud Platform — Предоставляют 300$ на три месяца тестового периода.
После выбора сервиса, пройдем регистрацию и создадим новую виртуальную машину.
Создание виртуальной машины.
Я выбрал минимальные параметры, так как нашему боты не нужны какие-то большие энергоресурсы.

Настройка сети.

Для подключения будем использовать протокол SSH. Для подключения к нашей виртуальной машине, нам необходимо будет выпустить новую связку ssh-ключей.
Для этого перейдем в терминал и пропишем следующую команду:
Затем пропишем имя нашего ключа и нажмем Enter. Наш ключ создан. Для подключения нам понадобится public-key с расширением .pub. Копируем содержимое нашего файла и вставляем его в соответствующее поле «Ключ виртуальной машины».
Переходим к следующему шагу.
Подключение к виртуальной машине
Для подключения к нашей виртуальной машине пропишем следующую команду:
ssh -i ~/.ssh/ИмяВашегоКлюча ubuntu@ваш публичный IP-адрес
Например: ssh -i ~/.ssh/my_key ubuntu@22.222.222.222
В случае удачного подключения вы увидите нечто подобное:

Мы подошли к самому сложному шагу, который я надеюсь, благодаря моей статье перестанет быть столь трудным для освоения.
- Установим на наш сервер последнюю версию Python. Для этого последовательно вводите следующие команды:
$ sudo apt update $ sudo apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget libbz2-dev $ wget https://www.python.org/ftp/python/3.8.5/Python-3.8.5.tgz $ tar -xf Python-3.8.5.tgz $ cd Python-3.8.5 $ ./configure --enable-optimizations $ make # ~15 минут $ sudo make altinstall $ cd /home
- Установим и создадим виртуально окружение:
$ python3.8 -m pip install --upgrade pip $ pip install virtualenv $ mkdir НазваниеВашегоБота $ cd НазваниеВашегоБота $ virtualenv venv $ source venv/bin/activate $ python -V $ deactivate
$ sudo apt install redis-server $ redis-cli
Проверить, запущен ли наш Redis-server, необходимо прописать «ping»

Если в ответе вы получили PONG, поздравляю, все готово к дальнейшей работе!

- Перенесем все необходимые файлы на наш виртуальный сервер. Для этого я буду использовать очень удобную программу CyberDuck
Выбираем новое подключение по SFTP, вводим IP-адрес вашей виртуальной машины, !ПРИВАТНЫЙ! ssh-ключ, логин и пароль от вашей виртуальной машины.

- Мы попадаем фактически на наш сервер, с уже установленным Python, папкой с названием нашего бота и виртуальным окружением. Остается перенести все данные нашего бота. Для этого копируем ВСЕ необходимые файлы и вставляем их на сервер.
- Поздравляю, мы на финишной прямой, остается запустить нашего бота на сервере и проверить его работоспособность.
$ cd /home/НазваниеВашегоБота/ # перейдем в папку проекта $ source venv/bin/activate # активируем окружение $ pip install -r requirements.txt # установим зависимости $ python main.py # запустим бота
Проверяем работу, если все в порядке, прописываем в терминале deactivate. Нам остается последний шаг. Настроить непрерывную работу нашего бота.
Шаг 5. Настройка беспрерывной работы нашего бота.
Пропишем следующую команду: nano /lib/systemd/system/НазваниеБота.service
[Unit] Description=Описание вашего бота After=network.target [Service] EnvironmentFile=/etc/environment ExecStart=/home/НазваниеБота/venv/bin/python main.py ExecReload=/home/НазваниеБота/venv/bin/python main.py WorkingDirectory=/home/НазваниеБота/ KillMode=process Restart=always RestartSec=5 [Install] WantedBy=multi-user.target
Нажимаем CTRL+O → Enter → CTRL+X для сохранения. Эти настройки помогут запускать или перезапускать нашего бота.
-
Последний шаг: Снова запускаем нашего бота, но уже с беспрерывной работой.
sudo systemctl enable НазваниеБота sudo systemctl start НазваниеБота
ГОТОВО! Наш бот запущен и теперь работает 24/7, независимо от того, включен наш с вами компьютер или нет. Если что-то не работает, тщательно проверьте, правильно ли вы прописали путь к файлам. Если терминал выдает ошибку авторизации, попробуйте добавить перед командой «sudo» (Команда от имени администратора)
P.S. Тема телеграм-ботов стала весьма интересной и актуальной в последнее время, поэтому буду рад услышать здравую критику по поводу моей первой на этот момент статьи. Если у вас возникнут идеи для написания новых, буду рад их выслушать.
- Python
- Клиентская оптимизация
- API
- Разработка под Linux
Пишем чат-бот на Python + PostgreSQL и Telegram
Пошаговое руководство написания чат-бота на языке Python.
- Установим Python и библиотеки;
- Получим вопросы и ответы из БД PostgreSQL;
- Подключим морфологию;
- Подключим чат-бот к каналу Telegram.
Colaboratory от Google
Изучение Python можно начать используя сервис Colaboratory от Google, или просто Colab. Сервис позволяет писать и выполнять код Python в браузере, не требуя собственного сервера.
Пример кода. Вопросы и ответы для чат-бота подгрузим с https://drive.google.com из текстового файла
# Однократно после запуска виртуальной машины устанавливаем библиотеки pymorphy2 и numpy !pip install pymorphy2 numpy # ---------------------------- # подключим библиотеки import csv import pymorphy2 import re morph = pymorphy2.MorphAnalyzer(lang='ru') # Массив вопросов questions=[] # Массив ответов answer=[] # Подключаем файл с Google диска, содержащий вопросы/ответы # Есть ли жизнь на марсе;Есть with open("/content/drive/MyDrive/robo-bot/question.txt", "r") as f_obj: reader = csv.reader(f_obj) for row in reader: s=" ".join(row) r=s.split(';') questions.append(r[0]) answer.append(r[1]) # выведем список вопросов и ответов print (questions) print (answer)
Запуск в Production
Наигравшись с кодом в Colaboratory и освоив Python развернем систему на боевом сервере Debian
Установим Python и PIP (установщик пакетов).
Так как Debian не самый новый, устанавливается версия 3.5
aptitude install python3 python3-pip # обновим пакеты если они были установлены ранее pip3 install --upgrade setuptools pip
Установим необходимые пакеты Python
# Из за устаревшей версии Debian установить psycopg2 не удалось, поставлен скомпилированный psycopg2-binary # Библиотека psycopg2 нужна для подключения к базе данных PostgreSQL # pip3 install psycopg2 pip3 install psycopg2-binary scikit-learn numpy pymorphy2
Пишем код в файле Chat_bot.py
# Импортируем библиотеки import pymorphy2 import re import psycopg2 import sklearn import numpy as np # Подключаемся к PostgreSQL conn = psycopg2.connect(dbname='energy', user='mao', password='darin', host='localhost') cursor = conn.cursor() # Настраиваем язык для библиотеки морфологии morph = pymorphy2.MorphAnalyzer(lang='ru') # объявляем массив кодов ответов и ответов answer_id=[] answer = dict() # получаем из PostgreSQL список ответов и проиндексируем их. # Работая с PostgreSQL обращаемся к схеме app, в которой находятся таблицы с данными cursor.execute('SELECT id, answer FROM app.chats_answer;') records = cursor.fetchall() for row in records: answer[row[0]]=row[1]
Структура таблицы ответов chats_answer, формат SQL
CREATE TABLE app.chats_answer ( id SERIAL, answer VARCHAR(512), CONSTRAINT chats_answer_pkey PRIMARY KEY(id) ) WITH (oids = false); ALTER TABLE app.chats_answer OWNER TO mao;
Да, я готов об этом поговорить
Я тоже хочу спать
Структура таблицы вопросов chats_question, формат SQL. Каждый вопрос связан с кодом ответа.
CREATE TABLE app.chats_question ( id SERIAL, question VARCHAR(512), answer_id INTEGER, CONSTRAINT chats_question_pkey PRIMARY KEY(id) ) WITH (oids = false); ALTER TABLE app.chats_question OWNER TO mao;
Сколько тебе лет
Лет то тебе сколько
Поговорим о возрасте
Трейлер фильма Матрица
Продолжаем код в файле Chat_bot.py
# объявляем массив вопросов questions=[] # загрузим вопросы и коды ответов cursor.execute('SELECT question, answer_id FROM app.chats_question;') records = cursor.fetchall() # посчитаем количество вопросов transform=0 for row in records: # Если текст вопроса не пустой if row[0]>"": # Если в БД есть код ответа на вопрос if row[1]>0: phrases=row[0] # разбираем вопрос на слова words=phrases.split(' ') phrase="" for word in words: # каждое слово из вопроса приводим в нормальную словоформу word = morph.parse(word)[0].normal_form # составляем фразу из нормализованных слов phrase = phrase + word + " " # Если длинна полученной фразы больше 0 добавляем ей в массив вопросов и массив кодов ответов if (len(phrase)>0): questions.append(phrase.strip()) answer_id.append(row[1]) transform=transform+1 # выведем на экран вопросы, ответы и коды ответов print (questions) print (answer) print (answer_id) # Закроем подключение к PostgreSQL cursor.close() conn.close()
Векторизация и трансформация
# Векторизируем вопросы в огромную матрицу # Перемножив фразы на слова из которых они состоят получим числовые значения from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.decomposition import TruncatedSVD vectorizer_q = TfidfVectorizer() vectorizer_q.fit(questions) matrix_big_q = vectorizer_q.transform(questions) print ("Размер матрицы: ") print (matrix_big_q.shape) # Трансформируем матрицу вопросов в меньший размер для уменьшения объема данных # Трансформировать будем в 200 мерное пространство, если вопросов больше 200 # Размерность подбирается индивидуально в зависимости от базы вопросов, которая может содержать 1 млн. или 1к вопросов и 1 # Без трансформации большая матрицу будет приводить к потерям памяти и снижению производительности if transform>200: transform=200 svd_q = TruncatedSVD(n_components=transform) svd_q.fit(matrix_big_q) # получим трансформированную матрицу matrix_small_q = svd_q.transform(matrix_big_q) print ("Коэффициент уменьшения матрицы: ") print ( svd_q.explained_variance_ratio_.sum())
Функция поиска ответа
# Тело программы поиска ответов from sklearn.neighbors import BallTree from sklearn.base import BaseEstimator def softmax(x): #создание вероятностного распределения proba = np.exp(-x) return proba / sum(proba) class NeighborSampler(BaseEstimator): def __init__(self, k=5, temperature=10.0): self.k=k self.temperature = temperature def fit(self, X, y): self.tree_ = BallTree(X) self.y_ = np.array(y) def predict(self, X, random_state=None): distances, indices = self.tree_.query(X, return_distance=True, k=self.k) result = [] for distance, index in zip(distances, indices): result.append(np.random.choice(index, p=softmax(distance * self.temperature))) return self.y_[result] from sklearn.pipeline import make_pipeline ns_q = NeighborSampler() # answer_id - код ответа в массиве, который получается при поиске ближайшего ответа ns_q.fit(matrix_small_q, answer_id) pipe_q = make_pipeline(vectorizer_q, svd_q, ns_q)
Проверка из консоли
# код для проверки работы из консоли print("Пишите ваш вопрос, слова exit или выход для выхода") request="" while request not in ['exit', 'выход']: # получим текст от ввода request=input() # разберем фразу на слова words= re.split('\W',request) phrase="" for word in words: word = morph.parse(word)[0].normal_form # морфируем слово вопроса в нормальную словоформу # Нормализуем словоформу каждого слова и соберем обратно фразу phrase = phrase + word + " " # запустим функцию и получим код ответа reply_id = int(pipe_q.predict([phrase.strip()])) # выведем текст ответа print (answer[reply_id])
Запустим и проверим
python3 Chat_bot.py
Подключим Telegram
# установим не самую последнюю версию для валидности дальнейшего кода #pip3 install PyTelegramBotAPI pip3 install PyTelegramBotAPI==3.6.7
Откроем Telegram и обратимся к боту @BOTFATHER https://t.me/botfather
Все просто, зарегистрируем нового бота и получим token.
import telebot telebot.apihelper.ENABLE_MIDDLEWARE = True # Укажем token полученный при регистрации бота bot = telebot.TeleBot("9999999999:AABBCCDDEEFFGGQWERTYUIOPASDFGHJKLLK") # Начнем обработку. Если пользователь запустил бота, ответим @bot.message_handler(commands=['start']) def start_message(message): bot.send_message(message.from_user.id, " Здравствуйте. Я виртуальный бот Mao!") # Если пользователь что-то написал, ответим @bot.message_handler(func=lambda message: True) def get_text_messages(message): request=message.text # разобьём фразу на массив слов, используя split. '\W' - любой символ кроме буквы и цифры words= re.split('\W',request) phrase="" # разберем фразу на слова, нормализуем каждое и соберем фразу for word in words: word = morph.parse(word)[0].normal_form phrase = phrase + word + " " # получим код ответа вызывая нашу функцию reply_id = int(pipe_q.predict([phrase.strip()])) # отправим ответ bot.send_message(message.from_user.id, answer[reply_id]) # продублируем ответ пользователю с bot.send_message(99999999, str(message.from_user.id) + "\n" + str(message.from_user.first_name) + " " + str(message.from_user.last_name) + " " +str(message.from_user.username) + "\n"+ str(request) + "\n"+ str(answer[reply_id])) # выведем в консоль вопрос / ответа print("Запрос:", request, " \n\tНормализованный: ", phrase, " \n\t\tОтвет :", answer[reply_id]) # Запустим обработку событий бота bot.infinity_polling(none_stop=True, interval=1)
В целом все готово. Вопросы в базу данных добавляются автоматически от службы тех. поддержки. Остаётся маркетологу в админ панели на YII назначать ответы вопросам. Раз в сутки cron перезапускает скрипт чат-бота, новые фразы поступают в работу.
Весь код чат бота
import csv import pymorphy2 import re import psycopg2 conn = psycopg2.connect(dbname='energy', user='mao', password='daring', host='localhost') cursor = conn.cursor() morph = pymorphy2.MorphAnalyzer(lang='ru') answer_id=[] answer = dict() cursor.execute('SELECT id, answer FROM app.chats_answer;') records = cursor.fetchall() for row in records: answer[row[0]]=row[1] questions=[] cursor.execute('SELECT question, answer_id FROM app.chats_question;') records = cursor.fetchall() transform=0 for row in records: if row[0]>"": if row[1]>0: phrases=row[0] words=phrases.split(' ') phrase="" for word in words: word = morph.parse(word)[0].normal_form phrase = phrase + word + " " if (len(phrase)>0): questions.append(phrase.strip()) answer_id.append(row[1]) transform=transform+1 #print (questions) #print (answer) #print (answer_id) cursor.close() conn.close() import sklearn from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.decomposition import TruncatedSVD vectorizer_q = TfidfVectorizer() vectorizer_q.fit(questions) matrix_big_q = vectorizer_q.transform(questions) print ("Размер матрицы: ") print (matrix_big_q.shape) if transform>200: transform=200 print(transform) svd_q = TruncatedSVD(n_components=transform) svd_q.fit(matrix_big_q) matrix_small_q = svd_q.transform(matrix_big_q) print ("Коэффициент уменьшения матрицы: ") print ( svd_q.explained_variance_ratio_.sum()) # тело программы k=5, temperature=10.0 можно подбирать import numpy as np from sklearn.neighbors import BallTree from sklearn.base import BaseEstimator def softmax(x): #создание вероятностного распределения proba = np.exp(-x) return proba / sum(proba) class NeighborSampler(BaseEstimator): def __init__(self, k=5, temperature=10.0): self.k=k self.temperature = temperature def fit(self, X, y): self.tree_ = BallTree(X) self.y_ = np.array(y) def predict(self, X, random_state=None): distances, indices = self.tree_.query(X, return_distance=True, k=self.k) result = [] for distance, index in zip(distances, indices): result.append(np.random.choice(index, p=softmax(distance * self.temperature))) return self.y_[result] from sklearn.pipeline import make_pipeline ns_q = NeighborSampler() ns_q.fit(matrix_small_q, answer_id) pipe_q = make_pipeline(vectorizer_q, svd_q, ns_q) import re import telebot telebot.apihelper.ENABLE_MIDDLEWARE = True bot = telebot.TeleBot("299999999:sdfgnreognrtgortgmrtgmrtgm") @bot.message_handler(commands=['start']) def start_message(message): bot.send_message(message.from_user.id, " Здравствуйте. Я виртуальный помощник Mao?") @bot.message_handler(func=lambda message: True) def get_text_messages(message): request=message.text words= re.split('\W',request) phrase="" for word in words: word = morph.parse(word)[0].normal_form phrase = phrase + word + " " reply_id = int(pipe_q.predict([phrase.strip()])) bot.send_message(message.from_user.id, answer[reply_id]) print("Запрос:", request, " \n\tНормализованный: ", phrase, " \n\t\tОтвет :", answer[reply_id]) bot.infinity_polling(none_stop=True, interval=1) print("Пишите ваш вопрос, слова exit или выход для выхода") request="" while request not in ['exit', 'выход']: request=input() words= re.split('\W',request) phrase="" for word in words: word = morph.parse(word)[0].normal_form phrase = phrase + word + " " reply_id = int(pipe_q.predict([phrase.strip()])) print (answer[reply_id])
В теле программы есть переменные k=5 и temperature=10.0. Их можно менять, что будет влиять на поиск, делая его более мягким или более жестким.
P.S. Умышленно привожу весь код для практики. Теорию машинного обучения с картинками можно почитать, например, в другой статье.
- Python
- PostgreSQL
- Data Mining
- Машинное обучение
- Natural Language Processing
Обучаемый Telegram чат-бот с ИИ в 30 строчек кода на Python

Сейчас сделать это совсем легко, поэтому, недолго думая, я принялся к написанию кода.
Языком я выбрал Python, т.к. на нём легче всего работать с подобного рода приложениями.
Итак, для создания Telegram чат-бота с ИИ нам потребуется:
1. API Telegram. В качестве обёртки я взял проверенную библиотеку python-telegram-bot
2. API ИИ. Выбрал я продукт от Google, а именно Dialogflow. Он предоставляет довольно-таки неплохое бесплатное API. Обёртка Dialogflow для Python
Шаг 1. Создаём бота в Telegram
Придумываем имя нашему боту и пишем @botfather. После создания бота нам придёт API токен, который желательно бы где-то сохранить, т.к. в дальнейшем он нам понадобится.

Шаг 2. Пишем основу бота
Создаём папку Bot, в которой потом создаём файл bot.py. Здесь будет код нашего бота.
Открываем консоль и переходим в директорию с файлом, устанавливаем python-telegram-bot.
pip install python-telegram-bot --upgrade
После установки мы уже можем написать «основу», которая пока что будет просто отвечать однотипными сообщениями. Импортируем необходимые модули и прописываем наш токен API:
Код настроек и импорта
# Настройки from telegram.ext import Updater, CommandHandler, MessageHandler, Filters updater = Updater(token='ВАШ API КЛЮЧ') # Токен API к Telegram dispatcher = updater.dispatcher
Далее напишем 2 обработчика команд. Это callback-функции, которые будут вызываться тогда, когда будет получено обновление. Напишем две таких функции для команды /start и для обычного любого текстового сообщения. В качестве аргументов туда передаются два параметра: bot и update. Bot содержит необходимые методы для взаимодействия с API, а update содержит данные о пришедшем сообщении.
Код callback’ов
# Обработка команд def startCommand(bot, update): bot.send_message(chat_id=update.message.chat_id, text='Привет, давай пообщаемся?') def textMessage(bot, update): response = 'Получил Ваше сообщение: ' + update.message.text bot.send_message(chat_id=update.message.chat_id, text=response)
Теперь осталось лишь присвоить уведомлениям эти обработчики и начать поиск обновлений.
Делается это очень просто:
Код хендлеров
# Хендлеры start_command_handler = CommandHandler('start', startCommand) text_message_handler = MessageHandler(Filters.text, textMessage) # Добавляем хендлеры в диспетчер dispatcher.add_handler(start_command_handler) dispatcher.add_handler(text_message_handler) # Начинаем поиск обновлений updater.start_polling(clean=True) # Останавливаем бота, если были нажаты Ctrl + C updater.idle()
Итого, полная основа скрипта выглядит вот так:
Код полной основы бота
# Настройки from telegram.ext import Updater, CommandHandler, MessageHandler, Filters updater = Updater(token='ВАШ API ТОКЕН') # Токен API к Telegram dispatcher = updater.dispatcher # Обработка команд def startCommand(bot, update): bot.send_message(chat_id=update.message.chat_id, text='Привет, давай пообщаемся?') def textMessage(bot, update): response = 'Получил Ваше сообщение: ' + update.message.text bot.send_message(chat_id=update.message.chat_id, text=response) # Хендлеры start_command_handler = CommandHandler('start', startCommand) text_message_handler = MessageHandler(Filters.text, textMessage) # Добавляем хендлеры в диспетчер dispatcher.add_handler(start_command_handler) dispatcher.add_handler(text_message_handler) # Начинаем поиск обновлений updater.start_polling(clean=True) # Останавливаем бота, если были нажаты Ctrl + C updater.idle()
Теперь мы можем проверить работоспособность нашего нового бота. Вставляем на 2 строке наш API токен, сохраняем изменения, переносимся в консоль и запускаем бота:
python bot.py
После запуска пишем ему. Если всё настроено правильно, то Вы увидите вот это:

Основа бота написана, приступаем к следующему шагу!
P.s. не забывайте выключить бота, для этого вернитесь в консоль и нажмите Ctrl + C, подождите пару секунд и бот успешно завершит работу.
Шаг 3. Настройка ИИ
В первую очередь, идём и регистрируемся на Dialogflow (просто входим с помощью своего Google аккаунта). Сразу после авторизации мы попадаем в панель управления.

Жмём на кнопку Create agent и заполняем поля по усмотрению (это никакой роли не сыграет, это нужно лишь для следующего действия).

Жмём на Create и видим следующую картину:

Расскажу, почему созданный нами ранее «Агент» никакой роли не играет. Во вкладке Intents есть «команды», по которым работает бот. Сейчас он умеет лишь отвечать на фразы типа «Привет», и если не понимает, то отвечает «Я вас не понял». Не сильно впечатляет.
После создания нашего пустого агента, у нас появилась куча других вкладок. Нам нужно нажать на Prebuilt Agents (это уже специально обученные агенты, которые имеют множество команд) и из всего представленного списка выбрать Small Talk.

Наводим на него и жмём Import. Далее ничего не меняя, жмём Ok. Агент импортировался и теперь мы можем его настроить. Для этого в левом верхнем углу жмём на шестерёнку возле Small-Talk и попадаем на страницу настроек. Теперь мы можем изменить имя агента, как захотим (я оставляю как было). Меняем часовой пояс и во вкладке Languages проверяем, чтобы был установлен русский язык (если не установлен, то ставим).

Возвращаемся на вкладку General, спускаемся немного вниз и копируем Client access token

Теперь наш ИИ полностью настроен, можно возвращаться к боту.
Шаг 4. Собираем всё вместе
ИИ готов, основа бота готова, что дальше? Дальше нам нужно скачать обёртку API от Dialogflow для питона.
pip install apiai
Установили? Возвращаемся к нашему боту. Добавляем в нашу секцию «Настройки» импорт модулей apiai и json (нужно, чтобы в будущем разбирать json ответы от dialogflow). Теперь это выглядит вот так:
Код обновлённых настроек
# Настройки from telegram.ext import Updater, CommandHandler, MessageHandler, Filters import apiai, json updater = Updater(token='ВАШ API КЛЮЧ') # Токен API к Telegram dispatcher = updater.dispatcher
Переходим к функции textMessage (которая отвечает за получение любого текстового сообщения) и посылаем полученные сообщения на сервера Dialogflow:
Код отправления сообщений на Dialogflow
def textMessage(bot, update): request = apiai.ApiAI('ВАШ API ТОКЕН').text_request() # Токен API к Dialogflow request.lang = 'ru' # На каком языке будет послан запрос request.session_id = 'BatlabAIBot' # ID Сессии диалога (нужно, чтобы потом учить бота) request.query = update.message.text # Посылаем запрос к ИИ с сообщением от юзера
Этот код будет посылать запрос к Dialogflow, но нам нужно также извлечь ответ. Дописываем парочку строк, итого textMessage выглядит вот так:
Полный код функции textMessage
def textMessage(bot, update): request = apiai.ApiAI('ВАШ API ТОКЕН').text_request() # Токен API к Dialogflow request.lang = 'ru' # На каком языке будет послан запрос request.session_id = 'BatlabAIBot' # ID Сессии диалога (нужно, чтобы потом учить бота) request.query = update.message.text # Посылаем запрос к ИИ с сообщением от юзера responseJson = json.loads(request.getresponse().read().decode('utf-8')) response = responseJson['result']['fulfillment']['speech'] # Разбираем JSON и вытаскиваем ответ # Если есть ответ от бота - присылаем юзеру, если нет - бот его не понял if response: bot.send_message(chat_id=update.message.chat_id, text=response) else: bot.send_message(chat_id=update.message.chat_id, text='Я Вас не совсем понял!')
Немного пояснений. С помощью
request.getresponse().read()
получается ответ от сервера, закодированный в байтах. Чтобы декодировать его, просто применяем метод
decode('utf-8')
и после этого «заворачиваем» всё в
json.loads()
чтобы распарсить json ответ.
Если ответа нет (точнее, json приходит всегда, но не всегда есть сам массив с ответом ИИ), то это означает, что Small-Talk не понял пользователя (обучением можно будет заняться позже). Поэтому если «ответа» нет, то пишем пользователю «Я Вас не совсем понял!».
Итого, полный код бота с ИИ будет выглядеть вот так:
Полный код бота с ИИ
# Настройки from telegram.ext import Updater, CommandHandler, MessageHandler, Filters import apiai, json updater = Updater(token='ВАШ API ТОКЕН') # Токен API к Telegram dispatcher = updater.dispatcher # Обработка команд def startCommand(bot, update): bot.send_message(chat_id=update.message.chat_id, text='Привет, давай пообщаемся?') def textMessage(bot, update): request = apiai.ApiAI('ВАШ API ТОКЕН').text_request() # Токен API к Dialogflow request.lang = 'ru' # На каком языке будет послан запрос request.session_id = 'BatlabAIBot' # ID Сессии диалога (нужно, чтобы потом учить бота) request.query = update.message.text # Посылаем запрос к ИИ с сообщением от юзера responseJson = json.loads(request.getresponse().read().decode('utf-8')) response = responseJson['result']['fulfillment']['speech'] # Разбираем JSON и вытаскиваем ответ # Если есть ответ от бота - присылаем юзеру, если нет - бот его не понял if response: bot.send_message(chat_id=update.message.chat_id, text=response) else: bot.send_message(chat_id=update.message.chat_id, text='Я Вас не совсем понял!') # Хендлеры start_command_handler = CommandHandler('start', startCommand) text_message_handler = MessageHandler(Filters.text, textMessage) # Добавляем хендлеры в диспетчер dispatcher.add_handler(start_command_handler) dispatcher.add_handler(text_message_handler) # Начинаем поиск обновлений updater.start_polling(clean=True) # Останавливаем бота, если были нажаты Ctrl + C updater.idle()
Сохраняем изменения, запускаем бота и идём проверять:

Вот и всё! Бот в 30 строк с ИИ написан!
Шаг 5. Заключительная часть
Думаю, Вы убедились, что написать бота с ИИ – дело 10 минут. Осталось лишь теперь его учить и учить. Делать это, кстати, можно во вкладке Training. Там можно посмотреть все сообщения, которые писались и что на них ответил бот (или не ответил). Там же его можно и обучать, говоря боту где он ответил правильно, а где нет.

Надеюсь, статья была Вам полезна, удачи в обучении!
- python
- telegram bot
- ии и машинное обучение
- telegram chabot ai
- ai
- как написать чат-бота telegram
- ии чат-бот
- ии бот
- telegram чат-бот на python
- Python
- Машинное обучение
