How to solve updater.dispatcher.add_hanlder in python Telegram bot API - python

I'm writing a python telegram bot and I want to work with inline keyboard bottom.
I write this code below:
from telegram import *
from telegram.ext import *
mbti_message = 'This is a test massage that should sent in MBTI part'
def startx(bot, update):
keyboard = [[InlineKeyboardButton("Option 1", callback_data='1'),
InlineKeyboardButton("Option 2", callback_data='2')],
[InlineKeyboardButton("Option 3", callback_data='3')]]
reply_markup = InlineKeyboardMarkup(keyboard)
chat_id = update.message.chat_id
bot.sendMessage(chat_id, "Message Sent From Function STARTX", reply_markup=reply_markup)
def buttomx(bot, update):
query = update.callback_query
bot.edit_message_text(text="Selected option: %s" % query.data,
chat_id=query.message.chat_id,
message_id=query.message.message_id)
def start (bot,update):
keyboard_list = [[InlineKeyboardButton("ABOUT US", callback_data='1')],
[InlineKeyboardButton("MBTI Test Start", callback_data='2')]]
reply_markup = InlineKeyboardMarkup(keyboard_list)
chat_id = update.message.chat_id
start_message_sent = "Welcome To My Bot Please Chose Your Options"
bot.sendMessage(chat_id,start_message_sent, reply_markup=reply_markup)
bot.sendMessage(chat_id,start_message_sent_global,reply_markup=reply_markup)
def bottom(bot, update):
counter = 0
query = update.callback_query
chat_id = query.message.chat_id
selected_option = int(query.data)
if selected_option==1 :
bot.sendMessage(chat_id,"You Chose About Us Section Thanks For Choosing Us")
elif selected_option==2:
bot.sendMessage(chat_id,"You Are Ready To Start Test ...")
command = 'mbti'
updater.dispatcher.add_handler(CommandHandler(command=command, callback=startx))
updater.dispatcher.add_handler(CallbackQueryHandler(buttomx))
updater.start_polling()
When user press bottom MBTI set command to mbti and pass it to command handler and when command handler get mbti command start to run starx function.
but when i use this code below in the if condition it send it before checking if condition
updater.dispatcher.add_handler (CommandHandler (command = command , startx)
What should i do in this condition?

Use a ConversationHandler for deep interactive menu. other way you can storing userState, and call function with State.
for more information see docs example it also supported user_data and RegExp for powerful handling message from users.
don't forget: data stores in memory and you may have lost or incorrect in some case. good think cleaned user_data in entry point,
each function can have many returns to other entry and with other side - each of entry has many different function in different matching case.

Related

NameError: name 'startCommand' is not defined - PYTHON

from coinbase.wallet.client import Client
from telegram import ParseMode
from telegram.ext import CommandHandler, Defaults, Updater
COINBASE_KEY = 'xxxxxxxxxxxx'
COINBASE_SECRET = 'xxxxxxxxxxxx'
TELEGRAM_TOKEN = 'xxxxxxxxxxxx'
coinbase_client = Client(COINBASE_KEY, COINBASE_SECRET)
#if __name__ == '__main__':
updater = Updater(token=TELEGRAM_TOKEN, defaults=Defaults(parse_mode=ParseMode.HTML))
dispatcher = updater.dispatcher
dispatcher.add_handler('start', startCommand) # Accessed via /start
dispatcher.add_handler('alert', priceAlert) # Accessed via /alert
updater.start_polling() # Start the bot
updater.idle() # Wait for the script to be stopped, this will stop the bot
def startCommand(update, context):
context.bot.send_message(chat_id=update.effective_chat.id, text='Hello there!')
def priceAlert(update, context):
if len(context.args) > 2:
crypto = context.args[0].upper()
sign = context.args[1]
price = context.args[2]
context.job_queue.run_repeating(priceAlertCallback, interval=15, first=15, context=[crypto, sign, price, update.message.chat_id])
response = f"⏳ I will send you a message when the price of {crypto} reaches £{price}, \n"
response += f"the current price of {crypto} is £{coinbase_client.get_spot_price(currency_pair=crypto + '-GBP')['amount']}"
else:
response = '⚠️ Please provide a crypto code and a price value: \n<i>/price_alert {crypto code} {> / <} {price}</i>'
context.bot.send_message(chat_id=update.effective_chat.id, text=response)
def priceAlertCallback(context):
crypto = context.job.context[0]
sign = context.job.context[1]
price = context.job.context[2]
chat_id = context.job.context[3]
send = False
spot_price = coinbase_client.get_spot_price(currency_pair=crypto + '-GBP')['amount']
if sign == '<':
if float(price) >= float(spot_price):
send = True
else:
if float(price) <= float(spot_price):
send = True
if send:
response = f'👋 {crypto} has surpassed £{price} and has just reached <b>£{spot_price}</b>!'
context.job.schedule_removal()
context.bot.send_message(chat_id=chat_id, text=response)
enter image description here
I get this error of the code above, also I have already tried changing the position of the def but, it also shows error, How to solve this?
It is the code for telegram bot and also this keeps on showing me NameError, I have already added python3 and pip, but still not solved
Python reads files top to bottom. So when you call dispatcher.add_handler('start', startCommand), the function startCommand is not yet known. Move the part
updater = Updater(token=TELEGRAM_TOKEN, defaults=Defaults(parse_mode=ParseMode.HTML))
dispatcher = updater.dispatcher
dispatcher.add_handler('start', startCommand) # Accessed via /start
dispatcher.add_handler('alert', priceAlert) # Accessed via /alert
updater.start_polling() # Start the bot
updater.idle() # Wait for the script to be stopped, this will stop the bot
below the callback definitions.
Apart from that, add_handler needs a Handler as argument, in your case something like add_handler(CommandHanlder('start', startCommand). Please see PTB tutorial as well as the examples.
Disclaimer: I'm the current maintainer of the python-telegram-bot library.
Try
dispatcher.add_handler('start', startCommand()) # Accessed via /start
dispatcher.add_handler('alert', priceAlert()) # Accessed via /alert
You will also need to add the two arguments required by both functions.
dispatcher.add_handler('start', startCommand(update, context))
dispatcher.add_handler('alert', startCommand(update, context))
I'm not exactly sure what data the two functions take in but I'm going to guess that it is whatever the bot is returning.

Telegram bot not responding when mentionned

I am developing a little bot in python with the library python-telegram-bot, and I am stucked with a little problem :
I have an InlineKeyboardButton with the parameter switch_inline_query_current_chat, so when the user click on it, a command is automatically written in its chat.
But, that command is preceded with the mention of the bot (with an #).
The problem is my bot isn't answering in that case, and I have no idea why..
Is there a solution to make the button do not preced the command with the mention of the bot ?
From #BotFather the groups are allowed and the privacy group is turned off.
Thank you a lot
Edit : This is the code for the CommandHandler :
def getEntry(update, context):
if not (is_allowed_user(update.message.from_user.username, 'getEntry')):
context.bot.send_message(chat_id=update.effective_chat.id,
text='Who the hell are you #' + update.message.from_user.username + ' ?')
return
search = ' '.join(context.args)
infos, err = get_infos_people(search)
if err is not None:
context.bot.send_message(chat_id=update.effective_chat.id, text=err)
return
context.bot.send_message(chat_id=update.effective_chat.id, text=beautify_infos(infos),
parse_mode=ParseMode.MARKDOWN, reply_markup=getMainKeyboard(infos))
get_handler = CommandHandler('get', getEntry, filters=~Filters.update.edited_message)
And this is the code for the buttons :
def getMainKeyboard(infos):
keyboard = [InlineKeyboardButton("modify",
switch_inline_query_current_chat="/get " + infos[0] + "<write here>")]]
return InlineKeyboardMarkup(keyboard)
Note: I'm no python-telegram-bot expert, but the issue/fix should be non-lib related
Your commandHandler() is defined as so:
get_handler = CommandHandler('get', getEntry, filters=~Filters.update.edited_message)
This links the /get command to the getEntry handler.
Issue
Since the command is only fired at /get, you'll need to add a second command with the name of the bot so it will register that command as-well;
get_handler = CommandHandler([ 'get', 'get#myBot' ], getEntry, filters=~Filters.update.edited_message)
The first argument (command) accepts both a str or a list as the docs shows
Had the same issue in some other library, don't think there is a 'cleaner' way of handeling this.

Best practice for a back button implementation in telegram conversation bot

I'm trying to create a telegram conversation bot using python-telegram-bot package and I wondered what is the best practice for implementing a "back to main menu" button for each state in the conversation.
For some reason, I feels like i'm doing it the wrong way. The back to main menu button actually does nothing except to drawing the main menu buttons which should be immediate, but still it's usually takes 0.5-3 seconds and sometimes even longer (Only one user at a time talking to the bot).
I'm using CallbackQueryHandler(back_to_main_menu, pattern='^main_menu$') for each state basically which I'm quite sure it's not the right way to do it although I couldn't find any other better solution so far.
Notice: the example below is just a little example of how I use the CallbackQueryHandler. My state machine got 13 states, in 10 of them I got a back to main menu button.
A short example of what I need:
import os
from telegram.ext import Updater, ConversationHandler, CommandHandler, CallbackQueryHandler
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, ReplyKeyboardRemove
FIRST, SECOND, MAIN_MENU = range(3)
def get_main_menu():
return [[InlineKeyboardButton("First", callback_data='first')],
[InlineKeyboardButton("Second", callback_data='second')]]
def add_main_menu_button(bot, update, message, menu):
query = update.callback_query
menu.append([InlineKeyboardButton("Back to main menu", callback_data="main_menu")])
reply_markup = InlineKeyboardMarkup(menu)
bot.edit_message_text(message, chat_id=query.message.chat_id, message_id=query.message.message_id,
reply_markup=reply_markup)
def back_to_main_menu(bot, update):
query = update.callback_query
reply_markup = InlineKeyboardMarkup(get_main_menu())
bot.edit_message_text("Example example 2", chat_id=query.message.chat_id, message_id=query.message.message_id, reply_markup=reply_markup)
return MAIN_MENU
def second(bot, update):
add_main_menu_button(bot, update, "E e", list())
def first(bot, update):
add_main_menu_button(bot, update, "T t", list())
def start(bot, update):
reply_markup = InlineKeyboardMarkup(get_main_menu())
update.message.reply_text("Example example 1", reply_markup=reply_markup)
return MAIN_MENU
def cancel(bot, update):
update.message.reply_text('Bye! I hope we can talk again some day.', reply_markup=ReplyKeyboardRemove())
return ConversationHandler.END
def main():
updater = Updater(os.environ["BOT_TOKEN"])
conversation_handler = ConversationHandler(entry_points=[CommandHandler('start', start)],
states={FIRST: [CallbackQueryHandler(back_to_main_menu, pattern='^main_menu$')],
SECOND: [CallbackQueryHandler(back_to_main_menu, pattern='^main_menu$')],
MAIN_MENU: [CallbackQueryHandler(first, pattern='first'),
CallbackQueryHandler(second)]},
fallbacks=[CommandHandler('cancel', cancel)],
allow_reentry=True
)
updater.dispatcher.add_handler(conversation_handler)
updater.start_polling()
updater.idle()
In addition, when I use multiple CallbackQueryHandler in a conversation I get the following warning:
WARNING:root:If 'per_message=False', 'CallbackQueryHandler' will not be tracked for every message
which makes me think I'm doing something wrong.
Thanks.
For each conversation you only need to specify one CallbackQueryHandler as a fallback. For example:
START = range(1)
start_conv_handler = ConversationHandler(entry_points=[CommandHandler('start', start)],
states={
START: [CommandHandler('start', start)]
},
fallbacks= CallbackQueryHandler(main_callback_handler)]
)
And then within that single CallbackQueryHandler you can plan all the neceesary actions you want your buttons to perform. Since you can add whatever information you need to the query that the handler receive, you can play with more complicated scenarios by putting return CallbackQueryHandler at the end of each function that describes a conversation step (start in my example).
So it would look like:
def start(bot, update):
... your code here
return CallbackQueryHandler

Callbackquery handler issue in python telegram bot

In my code I'm facing an issue with callbackquery handler, when I'm hit /start command Next button appear and when I'm hitting on that button it gives me reply as hi, till this output is correct. Then when I'm hitting another command /help then help button appears, when I hit that help button then it gives me same reply for next button is hi.
Conclusion: Is there is way to kill old callbackquery handler. I found way is return Conversationhandler.END from callbackquery handler function but it limits my functionality had googled for it but no found expected output.
Here is my code:
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, ConversationHandler
TELEGRAM_HTTP_API_TOKEN = 'token'
FIRST, SECOND, HELP = range(3)
def start(bot, update):
keyboard = [
[InlineKeyboardButton(u"Next", callback_data=str(FIRST))]
]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text(
u"Start handler, Press next",
reply_markup=reply_markup
)
return FIRST
def first(bot, update):
query = update.callback_query
#reply_markup = InlineKeyboardMarkup(keyboard)
bot.send_message(chat_id=query.message.chat_id,
text='hi')
def help(bot,update):
keyboard = [
[InlineKeyboardButton(u"HELP", callback_data=str(HELP))]
]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text(
u"Help handler, Press button",
reply_markup=reply_markup
)
return HELP
def myhelp(bot,update):
query = update.callback_query
bot.send_message(chat_id=query.message.chat_id,
text='help')
updater = Updater(TELEGRAM_HTTP_API_TOKEN)
conv_handler = ConversationHandler(
entry_points=[CommandHandler('start', start)],
states={
FIRST: [CallbackQueryHandler(first)]
},
fallbacks=[CommandHandler('start', start)]
)
conv_handler1=ConversationHandler(
entry_points=[CommandHandler('help',help)],
states={
HELP: [CallbackQueryHandler(myhelp)]
},
fallbacks=[CommandHandler('help',help)]
)
updater.dispatcher.add_handler(conv_handler)
updater.dispatcher.add_handler(conv_handler1)
updater.start_polling()
updater.idle()
This is code screenshot output for more detail
Any kind of help is welcome.
You need to make your bot persistent (so state don't get lost), add error handler (to know if something failed) and fallback route (if there is not route matching).
In that case you'll know what's going wrong and where.

How to use ChosenInlineResultHandler in Python Telegram Bot

I try use python-telegram-bot
I do not understand how to handle InlineKeyboardButton correctly.
def start(bot, update):
currencies = [currency for currency in API().get_currencies()]
keyboard = [[InlineKeyboardButton("{}".format(c), callback_data='{}'.format(c))] for c in currencies]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text('Select the currency you want to exchange:', reply_markup=reply_markup)
updater.dispatcher.add_handler(CommandHandler('start', start))
Now, I need to process the selection by passing it to another function with the help of ChosenInlineResultHandler, but I do not understand how to do this.
You are using Inline Buttons and the query coming back is simply CallbackQuery but not InlineQuery, yes the names are a bit confusing by the Telegram Bot API.
You can use telegram.ext.CallbackQueryHandler to catch the queries upon buttons pressed.
def button_callback(bot, update):
# data is the callback_data where you declared in the buttons
query = update.callback_query.data
if query == "something":
# do something here
updater.dispatcher.add_handler(CallbackQueryHandler(button_callback))
This is a minimal example of how to catch the buttons' data. You can check here for a complete example.

Categories