owned this note
owned this note
Published
Linked with GitHub
---
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, и т.д.)

Для того, чтобы зарегистрировать бота:
1) Введите команду `/newbot`
2) Введите название бота (например: My First Bot)
3) Введите **@алиас** бота, заканчивающийся на bot или Bot (без @, например: MyFirstBot)
4) Бот создан! BotFather отправит сообщение, где указан токен бота.

:::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.

Очевидный минус такого способа - огромное количество запросов к серверу, даже если новых изменений нет.
---
**Webhook** - метод, при котором **сервера Telegram сами отправляют** изменения вашему боту. Таким образом решается главная проблема polling'а - огромное количество бессмысленных запросов.

Минусы данного подхода:
- нужно сгенерировать и настроить 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) – клавиатуры, встроенные в сообщение. Могут обновлять сообщение и себя после нажатия
## Пользовательские клавиатуры
Клавиатуры, заменяющие пользователю основную клавиатуру

:::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**) клавиатуры гораздо более удобны в случае необходимости адаптации выбора ответа под сообщение.

Создаем клавиатуру и отправляем ее вместе с сообщением:
```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
Состояние -> Внешние данные -> Переход (Действие) -> Новое состояние
:::
## Простейший конечный автомат на примере пропускной системы (турникетов):

Белыми кругами обозначены состояния, а стрелками обозначены переходы между состояниями. Черным кругом обозначено начальное состояние.
## Чат-бот как конечный автомат
Рассмотрим пример бота, реализующего простую викторину:

Как мы видим, диалоговых ботов также можно рассматривать как конечные автоматы:
* Действия бота определяются текущим состоянием пользователя, с которым бот ведет диалог
* Переходы между состояниями происходят в следствии действий пользователя
## 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).

## Поддерджка 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 моде.
При вводе **@алиаса** бота и поисковом запросе, бот предложит самые релевантные видео.

А при нажатии на одно из предложений, пользователь отправит сообщение от своего имени с пометкой "через **@youtube**". К такому сообщению также могут быть прикреплены кнопки.

Давайте разберемся, как реализовать похожий функционал.
Для начала, в [@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"**:

## 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`.

Параметр `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')
```