Vadim Stepanov
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
      • No invitee
    • Publish Note

      Publish Note

      Everyone on the web can find and read all notes of this public team.
      Once published, notes can be searched and viewed by anyone online.
      See published notes
      Please check the box to agree to the Community Guidelines.
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
No invitee
Publish Note

Publish Note

Everyone on the web can find and read all notes of this public team.
Once published, notes can be searched and viewed by anyone online.
See published notes
Please check the box to agree to the Community Guidelines.
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
--- title: Введение в разработку диалоговых ботов. День 1 --- # Что такое чат-бот и зачем он нужен Диалоговый бот (**чат-бот**) - программа, взаимодействующая с пользователем в режиме онлайн-переписки. Находит применение в самых разных сферах бизнеса и общественной жизни: - Банкинг и финансы - Заказ товаров и услуг - Персональные ассистенты - Подписки на СМИ - Текстовые игры - и многое другое! ## Преимущества Главные преимущества диалоговых ботов перед другими способами взаимодействия с пользователем, такими как сайты и приложения: - Отсутствие необходимости установки дополнительного ПО для каждого продукта (пользователю достаточно мессенджера или программы-ассистента для работы с вашим сервисом) - Возможность наладить более органичное и интуитивно понятное взаимодействие (переписываться и разговаривать с ботом, используя стандартные методы взаимодействия) - Скорость загрузки и взаимодействия (пользователю нужно совершать меньше кликов и тратить меньше времени) - Простота разработки (нет необходимости в разработке UI\UX, единый API для общения с мессенджером или ассистентом) ## Системы с поддержкой чат-ботов * Telegram * Яндекс.Диалоги * Facebook Messenger * ВКонтакте * Viber * Skype * Slack * и другие... # Telegram боты Мессенджер Telegram имеет свою платформу для диалоговых ботов. Бот представляет из себя обычный Telegram профиль, но со следующими отличиями и ограничениями: * Бот не может сам начать общение с пользователем. Для начала работы с ботом, пользователь должен добавить его в группу или отправить команду `/start` в ЛС * Юзернейм бота имеет окончание **bot** (например, @TriviaBot, @GitHub_bot) * Боты не могут общаться между собой * Бота, как и обычного пользователя, можно добавить в группу. Бот будет видеть все сообщения в группе, кроме сообщений других ботов ## Регистрация бота Для взаимодействия с ботом, сначала нужно его зарегестрировать. Для этого в Telegram есть специальный бот - [@BotFather](https://tlgg.ru/BotFather). С помощью BotFather можно регистрировать ботов, смотреть информацию о своих ботах, изменять настройки (inline mode, webhook url, privacy settings, и т.д.) ![](https://i.imgur.com/SHjQG5R.png) Для того, чтобы зарегистрировать бота: 1) Введите команду `/newbot` 2) Введите название бота (например: My First Bot) 3) Введите **@алиас** бота, заканчивающийся на bot или Bot (без @, например: MyFirstBot) 4) Бот создан! BotFather отправит сообщение, где указан токен бота. ![](https://i.imgur.com/x0sslqK.png) :::warning Никогда не передавайте токен третьим лицам! Зная токен бота, злоумышленник может нарушить работу бота! ::: ## Задание №1: Регистрация и настройка бота с помощью BotFather Откройте диалог с [@BotFather](https://tlgg.ru/BotFather) и создайте нового бота. 1) Добавьте несколько слов в поле "Description" 2) Добавьте несколько слов в поле "About" 3) Добавьте аватар бота (если не хочется искать фото, возьмите его [здесь](https://images.freeimages.com/images/large-previews/2fb/50-s-robot-1-1181573.jpg)) 4) Зайдите в диалог с вашим ботом и посмотрите, как он выглядит # Telegram Bot API Telegram Bot API - это основанный на HTTP интерфейс взаимодействия ботов и серверов Telegram. Документация - https://core.telegram.org/bots/api. Любой запрос к серверам Telegram представляет из себя GET или POST HTTP запрос по адресу следующей формы: [https://api.telegram.org/bot<token>/METHOD_NAME](https://api.telegram.org/bot<token>/METHOD_NAME). Например, получить информацию о боте можно по ссылке: [https://api.telegram.org/bot<token>/getMe](https://api.telegram.org/bot<token>/getMe). ## Задание №2: Взаимодействие с Telegram Bot API из браузера 1) Используя браузер, перейдите по ссылке: [https://api.telegram.org/bot<token>/getMe](https://api.telegram.org/bot<token>/getMe), вставив токен своего бота вместо `<token>` 2) Изучите JSON ответ сервера Telegram 3) Напишите любое сообщение боту 4) Используя браузер, перейдите по ссылке: [https://api.telegram.org/bot<token>/getUpdates](https://api.telegram.org/bot<token>/getUpdates), вставив токен своего бота вместо `<token>`. В JSON ответе сервера найдите сообщение, которое вы написали ранее, и изучите какие свойства оно имеет 5) Используя браузер, перейдите по ссылке: [https://api.telegram.org/bot<token>/sendMessage?chat_id=**<chat_id>**&text=**<text>**](https://api.telegram.org/bot<token>/sendMessage?chat_id=<chat_id>&text=<text>), вставив токен своего бота вместо `<token>`, идентификатор своего чата (поле `message['chat']['id']` в JSON) вместо `<chat_id>` и текст ответного сообщения вместо `<text>` Пришло ли вам сообщение от бота в Telegram? ## Polling и Webhook Есть два метода взаимодействия бота c серверами Telegram: **polling** и **webhook**. **Polling** - метод, при котором ваш **бот периодически опрашивает** сервера Telegram о наличии новых изменений. При наличии новых сообщений, коллбэков или inline запросов, бот формирует ответы и отправляет их на сервера Telegram. ![](https://i.imgur.com/DDS9wPO.png) Очевидный минус такого способа - огромное количество запросов к серверу, даже если новых изменений нет. --- **Webhook** - метод, при котором **сервера Telegram сами отправляют** изменения вашему боту. Таким образом решается главная проблема polling'а - огромное количество бессмысленных запросов. ![](https://i.imgur.com/otJfole.png) Минусы данного подхода: - нужно сгенерировать и настроить ssl сертификаты - нужно поднять веб-сервер, умеющий принимать запросы из внешнего мира # Подготовка среды для разработки и запуска Telegram бота Инструменты, которые понадобятся нам для написания Telegram бота: 1. Python 3 + pip 2. Текстовый редактор или IDE с поддержкой Python (Sublime Text, PyCharm, Vim, и т.д.) 3. Модуль **pyTelegramBotAPI** ## Установка pyTelegramBotAPI 1) Перейдите в командную строку 2) Запустите команду `python3 -m pip install pyTelegramBotAPI` 3) Дождитесь завершения установки Библиотека теперь доступна для импорта через “import telebot”. Документация и исходный код библиотеки расположены здесь: https://github.com/eternnoir/pyTelegramBotAPI # Эхо бот с использованием pyTelegramBotAPI **pyTelegramBotAPI** - это обертка Telegram Bot API для Python. С помощью этого модуля вы можете взаимодействовать с ботом, не думая о том, куда и с какими параметрами отправлять запросы. Например, для отправки сообщения вы можете использовать простую команду `bot.sendMessage(chat_id=142561490, text='Hi there!')` :::success А теперь вспомним, как мы отправляли сообщение пользователю в [задании №2](#Задание-№2-Взаимодействие-с-Telegram-Bot-API-из-браузера). Использовать pyTelegramBotAPI намного удобнее! ::: Давайте взглянем на простейшего бота, который будет отвечать пользователю его же сообщением. Код простого эхо бота: ```python= import telebot API_TOKEN = '<api_token>' bot = telebot.TeleBot(API_TOKEN) @bot.message_handler(commands=['help', 'start']) def send_welcome(message): bot.send_message(chat_id=message.chat.id, text='Привет! Отправь мне любой текст!') @bot.message_handler(func=lambda message: True) def echo_message(message): bot.reply_to(message, message.text) bot.polling() ``` Разберем программу по частям: ```python= import telebot ``` Здесь мы импортируем библиотеку pyTelegramBotAPI, которая содержит в себе необходимый нам функционал для разработки Telegram ботов. ```python=3 API_TOKEN = '<api_token>' bot = telebot.TeleBot(API_TOKEN) ``` В переменную `API_TOKEN` нужно записать токен вашего бота (<> убрать). Таким образом мы указываем, с каким ботом мы взаимодействуем. Теперь нам доступен объект `bot`, с помощью которого мы можем отправлять, удалять и изменять сообщения. ```python=8 @bot.message_handler(commands=['start', 'help']) def send_welcome(message): bot.send_message(chat_id=message.chat.id, text='Привет! Отправь мне любой текст!') ``` C помощью декоратора `@bot.message_handler` мы указываем, что метод `send_welcome` будет вызываться только тогда, когда пользователь отправляет команду `/start` или `/help`. При этом, бот отправляет приветственное сообщение. ```python=13 @bot.message_handler(func=lambda message: True) def echo_message(message): bot.reply_to(message, message.text) ``` Также с помощью декоратора мы указываем, что любое другое сообщение будет просто отправлено обратно. ```python=18 bot.polling() ``` Запуск **polling**'a. Теперь бот будет переодически опрашивать сервера Telegram о наличии новых сообщений, и при наличии таковых, обрабатывать их. ## Задание №3: Счётчик слов в сообщении Модифицируйте простой эхо бот таким образом, чтобы при отправке команды `/start` он приветствовал пользователя по имени. При отправке любого другого сообщения, бот должен отправить число - количество слов в сообщении пользователя. Запустите и протестируйте бота. # Клавиатуры Иногда ответ пользователя можно представить в виде выбора между несколькими вариантами, которые известны боту заранее. Тогда, для удобства пользователя, мы можем создавать собственные клавиатуры, дающие пользователю этот выбор. Есть два типа клавиатур: * Пользовательские (кастомные) – клавиатуры, заменяющие пользователю основную клавиатуру * Встроенные (in-line) – клавиатуры, встроенные в сообщение. Могут обновлять сообщение и себя после нажатия ## Пользовательские клавиатуры Клавиатуры, заменяющие пользователю основную клавиатуру ![](https://i.imgur.com/xYlmDKT.jpg) :::info Как обрабатывать сообщение пользователя, посланное с помощью такой клавиатуры? Как обычное сообщение, ведь клавиатура просто посылает сообщение с текстом кнопки боту! ::: Импортируем фрагмент библиотеки: ```python= from telebot import types ``` Создаем клавиатуру и отправляем её: ```python=2 markup = types.ReplyKeyboardMarkup(row_width=3) btn3 = types.KeyboardButton('3') btn4 = types.KeyboardButton('4') btn5 = types.KeyboardButton('5') markup.add(btn3, btn4, btn5) bot.send_message(chat_id=chat_id, text='2 + 2 = ?', reply_markup=markup) ``` ## In-line клавиатуры Пользовательские клавиатуры, которые мы рассмотрели, чаще используются в случае, когда необходимо оставлять ее неизменной на протяжении многих сообщений. Встроенные (**in-line**) клавиатуры гораздо более удобны в случае необходимости адаптации выбора ответа под сообщение. ![](https://i.imgur.com/jgkAylN.png) Создаем клавиатуру и отправляем ее вместе с сообщением: ```python= markup = types.InlineKeyboardMarkup(row_width=3) btn1 = types.InlineKeyboardButton(text='Да!', callback_data='0') markup.add(btn1) bot.send_message(chat_id=chat_id, text='Ты человек?', reply_markup=markup) ``` При нажатии на in-line кнопку, сервера Telegram сообщат о новом событии - callback query. Посмотрим, как обрабатывать его: ```python= @bot.callback_query_handler(func=lambda call: call.data == '0') def reply(call): bot.edit_message_text(text="Ты человек!", chat_id=call.message.chat.id, message_id=call.message.message_id) ``` # Многопользовательские боты Большинство ботов не ограничиваются одним пользователем. При этом каждый пользователь в сложных ботах может находиться в разном состоянии – у каждого пользователя может быть разное сообщение на экране и разная клавиатура для ответа. Как подружить бота с несколькими пользователями сразу? ## Конечный автомат [Конечный автомат](https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82) (Finite State Machine) - абстрактная машина, имеющая конечное количество **состояний**. В каждый момент времени конечный автомат может находиться только в одном состоянии. Существует множество **переходов**, изменяющих состояние конечного автомата в ответ на **внешние данные**. Также конечный автомат имеет **начальное состояние**. :::info Состояние -> Внешние данные -> Переход (Действие) -> Новое состояние ::: ## Простейший конечный автомат на примере пропускной системы (турникетов): ![](https://i.imgur.com/2R5UkMQ.png) Белыми кругами обозначены состояния, а стрелками обозначены переходы между состояниями. Черным кругом обозначено начальное состояние. ## Чат-бот как конечный автомат Рассмотрим пример бота, реализующего простую викторину: ![](https://i.imgur.com/qJTUlRz.png) Как мы видим, диалоговых ботов также можно рассматривать как конечные автоматы: * Действия бота определяются текущим состоянием пользователя, с которым бот ведет диалог * Переходы между состояниями происходят в следствии действий пользователя ## Telegram chat id **chat_id** – уникальный идентификатор диалога с пользователем. Хранить информацию о пользователе можно привязывая ее к **chat_id**. Для того чтобы бот корректно работал с несколькими пользователями сразу, можно хранить состояния каждого пользователя следующим образом: ```python states = {chat_id: state} ``` ## Пример использования **chat_id**: ```python= import telebot API_TOKEN = '<api_token>' bot = telebot.TeleBot(API_TOKEN) states = {} @bot.message_handler(commands=['start']) def send_welcome(message): chat_id = message.chat.id bot.send_message(chat_id=chat_id, text='Привет! Как тебя зовут?') if states.get(chat_id) is None: states.update({chat_id: 0}) else: states[chat_id] = 0 @bot.message_handler(func=lambda message: states.get(message.chat.id) == 0) def ask_age(message): chat_id = message.chat.id bot.send_message(chat_id=chat_id, text='А сколько тебе лет, %s?' % message.text) states[chat_id] = 1 @bot.message_handler(func=lambda message: states.get(message.chat.id) == 1) def finalize(message): chat_id = message.chat.id bot.send_message(chat_id=chat_id, text='Круто! Мне тоже %s лет!' % message.text) states[chat_id] = 2 @bot.message_handler(func=lambda message: states.get(message.chat.id) == 2) def propose_restart(message): chat_id = message.chat.id bot.send_message(chat_id=chat_id, text='Я тебя запомнил! Нажми /start чтобы познакомиться заново!') bot.polling() ``` Очевидная проблема такого хранения состояний - при выключении бота, все данные сотрутся. Поэтому, часто для хранения состояния пользователей и другой информации о пользователях используют базы данных (MongoDB, PostgreSQL, Sqlite и т.д.). Рассмотрим добавление состояния пользователей в БД. Для этого воспользуемся sqlite и [peewee](https://github.com/coleifer/peewee). ```python= # db.py import peewee db = peewee.SqliteDatabase('users.db') class User(peewee.Model): chat_id = peewee.IntegerField(unique=True) state = peewee.IntegerField(default=0) class Meta: database = db def init(): db.connect() db.create_tables([User], safe = True) db.close() def get_state(chat_id): user = User.get_or_none(chat_id=chat_id) if user is None: return None return user.state def set_state(chat_id, state): user, created = User.get_or_create(chat_id=chat_id) user.state = state user.save() init() ``` ```python= # bot.py import telebot from db import get_state, set_state API_TOKEN = '<api_token>' bot = telebot.TeleBot(API_TOKEN) @bot.message_handler(commands=['start']) def send_welcome(message): chat_id = message.chat.id bot.send_message(chat_id=chat_id, text='Привет! Как тебя зовут?') set_state(chat_id=chat_id, state=0) @bot.message_handler(func=lambda message: get_state(message.chat.id) == 0) def ask_age(message): chat_id = message.chat.id bot.send_message(chat_id=chat_id, text='А сколько тебе лет, %s?' % message.text) set_state(chat_id=chat_id, state=1) @bot.message_handler(func=lambda message: get_state(message.chat.id) == 1) def finalize(message): chat_id = message.chat.id bot.send_message(chat_id=chat_id, text='Круто! Мне тоже %s лет!' % message.text) set_state(chat_id=chat_id, state=2) @bot.message_handler(func=lambda message: get_state(message.chat.id) == 2) def propose_restart(message): chat_id = message.chat.id bot.send_message(chat_id=chat_id, text='Я тебя запомнил! Нажми /start чтобы познакомиться заново!') bot.polling() ``` ## Задание №4: Многопользовательский бот-викторина Реализуйте многопользовательского бота-викторину с 3-4 простыми вопросами. * По команде `/start` бот должен поприветствовать пользователя и сразу же задать первый вопрос. * При неправильном ответе пользователя, бот должен ответить, что пользователь ошибся и перезадать ему тот же вопрос * При правильном ответе от пользователя, бот должен сказать, что пользователь ответил на вопрос правильно и задать следующий вопрос * Когда пользователь ответил на все вопросы, бот должен поздравить пользователя и предложить ему пройти викторину заново, нажав на `/restart` --- Поделитесь с коллегами **@алиасами** ботов и проведите тестирование в режиме работы с несколькими пользователями одновременно. Добились ли мы желаемого результата? # Telegram бот в Docker контейнере Для того, чтобы упростить запуск и разработку Telegram бота, можно использовать Docker. Запуск бота в изолированном Docker контейнере гарантирует стабильное и предсказуемое поведения бота вне зависимости от окружения компьютера, на котором запущен бот. Пример Dockerfile для эхо-бота: ```dockerfile= FROM python:3.7-alpine COPY . echo-bot WORKDIR echo-bot RUN python3 -m pip install -r requirements.txt CMD python3 bot.py ``` Для создания docker образа, воспользуемся командой: ```bash docker build -t echo-bot . ``` Запуск docker контейнера: ```bash docker run -it -e TG_API_TOKEN=<api_token> echo-bot ``` Заметьте, что токен бота передается как переменная окружения, не забудьте добавить соответсвующий функционал в код бота: ```python= import os API_TOKEN = os.getenv('TG_API_TOKEN') ``` ## Задание №5: Бот-викторина в Docker контейнере Модифицируйте многопользовательского бота-викторину из [задания №4](#Задание-№4-Многопользовательский-бот-викторина) таким образом, чтобы бот запускался в Docker контейнере. Токен бота не должен фигурировать в коде вашего бота, а передаваться как переменная окружения. Запустите и удостоверьтесь, что бот работает корректно. # Webhook + Heroku Вспомним, чем отличается [polling](#Polling) и [webhook](#Webhook). ![](https://i.imgur.com/ABNSmaq.png) ## Поддерджка webhook Все наши боты до этого момента использовали polling, но в реальном мире чаще используют webhook. Посмотрим, как реализовать поддержку webhook в нашем простом эхо-боте: ```python= import flask import telebot import os TOKEN = os.getenv('TG_API_TOKEN') WEBHOOK_HOST = os.getenv('WEBHOOK_HOST') WEBHOOK_PORT = os.getenv('WEBHOOK_PORT') WEBHOOK_SSL_CERT = './cert/cert.pem' WEBHOOK_SSL_PRIV = './cert/key.pem' WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT) WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN) bot = telebot.TeleBot(API_TOKEN) server = flask.Flask(__name__) @server.route(WEBHOOK_URL_PATH, methods=['POST']) def webhook(): if flask.request.headers.get('content-type') == 'application/json': json_string = flask.request.get_data().decode('utf-8') update = telebot.types.Update.de_json(json_string) bot.process_new_updates([update]) return '' else: flask.abort(403) @bot.message_handler(func=lambda message: True) def echo_message(message): bot.reply_to(message, message.text) if __name__ == '__main__': bot.remove_webhook() bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, certificate=open(WEBHOOK_SSL_CERT, 'r')) server.run(host='0.0.0.0', port=WEBHOOK_PORT, ssl_context=(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV)) ``` Для генерации сертификата и приватного ключа: ```bash openssl req -nodes -x509 -newkey rsa:4096 -keyout cert/key.pem -out cert/cert.pem -days 365 -subj '/CN=<host>' ``` ## Heroku Прблема наших предыдущих ботов в том, что они работали локально с компьютера, и при его выключении, бот переставал работать. Для решения этой проблемы используют удаленные сервера или схожие сервисы. Мы будем использовать сервис [Heroku](https://heroku.com), предоставляющий из себя облачную платформу, на которой можно бесплатно захостить бота. :::success Heroku использует https по умолчанию, поэтому можно не настраивать сертификаты! ::: ```python= import os from flask import Flask, request import telebot TOKEN = os.getenv('TG_API_TOKEN') bot = telebot.TeleBot(TOKEN) server = Flask(__name__) @bot.message_handler(commands=['start']) def start(message): bot.reply_to(message, 'Привет, %s!' % message.from_user.first_name) @bot.message_handler(func=lambda message: True, content_types=['text']) def echo_message(message): bot.reply_to(message, message.text) @server.route('/' + TOKEN, methods=['POST']) def get_message(): bot.process_new_updates([telebot.types.Update.de_json(request.stream.read().decode('utf-8'))]) return '', 200 if __name__ == '__main__': bot.remove_webhook() bot.set_webhook(url=os.getenv('WEBHOOK_URL') + TOKEN) server.run(host="0.0.0.0", port=int(os.getenv('PORT', 8443))) ``` Попробуем задеплоить нашего бота на Heroku. Для этого нам нужно: 1) Зарегистрировать аккаунт на heroku.com 2) Создать репозиторий на github.com со следующим содержимым: * Python скрипт с кодом бота * Файл с названием **Procfile**. Он нужен Heroku для того, чтобы понять какой именно скрипт нужно запустить. Содержимое Procfile: `web: python3 bot.py` * **requirements.txt** (Flask, pyTelegramBotAPI) 3) Создать новое приложение на Heroku 4) Во вкладке Deployment выбрать репозиторий на GitHub 5) Во вкладке Settings, в Config Vars указать токен бота и ссылку на приложение 6) Задеплоить бота в секции Manual Deploy во вкладке Deployment ## Задание №6: Бот с webhook на Heroku Разработайте Telegram бота, показывающего информацию о пользователе, отправившем сообщение. Для справки: [@userinfobot](https://tlgg.ru/userinfobot), который делает то же самое. # Inline боты Inline боты - это боты, которых не нужно добавлять в чат или писать им в ЛС. Чтобы вызвать его, можно в **любом** диалоге ввести его алиас в окне для сообщения, и он предложит вам варианты действий. Например, бот [**@youtube**](https://tlgg.ru/youtube) можно использовать в inline моде. При вводе **@алиаса** бота и поисковом запросе, бот предложит самые релевантные видео. ![](https://i.imgur.com/MrrbLSF.png) А при нажатии на одно из предложений, пользователь отправит сообщение от своего имени с пометкой "через **@youtube**". К такому сообщению также могут быть прикреплены кнопки. ![](https://i.imgur.com/sPwBFn2.png) Давайте разберемся, как реализовать похожий функционал. Для начала, в [@BotFather](https://tlgg.ru/BotFather) нужно активировать Inline mode для своего бота. Данная настройка находится в секции Bot Settings. ## Inline query Когда пользователь вводит текст после алиаса вашего бота, сервера Telegram оповещают вас о новом запросе - **inline query**. Чтобы обработать его с помощью Telebot, есть специальный декоратор `inline_handler`: ```python= @bot.inline_handler(func=lambda query: True) def answer_query(inline_query): text = inline_query.query # переменная text содержит в себе введенный текст ``` Далее, мы можем предложить пользователю возможные действия, они представляют из себя статьи - объекты класса `InlineQueryResultArticle` (доступны из telebot.types) Рассмотрим простой пример использования `InlineQueryResultArticle`: ```python= @bot.inline_handler(func=lambda query: 'alias' in query.query) def answer_alias_query(inline_query): alias_article = telebot.types.InlineQueryResultArticle( id='0', title='Отправить мой алиас', description='Нажав сюда, вы отправите в чат свой алиас!', input_message_content=telebot.types.InputTextMessageContent( message_text='Мой алиас: @%s' % inline_query.from_user.username ) ) bot.answer_inline_query( inline_query_id=inline_query.id, results=[alias_article], cache_time=0 ) ``` Параметр `results` в методе `answer_inline_query` хранит в себе список статей, которыми бот ответит пользователю. Что будет, если пользователь напишет **"send my username"**: ![](https://i.imgur.com/4oguiD8.png) ## Cache time Параметр `cache_time` в `answer_inline_query` отвечает за время, на которое сервера Telegram закэшируют ответ на запрос. Т.е. если пользователь ввёл "Send my alias", и бот ответил ему статьями, при следующем таком же запросе, сервера Telegram не отправят вашему боту новый inline query, а воспользуются ответом из кэша. Кэширование позволяет работать вашему боту быстрее и меньше нагружать сервер, но при разработке бота удобно использовать `cache_time=0`. Дэфолтное значение cache_time = 300 секунд. ## Switch to PM Иногда нужно сказать пользователю, чтобы он перешел в диалог с ботом. Например, чтобы он уточнил какую-нибудь информацию о себе и т.д. Для этого, в методе `answer_inline_query` есть параметр `switch_pm_text` и `switch_pm_parameter`. ![](https://i.imgur.com/oH8W2UI.png) Параметр `switch_pm_text` отвечает за текст кнопки. При нажатии на эту кнопку, пользователь перейдет в диалог с ботом, и вызовет команду `/start` с параметром, указанным в `switch_pm_parameter`. :::info Пользователь увидит только сообщение с текстом `/start`, а параметр будет доступен для обработки ботом. ::: ## Задание №7: Информация о пользователе в Inline mode Модифицируйте вашего бота из [задания №6](#Задание-№6-Бот-с-webhook-на-Heroku) таким образом, чтобы при упоминании его в диалоге, он предлагал вывести информацию о вас. При этом от лица пользователя (с пометкой *via @bot*) отправлялось сообщение с информацией о пользователе в том же формате, что и в [задании №6](#Задание-№6-Бот-с-webhook-на-Heroku). # Telegram speech-to-text bot Часто в группах люди записывают голосовые сообщения, но не всегда есть возможность послушать их (например, на совещании). Поэтому в Telegram существуют боты, которые переводят голосовые сообщения в текстовые. Один из таких ботов - [@voicybot](https://tlgg.ru/BotFather). После добавления в группу он будет транслировать любое голосовое сообщение в текстовое. ## Обработка медиафайлов Как получить голосовое сообщение пользователя: 1) Получить доступ к информации о голосовом сообщении, прикрепленном сообщении, используя `voice_info = bot.get_file(message.voice.file_id)` 2) Скачать файл (в виде байтов) с серверов Telegram: `voice_bytes = bot.download_file(voice_info.file_path)` 3) Записать байты в файл: ```python= with open('voice.ogg', 'wb') as file: file.write(voice_bytes) ``` ## Задание №8: Бот-облако Разработайте бота, который сохраняет голосовые сообщения, картинки и документы на диск компьтера в разные папки (voice, pics, docs). Протестируйте бота и проверьте, правильно ли он сохраняет файлы. ## SpeechRecognition Для того, чтобы распознавать речь, воспользуемся библиотекой [SpeechRecognition](https://pypi.org/project/SpeechRecognition/). Она поддерживает несколько API: - Google Speech Recognition - Microsoft Azure Speech - Wit.ai - IBM Speech to Text - и еще несколько других... Мы будем пользоваться Google Speech Recognition, т.к. его можно использовать бесплатно. ```python= import speech_recognition as sr recognizer = sr.Recognizer() with sr.AudioFile('file.wav') as source: audio = recognizer.record(source) text = recognizer.recognize_google(audio, language='ru-RU') ``` ## Задание №9: Распознавание голоса Напишите простую программу, которая умеет распознавать голос из аудиофайлов. Пример использования программы: ```bash recognize.py file1.wav file2.wav ... fileN.wav # output: Text1 Text2 Text3 ... TextN ``` ## Задание №10: Многопользовательский STT бот Разработайте бота, транслирующего голосовое сообщение в текстовое после добавления в группу. Проверьте работоспособность бота вместе с коллегами. 1) Бот должен использовать webhook 2) Бот должен быть задеплоен на Heroku 3) Для распознавания речи используйте модуль `SpeechRecognition` 4) При отправке голосового сообщения, бот сразу должен дать понять пользователю, что он работает (например, сообщением типа "Обрабатываю..."). После того, как голосовое сообщение распознано, бот должен изменить это сообщение на распознанный текст. Подсказки: 1) Чтобы бот видел сообщения в группе, разрешите ему делать это в @BotFather в секции "**Allow groups?**" 2) Для перевода .ogg файла в .wav файл используйте модуль [pydub](http://pydub.com/) ```python # convert .ogg voice file to .wav pydub.AudioSegment.from_ogg(voice_path_ogg).export(voice_path_wav, format='wav') ```

Import from clipboard

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template is not available.
Upgrade
All
  • All
  • Team
No template found.

Create custom template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

How to use Slide mode

API Docs

Edit in VSCode

Install browser extension

Get in Touch

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Upgrade to Prime Plan

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

No updates to save
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Upgrade

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Upgrade

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully