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()
Related
So I made this command where it would give a random generated image of a pokemon and then the person who runs the command gotta guess what's the pokemon's name. he needs to give the answer on the channel he runs the command previously. the problem is, even when the answer is correct it'd still response with "the answer is incorrect". so how do I fix this? can someone help me please?
#client.command()
async def rp(ctx):
ranpoke = random.randint(1, 905)
url = "https://pokeapi.co/api/v2/pokemon/"
secs = 5
try:
r = requests.get(f"{url}{ranpoke}")
packages_json = r.json()
packages_json.keys
napo = packages_json["name"]
embed = discord.Embed(title = "Who's that pokemon?!", color = discord.Color.random())
embed.set_image(url = f"https://play.pokemonshowdown.com/sprites/ani/{napo}.gif")
await ctx.send(embed = embed)
def check(msg):
return msg.author == ctx.author and msg.channel == ctx.channel
user_ans = await client.wait_for("message", check=check)
if user_ans == napo:
await ctx.send("You are correct! :)")
elif user_ans != napo:
await ctx.send(f"You are incorrect :v\nThe answer is {napo}")
except:
await ctx.send("bruh")
I'm expecting it to like say the answer is correct when it's correct, and say that the answer is incorrect when it's incorrect.
I've tried the first part of the code and the request seems to work fine, so the problem is either when you get the message or when you compare it. I see a case when it can fail even with a "correct" answer, comparing strings on python is case-sensitive, to avoid that you can use the string method .lower() before comparing the answer.
If this doesn't solve the problem, maybe the issue is located when you catch the user message, try doing a print(user_ans) to see in the console if you are catching the information properly.
user_ans == napo
user_ans is a discord.Message object, while napo is a string. When you compare these two objects using the == operator, it will always return False, because user_ans and napo are not the same object.
To fix the issue, you can compare the content of the message (i.e., the text that the user typed) to napo. To do this, you can use the .content attribute of the discord.Message object:
if user_ans.content == napo:
This will compare the text of the message (user_ans.content) to the string napo, and return True if they are equal, and False otherwise.
if napo = packages_json["name"] is a list of names then comparing it using == and != is wrong on lists and you may use something like this :
if user_ans in napo :
await ctx.send("You are correct! :)")
else:
await ctx.send(f"You are incorrect :v\nThe answer is {napo}")
Also be careful, if the JSON name contains lower/upper case and the user submission is not the same, the function returns false.
so you may use .lower() on user submission and list of names before comparing them.
well... i saw it and you mistook in a thing there, actually you need to see the content there, user_ans.content also try to check them in .lowercase() so it will be like this:
if user_ans.content.lower() == napo.lower():
await ctx.send("You are correct! :)")
else:
await ctx.send(f"You are incorrect :v\nThe answer is {napo}")
If you want to make your command wait only for a specific time/ or until correct answer then you can try:
def check(msg):
return msg.author == ctx.author and msg.channel == ctx.channel
for i in range(3):
try:
user_ans = await client.wait_for("message", check=check, timeout=10)
if user_ans.content.lower() == napo.lower():
await ctx.send("You are correct! :)")
else:
await ctx.send(f"You are incorrect!")
except asyncio.TimeoutError:
await ctx.send(f"Opps, you ran out of time... the correct answer was {napo}")
Here your bot will wait for 10 seconds and the command user have 3 attempts to answer correctly... If they fail then it will send correct answer
What I've tried
StackOverflow articles
Need help to fix a certain bug in rock, scissor and paper.
discord.py documentation
How can I add reaction to a message
(checked plenty of articles, but I'm not going to add them in order to get into the point)
I've managed to retrieve the emoji from the user in the check method, but still the issue with timeouterror appears, so there is something I'm missing which I can't get a hold on.
In this senario im using Cog,
The issue
Even though the wait_for passes the check method, I'm not sure how to send it forward to the logical conditon. The result I get is passed in the exception.
bot.py
import os
from dotenv import load_dotenv
from discord import Intents
# lib
from lib.cog.miniGames import miniGames # Games
from lib.client.krigjo25 import krigjo25
# Importing .evn file
load_dotenv()
def botSetup ():
# necsessary values from .env
botKey = os.getenv('Token')
server = os.getenv('server')
# discord configs
intents= Intents.all()
#retrieving the module command prefix is created in the bot module
bot=krigjo25(intents=intents)
# adding cogs into the bot
bot.add_cog(miniGames(bot))
bot.run(botKey)
if __name__ == '__main__':
botSetup()
miniGames.py
class miniGames(Cog, name='miniGames module'):
def __init__(self, bot):
self.bot = bot
#command(name='rsp')
#Cog.listener()
# 1: Creating a game where the user has three choices to choose between from
# 2: The bot adds 3 reactions, where you have to choose one of them as an answer
# 3: The bot checks wheter the conditions is true or false, in order to send the correct messge:
async def RockscissorsPaper(self, message:Message):
# Declearing variables
# Rock, Scissors, Paper
rock,scissor, paper = '\U0001FAA8', '\U00002702','\U0001F4C4'
answer = { 0:'\U0001FAA8',
1:'\U00002702',
2:'\U0001F4C4'}
# Randomizing the answer and assign it to the variable
shuffle(answer)
x = randrange(0,2)
answer = '\U0001FAA8' #answer.get(x)
print(answer)
# Creating Embed message
embed = Embed(color = Color.blurple())
embed.title = 'Rock, Scissors & Paper'
embed.description = ' In order to play the game, please click one one of the following reactions'
# Sending & adding reactions
ch = await message.channel.send(embed=embed)
await ch.add_reaction(rock)
await ch.add_reaction(scissor)
await ch.add_reaction(paper)
# passes the check method
def check( user, reaction):
print('check function', reaction, user)
return user == message.author and reaction == str(reaction.emoji)
# Checks the user's input¨'
# Questions : Is it possible to use dictionaries in order to find the given emoji?
try :
# How does this work? If wait_for is a "asynico" function how can it work like this?
reaction, user = await self.bot.wait_for('reaction_add', timeout=30, check=check)
except TimeoutError as e:
print(e)
else:
reaction = str(reaction.emoji)
# Checking if its the bots reaction
if user == self.bot.user:
return None
else:
if reaction == '\U0001F4C4' and answer == '\U0001FAA8':
await message.channel.send(' you won')
Add this at the beginning of your code:
intents = discord.Intents.all()
Then add this into your discord.Bot's declaration:
bot = discord.commands.Bot(prefixes=['!'], intents=intents)
Then go to Discord Developer Portal and enable all the intents writing from the Application's "bot" page.
can u remove this line?
#command(name='rsp')
--> #Cog.listener()
# 1: Creating a game where the user has three choices to choose between from
What is this listener supposed to answer?
It appears that i had to change :
def check( user, reaction):
print('check function', reaction, user)
return user == message.author and reaction == str(reaction.emoji)
New
def emojiCheck(reaction, member):
reaction = str(reaction)
member == ctx.author.name
# Do not return the bot's last reaction
return member !=self.bot.user and reaction
--
I also had to add the code block in the try - except statement.
** OLD **
try :
# How does this work? If wait_for is a "asynico" function how can it work like this?
reaction, user = await self.bot.wait_for('reaction_add', timeout=30, check=check)
except TimeoutError as e:
print(e)
else:
reaction = str(reaction.emoji)
# Checking if its the bots reaction
if user == self.bot.user:
return None
else:
if reaction == '\U0001F4C4' and answer == '\U0001FAA8':
await message.channel.send(' you won')
New
try:
# Timer Check
reaction, member = await self.bot.wait_for('reaction_add', timeout=60.0, check=emojiCheck)
print(member, reaction, answer)
# Dictionaries
# Tie
tie = {
0:f'{self.bot.user} draws a **tie** for {member}',
1:'Sir, lets **tie** a **tie**',
2:'What did the **tie** say to the bowtie? You\'re a weirdo',
3:'lets have a wii-match',
}
reactionRock = {
}
# Randomize the dictionary
shuffle(tie)
x = randrange(0,3)
tie = tie.get(x)
# If the situation is a draw / tie
if str(reaction) == answer:
self.embed.description = tie
await ctx.send(embed = self.embed)
The point is if-elif or else statement has to be inside the try-except statement.
Hope this is for help for other developers which has the same issue.
Thanks for the assistance which I received. Its appreciated.
I am trying to make a function whenever the user reacts with the check emoji or if they react with the x. So basically I have a check if the user has a phone, if the user has a phone then you can call them. The bot sends a message in dms and reacts with a check and a x, if you click the check I want a function to happen, how can I do this?
#commands.command()
#commands.cooldown(1,120,commands.BucketType.user)
async def call(self, ctx, member : discord.Member):
phone = False
users = await bank_data()
user = ctx.author
client = discord.Client
try:
bag=users[str(user.id)]["bag"]
except:
bag=[]
for item in bag:
name = item["item"]
if name == "phone":
phone = True
if phone == False:
await ctx.reply("You must buy a phone to call someone idiot.")
if phone == True:
try:
targetBag = users[str(target.id)]["bag"]
except:
targetBag=[]
targetPhone = False
if target:
for item in targetBag:
name = item["item"]
if name =="phone":
targetPhone = True
if targetPhone == False:
await ctx.reply("Attempted user to call does not have a phone.")
if targetPhone == True:
channel = await target.create_dm()
emojis=['✅', '❌']
confirmEmoji = '✅'
message=await channel.send(f"{ctx.author} is calling you. Do you want to answer?")
for emoji in emojis:
await message.add_reaction(emoji)
You can use the wait_for() for this case. Create a response variable so that you can check and use the response to answer the phone or decline it.
You can read more about it here-
https://discordpy.readthedocs.io/en/stable/api.html#discord.Client.wait_for
There are different types of events which you can pass into wait_for() in your case it's reaction_add
Hope this helped :D
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 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')