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
Related
i have this code for the message:
#FBot.message_handler(commands=["spy"])
def SpyInit(message):
spyInstance = game.Spy(1, message)
markup = types.InlineKeyboardMarkup()
startButton = types.InlineKeyboardButton("start", callback_data=spyInstance.id.id)
markup.add(startButton)
message = FBot.reply_to(message, "reply on this message to be added to the game", reply_markup = markup)
SpyList.append(spyInstance)
and this:
#FBot.callback_query_handler(func=lambda call : True)
def callback_query(call):
print(call.data)
for instance in SpyList:
if call.data == instance.id.id:
instance.Start()
Spy = instance
for player in Spy.PlayerList:
if Spy.spy == player:
FBot.send_message(player.id, "you are the spy")
else:
FBot.send_message(player.id, Spy.word)
the problem is, i get the first message with the start button but clicking the button does nothing.
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 have made a dropdown select in discord.py but when the user selects an option i dont want to respond with a message but if i dont respond with a message i get "Interaction Failed" in discord.
#commands.command()
async def shop(self,ctx):
em = discord.Embed(title = "Store",description = "Buy smthing", colour = ctx.author.colour)
await ctx.send(embed = em,
components=
[
Select(placeholder="Choose a item",
options=[
SelectOption(
label = "A",
value = "a",
description = ""
),
SelectOption(
label = "B",
value = "b",
description = ""
),
]),
Button(style = ButtonStyle.blue, label="button 1")
])
def check(msg):
return msg.author == ctx.author and msg.channel == ctx.channel
while True:
try:
res = await self.client.wait_for("select_option", check=check, timeout=10)
label = res.values[0]
await res.respond(content=f"U have clicked {label}") #If I don't write this line i get the message "Interaction failed"
print(label) #This was just for checking the output.
break
except asyncio.TimeoutError:
await ctx.send("Sorry, you didn't reply in time!")
break
except discord.NotFound:
print("error")
I dont fully understand how dropdown works, can someone please explain how to go abt this.
For example dank memer doesnt send response when i click on a option.
NO respones from bot when i clicked on the option
You can try
res.edit_origin(content = "This message can be exactly the same as your original message")
This function does not send any message, but it does stop the interaction failed message to appear
You can also do the following to change the embed and buttons / select menu:
res.edit_origin(content = "just some random message",component =[newButtons],embed=EmbedObject)
BTW: The image in your question was done by disabling the message's button (basically editing the buttons).
You can try this :
await interaction.response.defer()
will complete the interaction without the error
This interaction failed'
This is especially helpful while doing edit messages or add roles to users without any output
You must respond to a message when a dropdown is clicked. This is a Discord API limit.
There is a way but it isn't that clean:
#client.command(name='test')
async def text(ctx):
global ctxn #make a global variable named for example ctxn
ctxn = ctx #double the value from the ctx ;)
global msgTest
#Define the Fields you want to have in the Dropdown
msgTest = await ctx.send(f'```Select a component```',components = [
[Select(placeholder="Select Settings",
options=[SelectOption(label="Label1", value="Value1"), #Label is the Display Name, Value is for Interaction Selection
SelectOption(label="Label2", value="Value2"),
SelectOption(label="Label3", value="Value3")])]
]
)
#client.event
async def on_select_option(interaction):
#After the selection it searches for the value="XXXXX"
if interaction.values[0] == "Value1":
await msgTest.delete() #Here you delete the dropdown after you selected an entry
await TEST1(ctx=ctxn) #Call the Function with the copied ctx start value
if interaction.values[0] == "Value2":
await msgTest.delete() #Here you delete the dropdown after you selected an entry
await TEST2(ctx=ctxn) #Call the Function with the copied ctx start value
if interaction.values[0] == "Value3":
await msgTest.delete() #Here you delete the dropdown after you selected an entry
await TEST3(ctx=ctxn) #Call the Function with the copied ctx start value
#Here you can programm your functions
async def TEST1(ctx): #First Function
return await ctx.send("Function 1 were selected")
async def TEST2(ctx): #Second Function
return await ctx.send("Function 2 were selected")
async def TEST3(ctx): #Third Function
return await ctx.send("Function 3 were selected")
If you don't delete the dropdown menu which you sendet within the msgTest variable, you will still get the interaction failed msg.
Is it available to wait inline button push or text message simultaneously in Telethon conversation?
async with bot.conversation(chat_id) as conv:
buttons = [[Button.inline('Yes'), Button.inline('No')]]
conv.send_message('To be or not no be? Answer yes|no, or write your own opinion', buttons=buttons)
#This way we can wait for button press
def press_event(user_id):
return events.CallbackQuery(func=lambda e: e.sender_id == user_id)
press = await conv.wait_event(press_event(sender_id))
#...and this way we can wait for text message
response = await conv.get_response()
#And how can we wait for press event OR text message simultaneously?
So, here is the solution (thanks to Lonami)
#bot.on(events.NewMessage(pattern='/test'))
async def worklogs(event):
chat_id = event.message.chat.id
sender = await event.get_sender()
sender_id = sender.id
async with bot.conversation(chat_id) as conv:
def my_press_event(user_id):
return events.CallbackQuery(func=lambda e: e.sender_id == user_id)
buttons = [[Button.inline('Yes'), Button.inline('No')]]
await conv.send_message('To be or not no be? Answer yes|no, or write your own opinion', buttons=buttons)
tasks = [conv.wait_event(my_press_event(sender_id)), conv.get_response()]
done, pendind = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
event = done.pop().result()
if type(event) is events.callbackquery.CallbackQuery.Event:
selected = event.data.decode('utf-8')
print(f'Got button: "{selected}"')
elif type(event) is tl.patched.Message:
message = event.text
print(f'Got text message: "{message}"')
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')