Это минимальный пример, который использует ConversationHandler
для получения title
, text
и comments
в отдельных сообщениях
Вы начинаете разговор с помощью команды /add
.
Функция add()
отправляет пользователю сообщение с информацией о том, что делать, и возвращает значение TITLE
, информирующее бота о том, что следующее сообщение должно получить функцию get_title()
.
Функция get_title()
получает текст и сохраняет его в глобальном словаре как title
, и возвращает значение TEXT
, чтобы сообщить боту, что следующее сообщение должно получить функцию get_text()
.
Функция get_text()
получает текст и сохраняет его в глобальный словарь как text
, и он возвращает значение COMMENTS
, чтобы сообщить боту, что следующее сообщение должно получить функцию get_comments()
.
Функция get_comments()
получает текст и сохраняет его в глобальном словаре как comments
, и он отображает все данные из словаря (но он может сохранить его в базе данных). Он возвращает ConversationHandler.END
, чтобы сообщить боту, что это конец разговора. Он может вернуть COMMENTS
, чтобы получить больше комментариев, но он должен будет оставить комментарии в виде списка в словаре. И потребуется некоторая команда, чтобы прекратить получать комментарии, а затем сохранить все данные.
На основе примера кода разговорbot.py из документации
from telegram.ext import Updater, CommandHandler, ConversationHandler, MessageHandler, Filters
TOKEN = 'YOUR_TOKEN'
updater = Updater(token=TOKEN, use_context=True)
dispatcher = updater.dispatcher
# --- structure for data ---
data = {'title': "", 'text': "", 'comments': ""}
# --- states use in conversation ---
TITLE = 1
TEXT = 2
COMMENTS = 3
# --- functions use in conversation ---
# Command Handler which starts conversation
def add(update, context):
global data # to assign new dictionary to external/global variable
# create new empty dictionary
data = {'title': "", 'text': "", 'comments': ""}
update.message.reply_text("add title, text, comments in separated messages\n\nnow write title")
# next state in conversation
return TITLE
def get_title(update, context):
data['title'] = update.message.text
update.message.reply_text(f"title: {update.message.text}\n\nnow write text")
# next state in conversation
return TEXT
def get_text(update, context):
data['text'] = update.message.text
update.message.reply_text(f"text: {update.message.text}\n\nnow write comments")
# next state in conversation
return COMMENTS
def get_comments(update, context):
data['comments'] = update.message.text
update.message.reply_text(f"comments: {update.message.text}")
msg = """I got all data
title: {}
text: {}
comments: {}""".format(data['title'], data['text'], data['comments'])
update.message.reply_text(msg)
# end of conversation
return ConversationHandler.END
def cancel(update, context):
update.message.reply_text('canceled')
# end of conversation
return ConversationHandler.END
# --- create conversation ---
my_conversation_handler = ConversationHandler(
entry_points=[CommandHandler('add', add)],
states={
TITLE: [
CommandHandler('cancel', cancel), # has to be before MessageHandler to catch `/cancel` as command, not as `title`
MessageHandler(Filters.text, get_title)
],
TEXT: [
CommandHandler('cancel', cancel), # has to be before MessageHandler to catch `/cancel` as command, not as `text`
MessageHandler(Filters.text, get_text)
],
COMMENTS: [
CommandHandler('cancel', cancel), # has to be before MessageHandler to catch `/cancel` as command, not as `comments`
MessageHandler(Filters.text, get_comments)
],
},
fallbacks=[CommandHandler('cancel', cancel)]
)
dispatcher.add_handler(my_conversation_handler)
# --- run bot ---
updater.start_polling()
print('Running... [Press Ctrl+C to stop]')
updater.idle()
print('Stoping...')
updater.stop()
РЕДАКТИРОВАТЬ: что-то похожее с telebot
. Я использую глобальную переменную state
и message_handler, который перехватывает неизвестные сообщения
import telebot
TOKEN = 'TOKEN'
bot = telebot.TeleBot(TOKEN)
#print(bot.get_me())
# --- structure for data ---
data = {'title': "", 'text': "", 'comments': ""}
# --- states use in conversation ---
state = None
TITLE = 1
TEXT = 2
COMMENTS = 3
@bot.message_handler(commands=['add'])
def test(message):
global state
global data
data = {'title': "", 'text': "", 'comments': ""}
bot.send_message(message.chat.id, 'add title, text, comments in separated messages\n\nnow write title')
state = TITLE
@bot.message_handler()
def unknown(message):
global state
if state == TITLE:
data['title'] = message.text
bot.send_message(message.chat.id, f"title: {message.text}\n\nnow write text")
state = TEXT
elif state == TEXT:
data['text'] = message.text
bot.send_message(message.chat.id, f"text: {message.text}\n\nnow write comments")
state = COMMENTS
elif state == COMMENTS:
data['comments'] = message.text
bot.send_message(message.chat.id, f"comments: {message.text}")
msg = """I got all data
title: {}
text: {}
comments: {}""".format(data['title'], data['text'], data['comments'])
bot.send_message(message.chat.id, msg)
state = None
#else:
# print('unknown message')
# bot.send_message(msg.chat.id, 'unknown message')
@bot.message_handler(commands=['cancel'])
def test(message):
global state
bot.send_message(message.chat.id, 'canceled')
state = None
bot.polling()
РЕДАКТИРОВАТЬ: более простая версия
import telebot
TOKEN = 'TOKEN'
bot = telebot.TeleBot(TOKEN)
# --- structure for data ---
data = {'title': "", 'text': "", 'comments': ""}
# --- states use in conversation ---
bot.state = None # create own value `.state` in `bot` - so I don't have to use `global state`. Similar way I could create and use `bot.data`
TITLE = 1
TEXT = 2
COMMENTS = 3
@bot.message_handler(commands=['add'])
def test(message):
global data
data = {'title': "", 'text': "", 'comments': ""}
bot.send_message(message.chat.id, 'add title, text, comments in separated messages\n\nnow write title')
bot.state = TITLE
# it has to be before functions which check `bot.state`
@bot.message_handler(commands=['cancel'])
def test(message):
bot.send_message(message.chat.id, 'canceled')
bot.state = None
@bot.message_handler(func=lambda msg:bot.state==TITLE)
def get_title(message):
data['title'] = message.text
bot.send_message(message.chat.id, f"title: {message.text}\n\nnow write text")
bot.state = TEXT
@bot.message_handler(func=lambda msg:bot.state==TEXT)
def get_title(message):
data['text'] = message.text
bot.send_message(message.chat.id, f"text: {message.text}\n\nnow write comments")
bot.state = COMMENTS
@bot.message_handler(func=lambda msg:bot.state==COMMENTS)
def get_title(message):
data['comments'] = message.text
bot.send_message(message.chat.id, f"comments: {message.text}")
msg = """I got all data
title: {}
text: {}
comments: {}""".format(data['title'], data['text'], data['comments'])
bot.send_message(message.chat.id, msg)
bot.state = None
bot.polling()