I'm new in development and python too. I tried to write a simple telegram bot using Telebot. The scenario is to show inline keyboard to user when user click on button do some logic. In Example below I cut the code but it showing the problem. And the problem is:
When first user start working he gets correct and all notifications. But when second user starts to work with bot he gets correct keyboard but notification will send to First user.
Here is a code example:
import telebot
import datetime
bot = telebot.TeleBot(insert_token_here)
keyboard1 = telebot.types.ReplyKeyboardMarkup(True)
keyboard1.row('Choose date', 'dont push it')
#bot.message_handler(commands=['start'])
def start_message(message):
bot.send_message(message.chat.id, 'Welcome', reply_markup=keyboard1)
def dates_inline():
current_date = datetime.datetime.today()
# Inline keyboard
keyboard_dates = telebot.types.InlineKeyboardMarkup()
key_now = telebot.types.InlineKeyboardButton(text=current_date.strftime('%d.%m.%Y') + ' (Today)',
callback_data=current_date.strftime('%Y-%m-%d'))
keyboard_dates.add(key_now)
return keyboard_dates
#bot.message_handler(content_types=['text'])
def choose_message(message):
if message.text == "Choose date":
bot.send_message(message.chat.id, 'Choose date:', reply_markup=dates_inline())
#bot.callback_query_handler(func=lambda call: True)
def choose_date(call):
dt = call.data
print('chose_date dt: %s' % dt)
bot.send_message(message.chat.id, 'All done')
print('end')
else:
print('smth else')
def main():
bot.polling(none_stop=True)
if __name__ == '__main__':
main()
I also faced a similar problem.
Do not create a handler/decorator inside another one. It doesn't work like that. I'm also relatively new to python, so I don't know the exact reason. I also learned it from my mistake.
Do not send messages back to message.chat.id . send it to call.from_user.id so that it'll always send the reply back to the user from whom the call came.
#bot.message_handler(content_types=['text'])
def choose_message(message):
if message.text == "Choose date":
bot.send_message(message.chat.id, 'Choose date:', reply_markup=dates_inline())
else:
print('smth else')
#bot.callback_query_handler(func=lambda call: True)
def choose_date(call):
dt = call.data
print('chose_date dt: %s' % dt)
bot.send_message(call.from_user.id, 'All done')
print('end')
I am also in the development of a bot right now and this is working fine for me.
You need to move following code to top-level indentation. Otherwise it works not as you intended.
#bot.callback_query_handler(func=lambda call: True)
def choose_date(call):
dt = call.data
print('chose_date dt: %s' % dt)
bot.send_message(message.chat.id, 'All done')
#wowkin2 Here is a sample code:
#bot.message_handler(content_types=['text'])
def choose_message(message):
if message.text == "Choose date":
bot.send_message(message.chat.id, 'Choose date:', reply_markup=dates_inline())
print('end')
else:
print('smth else')
#bot.callback_query_handler(func=lambda call: True)
def choose_date(call):
dt = call.data
bot.send_message(message.chat.id, 'All done')
Related
I'm trying to get code from user and if it's correct to start sending him options.
But the third function (send_welcome) doesn't start. Could you say what I'm missing?
#bot.message_handler(commands=['start'])
def send_text_request(message):
msg = bot.send_message(message.chat.id, "Write a code")
bot.register_next_step_handler(msg, function)
def function(message):
if message.text=='6':
print('hello')
bot.register_next_step_handler(message, send_welcome)
def send_welcome(message):
markup=types.ReplyKeyboardRemove(selective=False)
markup = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)
itembtn1 = types.KeyboardButton("option1")
itembtn2 = types.KeyboardButton("option2")
markup.add(itembtn1, itembtn2)
msg = bot.send_message(message.chat.id, "Hello "+message.from_user.first_name+", I will help you! \n Enter the product", reply_markup=markup)
I'm using telebot and want to create several functions based on text inputs.
But it doesn't work. Bot takes only the first function.
Is it possible to create for example different function for greeting and data request so on?
I know I can do similar things usings command but I need to use text instead. Also because it's like conversation not process I don't want to use register_next_step_handler. Is thera a way with message_handler functions?
thank you in advance!
#bot.message_handler(content_types=['text'])
def greetings(message):
if message.text.lower()=='hello':
bot.send_message(message.chat.id, f"Hello {message.from_user.first_name}")
elif message.text.lower()=="bye":
bot.send_message(message.chat.id, f"Good Bye {message.from_user.first_name}")
else:
pass
#bot.message_handler(content_types=['text'])
def requests(message):
if message.text.lower()=='data':
bot.send_message(message.chat.id, f"{message.from_user.first_name} which data do you want?")
elif message.text.lower()=="forecast":
bot.send_message(message.chat.id, f"{message.from_user.first_name} we have only historic data")
For something like this I think you can use the func input for the message handler.
# Create a function that checks the message and sends answer to message handler
def check_function(message):
if message.text.lower() == "hello":
bot.send_message(message.chat.id, f"Hello {message.from_user.first_name}")
return True
elif message.text.lower() == "bye":
bot.send_message(message.chat.id, f"Good Bye {message.from_user.first_name}")
return True
elif message.text.lower() == "forecast":
bot.send_message(message.chat.id, f"{message.from_user.first_name} we have only historic data")
return True
elif message.text.lower() == 'data':
bot.send_message(message.chat.id, f"{message.from_user.first_name} which data do you want?")
return True
else:
pass
# Message handler using func
#bot.message_handler(func=check_function)
# Create a fake function that does nothing cause you need something after the handler that isn't polling.
def foo(message):
pass
bot.polling()
I'm trying to make /stop command for the bot (the greetings stop to send). It works, but only one time, after pressing the /start command it is unable to stop again and runs forever.
Tried different methods of stopping, manged either to stop and unable to restart or to stop once and unable to stop after repeating /start or "greet".
I would be very grateful for the advice of how to improve the existing code
import random, telebot, schedule, time
from telebot import types
from config import token
bot = telebot.TeleBot(token)
greetings = ["hello", "Have a nice day", "Goodbye", "Wow"]
#bot.message_handler(commands=['start'])
def start_message(message):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
item1 = types.KeyboardButton("Greet")
markup.add(item1)
bot.send_message(message.chat.id, "Press button", reply_markup=markup)
#bot.message_handler(content_types=["text"])
def run_function(message):
def function_to_run():
random_greet = random.choice(greetings)
bot.send_message(message.chat.id, random_greet)
def scheduling():
schedule.every(4).seconds.do(function_to_run).tag('schedule')
scheduling()
if message.text.lower() == "greet":
bot.send_message(message.chat.id, "here you go")
function_to_run()
def schedule_run():
while True:
schedule.run_pending()
time.sleep(1)
schedule_run()
elif message.text.lower() == "stop":
bot.send_message(message.chat.id, "stopping...")
schedule.clear('schedule')
time.sleep(1)
bot.send_message(message.chat.id, "stopped successfully")
bot.polling()
import random, telebot, schedule, time
from telebot import types
from config import token
bot = telebot.TeleBot(token)
greetings = ["hello", "Have a nice day", "Goodbye", "Wow"]
#bot.message_handler(commands=['start', 'stop'])
def start_message(message):
command = message.text.split()[0]
if command == "/start":
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
item1 = types.KeyboardButton("Greet")
markup.add(item1)
bot.send_message(message.chat.id, "Press button", reply_markup=markup)
elif command == "/stop":
bot.send_message(message.chat.id, "stopping...")
schedule.clear('schedule')
time.sleep(1)
bot.send_message(message.chat.id, "stopped successfully")
exit()
#bot.message_handler(content_types=["text"])
def run_function(message):
...
# or
elif message.text.lower() == "stop":
bot.send_message(message.chat.id, "stopping...")
schedule.clear('schedule')
time.sleep(1)
bot.send_message(message.chat.id, "stopped successfully")
exit()
bot.polling()
if you want to on it again try this:
import random, telebot, schedule, time
from telebot import types
from config import token
bot = telebot.TeleBot(token)
greetings = ["hello", "Have a nice day", "Goodbye", "Wow"]
on = True
#bot.message_handler(commands=['start', 'stop'])
def start_message(message):
global on
command = message.text.split()[0]
if command == "/start" and not on:
on = True
# your code
if command == "/stop" and on:
on = False
# your code
#bot.message_handler(content_types=["text"])
def run_function(message):
global on
if on:
# your code
bot.polling()
I am trying to do an optional input, and have this code
bot.send_chat_action(message.from_user.id, 'typing')
markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton("Лечу только в одну сторону", callback_data="one_way"))
msg = bot.send_message(message.from_user.id, '✅Хорошо. Теперь введите дату возвращения:', reply_markup=markup)
bot.register_next_step_handler(msg, get_return_date)
This code sends user a message with button to skip this step, and registers function get_return_date(), that waits for a date value. Message
And if user clicks the button, query handler register another function get_adults(), that waits for numeric value:
#bot.callback_query_handler(func=lambda call: call.data == "one_way")
def is_one_way(call):
msg = bot.send_message(call.from_user.id,
'✅Хорошо. Сколько взрослых (пассажиров старше 12-ти лет на момент полёта) полетят 🤵👩💼?')
bot.register_next_step_handler(msg, get_adults)
return
And, trouble is that - if user clicks the button to skip, both get_return_date() and get_adults() are waiting for a value and work at one time:
Problem
Any ideas what should i do?
You can do this:
bot.send_chat_action(message.from_user.id, 'typing')
msg = bot.send_message(message.from_user.id, '✅Хорошо. Теперь введите дату возвращения: (you can skip this passage with /skip)')
bot.register_next_step_handler(msg, get_return_date)
def get_retourn_date(message):
if message.text == '/skip':
get_adults()
return
# write here the actual function code
i use query callbacks and i put this func at the begining of the callback:
bot.clear_step_handler_by_chat_id(call.message.chat.id)
u can use it like this
def gen_markup():
markup = InlineKeyboardMarkup()
markup.row_width = 1
markup.add(InlineKeyboardButton("Button 1", callback_data="one"),
InlineKeyboardButton("Button 2", callback_data="two"))
def ButtonOneFunc(message):
#do whatever u want here
def ButtonTwoFunc(message):
#do whatever u want here
#bot.callback_query_handler(func=lambda call: True)
def callback_query(call):
bot.clear_step_handler_by_chat_id(call.message.chat.id)
if call.data == "one":
sent= bot.reply_to(call.message, "This is Button 1")
bot.register_next_step_handler(sent, ButtonOneFunc)
elif call.data == "two":
sent= bot.reply_to(call.message, "This is Button 2")
bot.register_next_step_handler(sent, ButtonTwoFunc)
what will happen here is, whenever the user will click a button, it will clear all next_register_handler that were open
and then enter the new call.data and set the handler which the user clicked on
I'm building a Telegram bot with the library https://github.com/eternnoir/pyTelegramBotAPI
I'm trying to make when I press a menu button, it sends a message to the user.
How could I do it?
import telebot
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
TELEGRAM_TOKEN = '<TOKEN>'
bot = telebot.TeleBot(TELEGRAM_TOKEN)
def gen_markup():
markup = InlineKeyboardMarkup()
markup.row_width = 2
markup.add(InlineKeyboardButton("Yes", callback_data="cb_yes"),
InlineKeyboardButton("No", callback_data="cb_no"))
return markup
#bot.callback_query_handler(func=lambda call: True)
def callback_query(call):
if call.data == "cb_yes":
bot.answer_callback_query(call.id, "Answer is Yes")
elif call.data == "cb_no":
bot.answer_callback_query(call.id, "Answer is No")
#bot.message_handler(func=lambda message: True)
def message_handler(message):
bot.send_message(message.chat.id, "Yes/no?", reply_markup=gen_markup())
bot.polling(none_stop=True)
You can use data of your call object as the user id(call.from_user.id) of the sender to send a message:
if call.data == "cb_yes":
bot.answer_callback_query(call.id, "Answer is Yes")
bot.send_message(call.from_user.id,"Your answer was Yes!")
elif call.data == "cb_no":
bot.answer_callback_query(call.id, "Answer is No")
bot.send_message(call.from_user.id,"Your answer was No!")