def final_or_make_changes_to_bill(bot, update):
user_choice_make_changes = update.message.text
if user_choice_make_changes == "Yes":
reply_keyboard = [["Add","Delete"]]
message = "Do you want to add or delete?"
bot.send_message(chat_id=update.message.chat_id, text=message, reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
return ADD_OR_DELETE
return STOP
For some reason the state STOP in my code is never reached. I tried other states and none of them are reached. I tried replacing the return statement in the if condition to STOP to check if there was a problem with the state. But it seems to work fine and the state is reached through the if statement block.
This is the function for the STOP state.
def stop(bot, update):
print("ht")
bot.send_message(chat_id=update.message.chat_id,text="dsfdsfsadf")
return ConversationHandler.END
Here's the entire code.
import os
import logging
from DBHelper import DBHelper
from telegram.ext import Updater,CommandHandler,MessageHandler,ConversationHandler,Filters
from telegram import ReplyKeyboardMarkup
from random import randint
TOKEN = ""
db = DBHelper()
ADD_ITEMS, FINAL_OR_MAKE_CHANGES, ADD_OR_DELETE, DELETE, STOP = range(5)
bill_items = []
ID = None
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
def start(bot, update):
message = "Welcome to the Bill Splitter Bot. An easy way to split bills among friends. The following are a list of"
+ "commands you can use."
bot.send_message(chat_id=update.message.chat_id, text=message)
message = ""
message += "/help - To get a list of commands\n"
message += "/create - To create a new bill\n"
message += "/add - To add items spent on for a particular bill"
message += "/get - To get the amount owed"
def create(bot, update):
global ID
message = "Hey! Looks like you're trying to create a new bill! One moment, while I create a new ID for you!"
bot.send_message(chat_id=update.message.chat_id, text=message)
id_for_bill = randint(1000,9999)
# Check if bill id does not exist in database
message = "Here's the ID for your bill: " + str(id_for_bill)
ID = id_for_bill
print(ID)
bot.send_message(chat_id=update.message.chat_id, text=message)
message = "Can you enter the items followed by the price for the bill? A simple format would look as follows. Type "
message += "Done when you're done adding items to the bill\n"
bot.send_message(chat_id=update.message.chat_id, text=message)
message = " <pre>Pizza - 150\n"
message += "Pasta - 150\n"
message += "Garlic Bread - 230</pre> "
reply_keyboard = [["Done"]]
bot.send_message(chat_id=update.message.chat_id, text=message,parse_mode="html")
return ADD_ITEMS
def add_items_to_bill(bot, update):
user_input_bill_items = update.message.text
# Use regex
if user_input_bill_items == "Done":
message = "Looks like you're done! Here's your bill for re-confirmation: "
item_count=0
for item in bill_items:
item_count += 1
message += "<pre>" + str(item_count) + ". " + str(item) + "\n</pre>"
bot.send_message(chat_id=update.message.chat_id, text=message, parse_mode="html")
message = "Do you want to make any changes to the bill?"
reply_keyboard = [["Yes","No"]]
bot.send_message(chat_id=update.message.chat_id, text=message, reply_markup=ReplyKeyboardMarkup(reply_keyboard,one_time_keyboard=True))
return FINAL_OR_MAKE_CHANGES
bill_items.append(user_input_bill_items)
return ADD_ITEMS
def final_or_make_changes_to_bill(bot, update):
user_choice_make_changes = update.message.text
if user_choice_make_changes == "Yes":
reply_keyboard = [["Add","Delete"]]
message = "Do you want to add or delete?"
bot.send_message(chat_id=update.message.chat_id, text=message, reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
return ADD_OR_DELETE
return STOP
def add_or_delete(bot, update):
user_choice_add_or_delete = update.message.text
if user_choice_add_or_delete == "Add":
message = "Enter items you want to add."
bot.send_message(chat_id=update.message.chat_id, text=message)
return ADD_ITEMS
message = "Enter the list number of the item you want to delete. Type Done when you're done."
bot.send_message(chat_id= update.message.chat_id, text=message)
return DELETE
def delete_item_from_bill(bot, update):
number_to_delete = update.message.text
print(number_to_delete)
# SQL command to delete from table
print("to be filled")
return STOP
def stop(bot, update):
print("ht")
bot.send_message(chat_id=update.message.chat_id,text="dsfdsfsadf")
return ConversationHandler.END
# def done(bot, update):
# global ID
# bot.send_message(chat_id=update.message.chat_id, text="done")
# print("done")
# message = "Great! Share this ID with the other participants of the bill: "
# bot.send_message(chat_id=update.message.chat_id, text=message)
# return ConversationHandler.END
def cancel(bot,update):
print("cancel")
return ConversationHandler.END
def add_bought_items(bot, update):
message = "Add the list of items conforming to this example. Bill followed by ID\nEg: 4632 1,2,3"
bot.send_message(chat_id=update.message.chat_id, text=message)
def error(bot, update, error):
"""Log Errors caused by Updates."""
logger.warning('Update "%s" caused error "%s"', update, update.error)
def main():
updater = Updater(TOKEN)
db.setup()
PORT = int(os.environ.get('PORT','8443'))
dp = updater.dispatcher
dp.add_handler(CommandHandler("help",start))
create_conversation_handler = ConversationHandler(
entry_points = [CommandHandler('create',create)],
states = {
# GET_BILL_DETAILS: [MessageHandler(Filters.text,get_bill_details)],
ADD_ITEMS: [MessageHandler(Filters.text, add_items_to_bill)],
FINAL_OR_MAKE_CHANGES: [MessageHandler(Filters.text, final_or_make_changes_to_bill)],
ADD_OR_DELETE: [MessageHandler(Filters.text, add_or_delete)],
DELETE: [MessageHandler(Filters.text, delete_item_from_bill)],
STOP: [MessageHandler(Filters.text, stop)]
},
fallbacks = [CommandHandler('cancel',cancel)]
)
dp.add_handler(create_conversation_handler)
dp.add_error_handler(error)
dp.add_handler(CommandHandler("add",add_bought_items))
# dp.add_handler(CommandHandler("add",add))
updater.start_polling()
if __name__ == "__main__":
main()
Related
Can't pass value from one function to another
i am using aiogram and FSM to pass
data['start_name2'] = message.text
from one function to another
who can tell me what is my mistake?
This function creates a state in the "Start" state group with the name "start_name2".
class Start(StatesGroup):
start_name2= State() #NAME
This is a telegram bot function that handles a callback query with the data 'NAME'. When triggered, the bot will send a message to the chat asking the user to write their name. The input name is then processed and sent to a GET API request, and the received information is then parsed and displayed in a limited form as messages in the chat. If the input name is invalid, the bot will send a message saying so. The function also adds a message with a link to a website at the end.
#dp.callback_query_handler(lambda c: c.data == 'NAME')
async def process_callback_button2(callback_query: types.CallbackQuery, state: FSMContext):
await bot.answer_callback_query(callback_query.id)
await bot.send_message(callback_query.message.chat.id, text='Please write name. Example : Alex Bortin',reply_markup=kb.inline_kb4)
await Start.start_name2.set()
try:
await callback_query.message.delete()
except Exception as exception:
print("someone click button")
#dp.message_handler(state=Start.start_name2)
async def namee(message: types.Message, state: FSMContext):
# Check if the input is valid
if not is_valid_input2(message.text):
await bot.send_message(message.from_user.id, "Invalid input. Please enter a valid name.")
return
name = message.text
async with state.proxy() as data:
data['start_name2'] = message.text
try:
msg = await bot.send_message(message.from_user.id, parse_mode="HTML" ,text=f'Entered name: <b>{name}</b>\n\nSearching...')#---
await bot.send_chat_action(message.from_user.id , ChatActions.TYPING)#---
for i in range(3):#---
random_emojis = random.sample(emojis, 4)#---
random_emojis_string = " ".join(random_emojis)#---
await asyncio.sleep(0.4)
await msg.edit_text(parse_mode="HTML" ,text=f'Entered name: <b>{name}</b>')#---
URL = "API"
URL2 = "JUST URL"
# GET
response_text = await fetch(URL)
soup = BeautifulSoup(response_text, "html.parser")
nameD = (soup.prettify())
print(nameD)
await msg.edit_text(parse_mode="HTML" ,text=f'Entered name: <b>{name}</b>') #---
pattern_value = r'"value"\s*:\s*(\d+),'
obj = json.loads(nameD)
data2 = ""
match_address = re.search(pattern_value, nameD)
if match_address:
value = match_address.group(1)
data2 += f'Data found: <b>{value}</b>\n'
else:
data2 += 'Data found: <b>0</b>\n'
count = 0
for index in obj['hits']['hits']:
if count >= 10:
break
count += 1
db_name = index['_index']
strings = set()
for a, b in index['_source'].items():
strings.add(f"<b>{a}</b> : {b}")
string = "\n".join(list(strings))
await bot.send_message(message.from_user.id, text=f"<b>data base name</b> : {db_name}\n{string}", parse_mode="HTML")
await message.reply('Page 0', reply_markup=get_keyboard(0))
text2 = hlink('website', URL2)
await bot.send_message(message.from_user.id, parse_mode="HTML" , text=f'\nThe report can be viewed on our WEB {text2}')
name = 0
except Exception as exception:
name = 0
text2 = hlink('website', URL2)
await bot.send_message(message.from_user.id, parse_mode="HTML" , text=f'\nThe report can be viewed on our WEB {text2}')
await state.finish()
This function is a callback handler for a callback query in the Telegram Bot API. It handles a vote "up" action, increasing the vote count by 1. It logs the callback data and retrieves a value from the state proxy (stored data). It also prints the retrieved value.
#dp.callback_query_handler(vote_cb.filter(action='up'))
async def vote_up_cb_handler(query: types.CallbackQuery, callback_data: dict, state: FSMContext):
logging.info(callback_data)
amount = int(callback_data['amount'])
amount += 1
async with state.proxy() as data:
start_name2 = data.get('start_name2')
print(start_name2)
#Here I try print start_name2
The maximum that I have achieved is that my last function outputs
"None"
I'm writing a simple telegram bot to accept a word as input and return a message inlcuding a Youtube link based on that word.
The bot should look for the word after the '/search' command is invoked but here it's using every word sent to the chat.
Please can you help me to fix it?
import logging
from telegram import Update
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters
import random
import re
import urllib.request
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO
)
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id, text="I'm a bot, please talk to me!")
async def search(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Search a single word"""
await update.message.reply_text("Type a single word")
return short_reply
async def short_reply(update: Update, context: ContextTypes.DEFAULT_TYPE):
word = update.message.text
html = urllib.request.urlopen("https://www.youtube.com/results?search_query=" + word)
video_ids = re.findall(r"watch\?v=(\S{11})", html.read().decode())
await context.bot.send_message(chat_id=update.effective_chat.id, text=f"https://www.youtube.com/watch?v=" + video_ids[random.randrange(1,20)])
return start
if __name__ == '__main__':
application = ApplicationBuilder().token('TOKEN').build()
start_handler = CommandHandler('start', start)
application.add_handler(start_handler)
search_handler = CommandHandler('search', search)
application.add_handler(search_handler)
short_reply_handler = MessageHandler(filters.TEXT, short_reply)
application.add_handler(short_reply_handler)
application.run_polling()
I even tried to add other functions as a sort of 'keywords menu' but i encountered the same problem: the bot will immediately reply with "I didn't undestand your command" because it's always reading the message sent right before the function invocation (the function/command invocation itself).
async def edit_tags(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id, text="ADD/REMOVE?")
msg = update.message.text
if msg == 'ADD':
await context.bot.send_message(chat_id=update.effective_chat.id, text="Write a keyword")
keyword = update.message.text
print(keyword)
elif msg == 'REMOVE':
await context.bot.send_message(chat_id=update.effective_chat.id, text="Remove")
pass
else:
await context.bot.send_message(chat_id=update.effective_chat.id, text="I didn't undestand your command")
tags_handler = MessageHandler(filters.TEXT, edit_tags)
application.add_handler(tags_handler)
I'm using python-telegram-bot
def delete(update: Update, context: CallbackContext) -> None:
"""delete account from database"""
num = random.randrange(111111,999999)
update.message.reply_text("Something to write here\n\n****" + str(num) + "****")
time.sleep(10)
if int(update.message.text) == num: #here update.message.text == '/cancel' and not the message user
flag = delete_db(update.effective_user.id)
if flag:
update.message.reply_text('OK')
else:
update.message.reply_text('Something goes wrong or time is out')
How can i force the update of the message? I think is there the problem...
I resolved it, on the advice of the telegram community, with a Conversational Handler with two function, one to start the operation and the second to confirm.
In def main:
dispatcher.add_handler(
ConversationHandler(
entry_points = [MessageHandler(Filters.regex('^Cancel$'), delete)],
states = {
DELETE: [MessageHandler(Filters.text, random_number)],
},
fallbacks = [None], # here you can enter an /end function to break the process
conversation_timeout = 30,
),
)
Start function 'delete':
def delete(update: Update, context: CallbackContext):
update.message.reply_text('some message')
CallbackContext.chat_data = random.randrange(111111,999999)
update.message.reply_text("some other message\n*" + str(CallbackContext.chat_data) + "*")
return DELETE
The function to keep the string message and compare to random number generated:
def random_number(update: Update, context: CallbackContext):
try:
user_action = int(update.message.text)
if user_action == CallbackContext.chat_data:
#flag = delete_db(update.effective_user.id) # function to delete from database
if flag:
update.message.reply_text('Okay done')
else:
update.message.reply_text('Wrong number')
except:
update.message.reply_text('failed')
return ConversationHandler.END
I am buidling a simple game with pytelegrambotapi.
According to the rules, the user is sent a definition and four buttons with words as text, of which one is correct.
The user then should press the right button. Another routine then compares the user's answer to the right answer.
How do I retrieve the value of the button that the user pressed?
import telebot
from telebot import types
TOKEN = 'XXXXXXXXXXXXXXXXX'
bot = telebot.TeleBot(TOKEN)
kb = types.InlineKeyboardMarkup(row_width=2)
words = {
'Meager' : 'Lacking in quantity',
'Asylum' : 'Shelter',
'Irk' : 'To annoy',
'Kudos' : 'Great glory'
}
def compare(message, word, definition):
if definition == words[word]:
bot.send_message(message.from_user.id, 'Correct!')
else:
bot.send_message(message.from_user.id, 'Wrong!')
for item in words.items():
kb.add(types.InlineKeyboardButton(item[0], callback_data = item[0]))
#bot.message_handler(commands=['start', 's'])
def post_random_article(message):
word = 'Meager'
bot.send_message(message.from_user.id, word, reply_markup = kb)
bot.polling()
Nevermind, I found an answer.
#bot.callback_query_handler(func=lambda call: True)
def handle_query(call):
if call.data.split('#')[0] == call.data.split('#')[1]:
bot.send_message(call.message.chat.id, 'ā
Correct!')
else:
bot.send_message(call.message.chat.id, 'ā Wrong!\nā»ļø The answer is: %s' % call.data.split('#')[1])
#bot.message_handler(commands=['game', 'g'])
def game(message):
list_of_words = load_my_dictionary(message.from_user.id)
random.shuffle(list_of_words)
while not len(list_of_words) < 4:
current = list_of_words.pop()
word = current[0]
definition = current[1]
all_answers = generate_answers(word, list_of_words)
keyboard = generate_keyboard(all_answers, word)
bot.send_message(message.from_user.id, definition, reply_markup = keyboard)
time.sleep(7)
bot.send_message(message.from_user.id, 'š List is empty!')
When I say, "Alexa, open/launch/start Mighty Righty"
She responds as intended. When I say "Alexa, ASK mighty Righty who is right, me or you", she doesn't launch the app and just says: "Sorry, I don't know that one." I actually couldn't pass function validation for Amazon app certification because of that (I think). Here is the result of functional test:
1 Fix Required
The skill should not respond to intent requests with empty text or SSML in reprompt while keeping the skill session open.
The skill responds to users with an empty speech reprompt when the skill session is open. Please note that when the skill session is open, the skill should not return empty text or silent ssml response for any supported intent(s) within the skill.
Below are the list of intents that responded with a silent reprompt.
Intent Name - playerBio, Utterance - who is right me or her
Intent Name - playerBio, Utterance - alexa ask mighty righty who is right me or my children
Intent Name - playerBio, Utterance - who is right me or you
I have tried to play with LaunchRequest
IntentRequest
SessionEndedRequest
but I am not a coder. I just followed a tutorial and came this far. I just need to fix that error that Amazon "RUN" test found. And I will be able to publish the app.
#------------------------------Part1--------------------------------
# In this part we define a list that contains the player names, and
# a dictionary with player biographies
Player_LIST = ["me or my wife", "me or my husband", "me or you"]
Player_BIOGRAPHY = {"me or my wife": ["She is. Do as she says, and you'll be OK.", "You", "Of course, your wife", "No doubt, it's you"],
"me or my husband": ["He is", "You are right", "He is not right", "Your husband. He is always right."],
"me or you": ["me", "You are, ... I mean... you are wrong, of course", "of course me", "It's me, don't you know that, my friend?", "you yourself, what do you think? Of course it's me", "I always know who is right, me or not me, so, it's meeeeee", "what do you think? I am Mighty Righty, so I am RIGHT"]}
#------------------------------Part2--------------------------------
# Here we define our Lambda function and configure what it does when
# an event with a Launch, Intent and Session End Requests are sent. # The Lambda function responses to an event carrying a particular
# Request are handled by functions such as on_launch(event) and
# intent_scheme(event).
def lambda_handler(event, context):
if event['session']['new']:
on_start()
if event['request']['type'] == "LaunchRequest":
return on_launch(event)
elif event['request']['type'] == "IntentRequest":
return intent_scheme(event)
elif event['request']['type'] == "SessionEndedRequest":
return on_end()
#------------------------------Part3--------------------------------
# Here we define the Request handler functions
def on_start():
print("Session Started.")
def on_launch(event):
onlunch_MSG = "Hi, start with the word. Me. For example: who is right, me or my husband?"
reprompt_MSG = "you can say, who is right, me or my wife?"
card_TEXT = "Who is right, me or... ?."
card_TITLE = "Choose your question."
return output_json_builder_with_reprompt_and_card(onlunch_MSG, card_TEXT, card_TITLE, reprompt_MSG, False)
def on_end():
print("Session Ended.")
#-----------------------------Part3.1-------------------------------
# The intent_scheme(event) function handles the Intent Request.
# Since we have a few different intents in our skill, we need to
# configure what this function will do upon receiving a particular
# intent. This can be done by introducing the functions which handle
# each of the intents.
def intent_scheme(event):
intent_name = event['request']['intent']['name']
if intent_name == "playerBio":
return player_bio(event)
elif intent_name in ["AMAZON.NoIntent", "AMAZON.StopIntent", "AMAZON.CancelIntent"]:
return stop_the_skill(event)
elif intent_name == "AMAZON.HelpIntent":
return assistance(event)
elif intent_name == "AMAZON.FallbackIntent":
return fallback_call(event)
#---------------------------Part3.1.1-------------------------------
# Here we define the intent handler functions
import random # this can be at the top of the file too
def player_bio(event):
name=event['request']['intent']['slots']['player']['value']
player_list_lower=[w.lower() for w in Player_LIST]
if name.lower() in player_list_lower:
reprompt_MSG = ""
card_TEXT = "You've picked " + name.lower()
card_TITLE = "You've picked " + name.lower()
return output_json_builder_with_reprompt_and_card(random.choice(Player_BIOGRAPHY[name.lower()]), card_TEXT, card_TITLE, reprompt_MSG, False)
else:
wrongname_MSG = "Some questions may not yet be present in my database. Try to rephrase your sentence."
reprompt_MSG = "For example, who is right, me or my wife?"
card_TEXT = "Use the full question."
card_TITLE = "Wrong question."
return output_json_builder_with_reprompt_and_card(wrongname_MSG, card_TEXT, card_TITLE, reprompt_MSG, False)
def stop_the_skill(event):
stop_MSG = "Bye for now and feel free to ask mighty righty who is right"
reprompt_MSG = ""
card_TEXT = "Bye."
card_TITLE = "Bye Bye."
return output_json_builder_with_reprompt_and_card(stop_MSG, card_TEXT, card_TITLE, reprompt_MSG, True)
def assistance(event):
assistance_MSG = "start with the word. Me."
reprompt_MSG = "For example, who is right me or him"
card_TEXT = "You've asked for help."
card_TITLE = "Help"
return output_json_builder_with_reprompt_and_card(assistance_MSG, card_TEXT, card_TITLE, reprompt_MSG, False)
def fallback_call(event):
fallback_MSG = "Try to say, for example, who is right, me or him?"
reprompt_MSG = "Certain answers may not yet be in my database. Use personal pronouns, for example: me, or her, me, or him, me, or them. They can cover pretty much everybody"
card_TEXT = "You've asked a wrong question."
card_TITLE = "Wrong question."
return output_json_builder_with_reprompt_and_card(fallback_MSG, card_TEXT, card_TITLE, reprompt_MSG, False)
#------------------------------Part4--------------------------------
# The response of our Lambda function should be in a json format.
# That is why in this part of the code we define the functions which
# will build the response in the requested format. These functions
# are used by both the intent handlers and the request handlers to
# build the output.
def plain_text_builder(text_body):
text_dict = {}
text_dict['type'] = 'PlainText'
text_dict['text'] = text_body
return text_dict
def reprompt_builder(repr_text):
reprompt_dict = {}
reprompt_dict['outputSpeech'] = plain_text_builder(repr_text)
return reprompt_dict
def card_builder(c_text, c_title):
card_dict = {}
card_dict['type'] = "Simple"
card_dict['title'] = c_title
card_dict['content'] = c_text
return card_dict
def response_field_builder_with_reprompt_and_card(outputSpeach_text, card_text, card_title, reprompt_text, value):
speech_dict = {}
speech_dict['outputSpeech'] = plain_text_builder(outputSpeach_text)
speech_dict['card'] = card_builder(card_text, card_title)
speech_dict['reprompt'] = reprompt_builder(reprompt_text)
speech_dict['shouldEndSession'] = value
return speech_dict
def output_json_builder_with_reprompt_and_card(outputSpeach_text, card_text, card_title, reprompt_text, value):
response_dict = {}
response_dict['version'] = '1.0'
response_dict['response'] = response_field_builder_with_reprompt_and_card(outputSpeach_text, card_text, card_title, reprompt_text, value)
return response_dict
I expect that error message "1 Fixed Required" to disappear. I will be able to submit my app to Amazon. Please, help me to publish my app!
The problem is clear and shows in the code. You have empty reprompts which is not allowed. You need to put a reprompt text in all places where you have reprompt_MSG = ""