Context:
I am using PyTelegramBotAPi or Python Telegram Bot
I have a code I am running when a user starts the conversation.
When the user starts the conversation I need to send him the first picture and a question if He saw something in the picture, the function needs to wait for the user input and return whether he saw it or not.
After that, I will need to keep sending the picture in a loop and wait for the answer and run a bisection algorithm on it.
What I have tried so far:
I tried to use reply markup that waits for a response or an inline keyboard with handlers but I am stuck because my code is running without waiting for the user input.
The code:
@bot.message_handler(func=lambda msg: msg in ['Yes', 'No'])
@bot.message_handler(commands=['start', 'help'])
def main(message):
"""
This is my main function
"""
chat_id = message.chat.id
try:
reply_answer = message.reply_to_message.text
except AttributeError:
reply_answer = '0'
# TODO : should wait for the answer asynchnonossly
def tester(n, reply_answer):
"""
Displays the current candidate to the user and asks them to
check if they see wildfire damages.
"""
print('call......')
bisector.index = n
bot.send_photo(
chat_id=chat_id,
photo=bisector.image.save_image(),
caption=f"Did you see it Yes or No {bisector.date}",
reply_markup=types.ForceReply(selective=True))
# I SHOUL WAIT FOR THE INPUT HERE AND RETURN THE USER INPUT
return eval(reply_answer)
culprit = bisect(bisector.count, lambda x: x, partial(tester, reply_answer=reply_answer) )
bisector.index = culprit
bot.send_message(chat_id, f"Found! First apparition = {bisector.date}")
bot.polling(none_stop=True)
The algorithm I am running on the user input is something like this :
def bisect(n, mapper, tester):
"""
Runs a bisection.
- `n` is the number of elements to be bisected
- `mapper` is a callable that will transform an integer from "0" to "n"
into a value that can be tested
- `tester` returns true if the value is within the "right" range
"""
if n < 1:
raise ValueError('Cannot bissect an empty array')
left = 0
right = n - 1
while left + 1 < right:
mid = int((left + right) / 2)
val = mapper(mid)
tester_values = tester(val) # Here is where I am using the ouput from Telegram bot
if tester_values:
right = mid
else:
left = mid
return mapper(right)
I hope I was clear explaining the problem, feel free to ask any clarification.
If you know something that can point me in the right direction in order to solve this problem, let me know.
I have tried a similar question but I am not getting answers.
2
Answers
I have found the answer:
the trick was to use next_step_handler, and
message_handler_function
to handle command starting withstart
andhelp
Then as suggested by @ALi in his answer, I will be saving the user input answer as well as the question id he replied to in a dictionary where keys are questions and id are the answer.
Once the user has answered all questions, I can run the algorithms on his answer
Here is how it looks like in the code :
You should save your user info in a database. Basic fields would be:
(id, first_name, last_name, username, menu)
What is menu?
Menu keeps user’s current state. When a user sends a message to your bot, you check the database to find out about user’s current sate.
So if the user doesn’t exist, you add them to your users table with
menu
set toMainMenu
orWelcomeMenu
or in your casePictureMenu
.Now you’re going to have a listener for update function, let’s assume each of these a menu.
@bot.message_handler(commands=['start', 'help'])
so when the user sends
start
you’re going to check user’s menu field inside the function.I hope you got it.