Ведём (более-менее) осмысленные диалоги. Конечные автоматы
Полезных ботов мы уже умеем делать (если вам вдруг так не кажется, перечитайте первые уроки), теперь пора делать, кхм, «смышлённых».
Но для начала – немного теории. Будем считать, что диалог пользователя с ботом можно разбить на логические части: начало диалога, запрос одной информации, запрос другой информации, возврат к определенному этапу диалога, конец диалога. При этом можно сказать, что при каждом сообщении пользователя, его состояние (или состояние бота, с какой стороны посмотреть) меняется, и между этими состояниями осуществляются переходы. Под «состоянием» будем понимать следующее ожидаемое от пользователя действие.
Наш бот должен иметь возможность определять текущее состояние пользователя, подбирать соответствующие сообщения, а также дожидаться нужного ответа. Поставим задачу следующим образом: бот запрашивает у пользователя имя, возраст и просит отправить картинку. Не допускается некорректный ввод возраста и пропуск какого-либо шага. По команде /reset диалог начинается заново. Состояние пользователя не должно потеряться при перезагрузке бота.
На следующем рисунке изображены возможные состояния бота и переходы между ними.
Переход между состояниями
Бот должен помнить все сохранённые состояния даже после перезагрузки, поэтому нам потребуется отдельное хранилище во внешней памяти (например, на жёстком диске). Будем использовать однофайловую БД Vedis, позволяющую удобно хранить пары «ключ-значение». В качестве ключа возьмём ID пользователя, конвертированный в строку, а в качестве значения — его «состояние».
Пишем бота
С базы и начнём. Создадим пустой файл bot.py и рядом с ним dbworker.py , в котором опишем два метода для работы с БД: получение текущего состояния и смена состояния на желаемое.
Как видно из кода выше, не хватает ещё файла config.py . Создадим этот файл, в нём укажем токен бота, название базы данных (с расширением .vdb ) и зададим класс со списком возможных состояний пользователя:
Настало время перейти к описанию логики бота. По команде /start будем инициировать начало диалога и спрашивать у юзера его имя, затем переключать «состояние» на «ожидаем ввода имени». По команде /reset будем возвращаться в начало диалога, спрашивать имя и т.д., копируя код из обработчика /start. Различия появятся позже.
Теперь нам нужен хэндлер, который сработает только при определённом состоянии пользователя. Отлично, прямо так и сделаем:
Обратите внимание: мы сравниваем текущее состояние пользователя со значением состояния, необходимым для входа в функцию. Если у пользователя в данный момент другое состояние, то подхэндлерный метод просто не вызовется. Соответственно, если у вас два хэндлера, реагирующих на одно и то же состояние, сработает первый по списку.
Следующая функция должна принять от пользователя его возраст. Если в первом случае нам было всё равно, то теперь придётся заняться проверкой вводимых значений, причём делать надо именно на втором шаге, а не на первом.
Как видно из скриншота ниже, при вводе некорректных значений бот не сбрасывает диалог и не переходит к следующим вопросам, а «удерживает» состояние, вынуждая пользователя ответить корректно, при этом на шаге №1 любой ввод позволял перейти далее.
Некорректный ввод
Наконец, на последнем шаге мы ожидаем отправку изображения, поэтому дополнительно выставляем нужный content_types :
Если теперь запустить бота и проверить, логика должна быть правильной: на каждом этапе бот ожидает от юзера конкретное действия, возможно, проверяя корректность ввода. По команде /reset сбрасывает в начало, а благодаря записи текущего состояния на диск, боту не страшны перезапуски. Остаётся одна маленькая деталь: вдруг пользователь случайно очистит диалог с ботом или вдруг приложение заглючит и придётся снова вызывать команду /start. Добавим в первый обработчик несколько проверок, чтобы после долгой разлуки бот продолжал общаться с юзером на том месте, где они остановились:
Теперь вы умеете контролировать диалог пользователя и бота. Не забудьте изучить полный код урока на Github, если что-то осталось непонятно.
Python Telegram Bot, как дождаться ответа пользователя на вопрос и вернуть его
У меня есть код, который я запускаю, когда пользователь начинает разговор.
Когда пользователь начинает разговор, мне нужно отправить ему первое изображение и вопрос, видел ли он что-то на рисунке, функция должна дождаться ввода пользователя и вернуть, видел ли он это или нет.
После этого мне нужно будет отправить изображение в цикле, дождаться ответа и запустить алгоритм деления пополам.
Что я пробовал до сих пор:
Я пытался использовать разметку ответа, которая ожидает ответа, или встроенную клавиатуру с обработчиками, но я застрял, потому что мой код работает без ожидания ввода пользователя.
Код:
Алгоритм, который я запускаю для пользовательского ввода, выглядит примерно так:
Я надеюсь, что я четко объяснил проблему, не стесняйтесь спрашивать любые разъяснения. Если вы знаете что-то, что может направить меня в правильном направлении, чтобы решить эту проблему, дайте мне знать.
Telegram bot, timeout handler и привязка к пользователю начавшему диалог с ботом.
Приветствую всех, делаю бота на питоне , с модулем telebot , возник вопрос : 1. Как сделать таймаут хендлера , например боту отдана первая команда /k , бот ожидает ввода от пользователя , чтобы перейти к следующей функции get_info . , мне хотелось бы ввести тайм аут ожидания в районе 5 минут, а потом хендлер бы сбрасывался, возможно ли это сделать ? 2. Как сделать привязку к пользователю который ввел команду. Сейчас любой пользователь в группе может перехватить так сказать диалог с ботом. например , я пишу команду /k , и бот должен только от меня дальше пойти выполнять уже следующую функцию, подозреваю что нужно привязываться к параметрку uid = message.from_user.id , но может есть другой способ?
тебе нужна state machine для каждого пользователя
Удобнее делать на вебхуках, без всякого телебота, бот-апи у телеги простой — post-запросы.
И «диалоги» с отдельными пользователями проще будет разруливать.
На вебхуках не вариант , нет белого IP , да и уже много написано на этом модуле telebot, так что нужно как то на текущем виде получить. Как фильтровать пользователей разобрался , просто сравниваю UID в первой функции и во второй. Но вот как тайм аут ожидания тут вставить .. не где не нашел инфы об этом.
На вебхуках не вариант , нет белого IP.
Я могу ошибаться, но по-моему телега принимает self-signed сертификаты, так что можно заморочиться с дин. DNS (если всё-таки есть возможность «белого» IP).
Но вот как тайм аут ожидания тут вставить
Сохранять в start пользовательский uid и время когда пользователь написал первый раз. А в get_info проверять сколько времени прошло. Но это не красиво.
Попробовал привязаться к времени , но получилось не совсем то что нужно, получается функция get_info не сработает до ввода команды боту и соответственно не обработает разницу во времени
Ожидание ответа от пользователя telegram bot
Как реализовать ввод пользователя в Telegram Bot`e в разветвлении Switch?
Здравствуйте! Пишу телеграм бота. Столкнулся со следующей проблемой: Команды пользователя.
Telegram.Bot Как используя бота пригласить пользователя в приват канал?
Не подскажите как можно при помощи бота пригласить пользователя в приват канал, зная номер этого.
Как сделать так, чтобы Telegram bot работал для каждого пользователя отдельно?
Здравствуйте. Я написал телеграмм бота, он авторизуется на сайте электронного дневника и выдает.
Ожидание ответа пользователя и его обработка
Задача: Получить от пользователя на форме ответ "Правда" или "Ложь" по нажатию соответствующей.