python-telegram-bot - process the output of a ReplyKeyboardMarkup - python

I'm using python-telegram-bot and I need to process the output of a reply keyboard to use this in further steps (e.g., to return to the user an output based on her choice).
This is my code
def start(update, context):
reply_keyboard = [['Boy', 'Girl', 'Other']]
update.message.reply_text(
'Hi! My name is Professor Bot. I will hold a conversation with you. '
'Send /cancel to stop talking to me.\n\n'
'Are you a boy or a girl?',
reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
How can I use user's choice to return data based on it? The code above just print the choice to the chat.

I can see that you're referring to the example conversationbot.py from python-telegram-bot's GitHub.
When user selects a choice from ReplyKeyboard, it'll be sent as a message to bot. So you've to pickup that message. For this you've to use ConversationHandler where you can define stages/states for a conversation.
Look at the same example you're referring to. The entry point to ConversationHandler here is /start command. Then the bot replies with the keyboard. The next stage here is GENDER (you can see return GENDER in start function). Here MessageHandler is used with regex and the callback function is gender(). When user selects from the choice, the bot matches the reply with ^(Boy|Girl|Other)$ and this calls gender() function if it's true. Similarly the further states in ConversationHandler will proceed.
Finally, ConversationHandler will end when it reaches the last state or when /cancel (fallback) is sent.

Related

Discord.py Automatically assign roles to users having specific keywords in a message or image

I'm extremely new to discord.py and I was wondering if there is an existing bot or if I could make a bot that can assign a role to a user based on keywords in a text and/or image to get a specific role through verification.
Is this possible and if so can I get some help with it?
I have tried looking for bots that may have this feature but I have been unsuccessful, I am somewhat willing to make a bot as well but I'm a beginner coder but I am willing to figure things out!
It is possible. But I'm unsure when you want this to be triggered;
checking every possible message?
messages in a certain channel?
some kind of response to a slash command/modal dialog?
etc
Let's role with "checking every possible message" for a basic example.
Let's say we have a server about people's favourite fruit and we want to assign users a role based on their favourite fruit as this gives them access to the private channel about that fruit.
import discord
# we have already created roles in our server for the fruits
# so we'll put the IDs here for ease of use
ROLES = {
"banana": 112233445566,
"apple": 123456123456,
"orange": 665544332211
}
# requires elevated privileges - but let's say we've ticked those
intents = discord.Intents.all()
client = discord.Bot(intents=intents)
# register a client event to trigger some code every time a message is sent
#client.event
async def on_message(message: discord.Message):
message_content = message.content.lower()
if "bananas are good" in message_content:
role = ROLES["banana"]
elif "apples are good" in message_content:
role = ROLES["apple"]
elif "oranges are good" in message_content:
role = ROLES["orange"]
else:
# make sure we have a case for when nothing we want is found
role = None
if not role:
# exit out if we don't have a role to assign
return
guild_roles = await message.guild.fetch_roles()
our_role = [gr for gr in guild_roles if gr.id == role]
await message.author.add_roles(our_role)
client.run(OUR_TOKEN)
This is a very basic example but it possible. Ideally, we'd have a better way of checking message content - either via regex or other form of analysis. Additionally, we'd probably only check messages in a certain channel (or another method entirely, like a modal dialogue or a slash command). Also, what we're not doing above, is removing the user from the other roles (provided you would want that). So it would be possible for a user to have the "banana", "oranges", and "apples" roles all at once.
Hopefully that gives some ideas of where to start. Images would be similar - triggering some kind of function when you want it, downloading the image and running whatever analysis you want on the image.
Disclaimer: I wrote this with the pycord library in mind and didn't see the discord.py tag - should mostly be similar though but might not be.

Telegram bot doesn't answer after CommandHandler starts

So, I'm kinda new creating bots with Python. I'm using PyPI(PY Telegram Bot). I've been learning a lot during these days and it even started working. While using MessageHandler I could pretty much send a message and the bot would return me a text or a picture.
But now I want something different. I want to start creating a game for Telegram, still to learn more on how to use the library.
The thing is: eveytime I want the bot to answer me, it doesn't work. Basically when entering the rockpaperscissors function, I want it to show a text asking for an option, then, whatever this answer is leads me to an answer by the bot. But whenever I answer, the bot never answers back.
Just an example of what happens:
And here is the source code. I excluded the superfluous sections so it wouldn't be that messy. Any help is appreciated :)
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, ConversationHandler, CallbackContext
import random
def rockpaperscissors(update, context):
update.message.reply_text('Rock, paper, scissors. Return an option')
msgUsr = str(update.message.text)
if msgUser == "rock":
update.message.reply_text("You chose 'rock'")
def main():
token ='(token)'
updater = Updater(token=token, use_context=True)
dispatcher.add_handler(CommandHandler('rps',rockpaperscissors))
updater.start_polling()
updater.idle()
if __name__ == "__main__":
main()
Your bot is expecting a command /rps, and responding correctly. However, when you send a plain message (rather than a command), the bot just doesn't know what to do. Note that the function rockpaperscissors is only called when the user sends a message starting with /rps or /rps#yourbot , but it never equals to "rock". So your if will never be executed.
You must add a MessageHandler and associate another function to, well, handle the message.

discord py - message.mentions "else" makes nothing

I want to get the user that was mentioned in a message and send him a private message. That's working without problems, but now I want to add a message for the case, that the mentioned member is not on the same server.
I searched a lot and try now for over 3 hours to find a solution.
Showcase of the problem: https://youtu.be/PYZMVXYtxpE
Heres my code:
#bot.event
async def on_message(message):
if len(message.mentions) == 1:
membe1 = message.mentions[0].id
membe2 = bot.get_user(membe1)
guild = bot.get_guild(message.author.guild.id)
if guild.get_member(membe1) is not None:
await membe2.send(content=f"you was mentioned in the server chat")
else:
embed2 = discord.Embed(title=f"» :warning: | PING not possible", description=f"not possible")
await message.channel.send(content=f"{message.author.mention}", embed=embed)
await message.delete()
return
The first part is working without problems, but at the "else" part, does the bot nothing. He still posts the message with the "invalid" ping in the chat and just ignores it. What can I do to fix that?
There is an error of design in what you are trying to do.
In Discord, you are not able to mention a user if he is not on that same server, so what you are checking will never work at all, currently your code is pretty much checking if the mentioned user exists, which will always happen unless he leaves the guild at the same time the command is executed.
Say for example, to make your command work you want to mention the user user123, who is in your server, you do the following:
#user123 blablabla
And that works because Discord internal cache can find user123 in your server and it is mentioned, which means that clicking on "#user123" will show us a target with his avatar, his roles or whatsoever.
But if you try to do the same for an invalid user, let's say notuser321:
#notuser321 blablabla
This is not a mention, take for example that you know who notuser321 is but he is in the same server as the bot is. Discord cannot retrieve this user from the cache and it is not considered a mention, just a single string, so not a single part of your code will be triggered, because len(message.mentions) will be 0.
Something that you could try would be using regular expressions to find an attempt to tag within message.content. An example would be something like this:
import re
message = "I love #user1 and #user2"
mention_attempt = re.findall(r'[#]\S*', message) # ['#user1', '#user2']

Python, discord.py - search wikipedia with user input

I'm trying to make a Discord bot with Discordpy and WikipediaApi. The bot is supposed to print Wikipedia summary after entering an appropriate sentence: "What is...?" or "Who is...?". So far, it's working well, but the Wikipedia page is defined in the code. I want take a page title as keyword from user, for example, he might ask "What is Microsoft?" or "Who is Elon Musk?" and receive a reply (if a page exists in Wikipedia, of course). I know I should use client.wait_for(), but I feel confused with that, as the input will be a part of longer sentence.
import discord
import wikipediaapi
#client.event
async def on_message(message):
if not (message.author == client.user):
if (message.mention_everyone == False):
if (client.user.mentioned_in(message) or isinstance(message.channel, discord.abc.PrivateChannel)):
async with message.channel.typing():
if message.content.startswith('What is') or message.content.startswith('Who is'):
wiki_wiki = wikipediaapi.Wikipedia('pl')
page_py = wiki_wiki.page('Elon Musk') <----- HERE
await message.channel.send("Page - Summary: %s" % page_py.summary)
client.run('token')
Seeing as you're trying to parse it out of every message, you could try just splitting the "command" (What is/Who is) and take the remainder as the query.
if message.content.startswith('What is') or message.content.startswith('Who is'):
args = message.content.split(" ") # Split the message based on spaces
if len(args) > 2: # Checks if a query was passed, avoids a potential IndexError
query = " ".join(args[2:]) # Cut out the "What is" part, and join the rest back into a single string with spaces
wiki_wiki = wikipediaapi.Wikipedia('pl')
page_py = wiki_wiki.page(query)
I do strongly recommend using the built-in Commands module though, and just making a "Wiki" command. This way, your code would look as follows:
#client.command()
async def wiki(ctx, *query):
if query: # I'm not sure what the wikipedia api does if you give it an empty string, so this if-statement makes sure something was passed
query = " ".join(query) # The rest of the args were passed as a list, so join them back into a string with spaces
wiki_wiki = wikipediaapi.Wikipedia('pl')
page_py = wiki_wiki.page(query)
And you can call it in Discord by simply doing [prefix]wiki elon musk. In your case, you check if the bot was mentioned to parse commands which can also be handled with prefixes, so you wouldn't lose any functionality on that end (and can add more prefixes if you so wish).

How can make conversation between bot and user with telepot

I want to create the bot with telepot that ask the users frequent questions.
For example first ask 'whats your name.?' then the user reply 'user-name',then ask how old are you? and the user reply his age and ...
I had written a code for this chat between user and bot,but sometimes I am getting error. Please guide me how can I make this bot with telepot.?
I want to make conversation between bot and users with telepot
I am no longer maintaining this library. Thanks for considering
telepot.
- the maintainer, nickoala
What you're looking for is DelegatorBot.
Consider this tutorial.
Consider this scenario. A bot wants to have an intelligent
conversation with a lot of users, and if we could only use a single
line of execution to handle messages (like what we have done so far),
we would have to maintain some state variables about each conversation
outside the message-handling function(s). On receiving each message,
we first have to check whether the user already has a conversation
started, and if so, what we have been talking about. To avoid such
mundaneness, we need a structured way to maintain “threads” of
conversation.
DelegatorBot provides you with one instance of your bot for every user, so you don't have to think about what happens when multiple users talk to it. (If it helps you, feel free to have a look at how I am using it.)
The tutorial's example is a simple counter of how many messages the user has sent:
import sys
import time
import telepot
from telepot.loop import MessageLoop
from telepot.delegate import pave_event_space, per_chat_id, create_open
class MessageCounter(telepot.helper.ChatHandler):
def __init__(self, *args, **kwargs):
super(MessageCounter, self).__init__(*args, **kwargs)
self._count = 0
def on_chat_message(self, msg):
self._count += 1
self.sender.sendMessage(self._count)
TOKEN = sys.argv[1] # get token from command-line
bot = telepot.DelegatorBot(TOKEN, [
pave_event_space()(
per_chat_id(), create_open, MessageCounter, timeout=10),
])
MessageLoop(bot).run_as_thread()
while 1:
time.sleep(10)
This code creates an instance of MessageCounter for every individual user.
I had written a code for this chat between user and bot,but sometimes I am getting error.
If your question was rather about the errors you're getting than about how to keep a conversation with state, you need to provide more information about what errors you're getting, and when those appear.

Categories