处理文本输入异常而不是按钮点击在回调查询aiogram机器人中。

huangapple go评论68阅读模式
英文:

Handling text input exception instead of button click in callback_query aiogram bot

问题

I've translated the non-code part of your text as you requested:

朋友们,我正在学习创建简单的机器人。我自己也在互联网上寻找解决方案。但现在我无法没有你们的经验,我希望能得到帮助! 处理文本输入异常而不是按钮点击在回调查询aiogram机器人中。

期望结果:

  1. 通过启动命令,我们启动机器人。

  2. 出现消息:“来自机器人的问候!”下面有一个按钮:“选择城市”。

  3. 当按下“选择城市”按钮时,会出现字样:“您的城市:”和一系列城市名称的按钮。

  4. 用户点击一个城市名称的按钮。

  5. 之后,城市名称按钮消失,聊天中出现了按下的城市名称的文本。

  6. 总结:在代码变量中,我们获得了城市的名称。

问题:
在第3步之后,除了点击城市按钮之外,用户还可以在文本字段中输入内容。然后按钮会消失,如果输入的不是按钮上指定的城市名称之一,进程将停止,因为城市名称是后续发送请求所需的参数。

解决方案:
需要在第3步之后捕获任何文本输入,除了指定按钮的名称之外,如果文本不等于按钮上的城市名称 => 需要:

  1. 显示消息,要求选择城市!
  2. 再次显示带有城市名称的按钮。
  3. 捕获并将正确的名称写入变量,可以通过点击按钮或用户在文本字段中输入城市名称的确切匹配来获得。

**关于期望结果,**对我来说一切都顺利,但我无法解决问题 - 不正确的输入或用户在文本字段中的意外点击...我尝试将其包装在While循环中,但无法获得正确的响应。请告诉我如何解决这个问题?

如果您需要进一步的帮助,请随时提出问题。

英文:

Friends, I am learning to create simple bots. And I'm myself looking for a solution to problems on the Internet. But now I can not do without your experience and I hope for help! 处理文本输入异常而不是按钮点击在回调查询aiogram机器人中。

Expected Result:

  1. By the start command, we launch the bot.
  2. A message appears: "Hello from the bot!" and under it there is a button: "Select a city"
  3. When you press the button: "Select a city", the inscription appears: "Your city:" and a number of buttons with the names of cities.
  4. The user clicks on one of the buttons with the name of the city.

5.After that, the buttons with the cities disappear and the text sent to the chat appears with the name of the city button pressed.

6.TOTAL: In the code variable we get the name of the city.

Problem:
After step 3, in addition to clicking on any of the buttons with the city, the user can enter something in the text field. Then the buttons are collapsed, and if something other than the name of the cities indicated on the buttons is entered, the process will stop, since the name of the city is the parameter needed later to send the request.

Solution:
Need to catch any text input after the 3rd step, other than the name of the specified buttons, and if the text != the name of one of the buttons => you need:

  1. display a message that you need to select a city!
  2. display the buttons with the name of the cities again.
  3. catch and write to the variable the correct name, obtained either by clicking on the button, or by entering the exact match of the city name in the text field by the user.

Regarding the expected result, everything worked out for me, but I can’t handle the problem - incorrect input or accidental clicking by the user in the text field... I tried wrapping it in a While Loop, but I'm having trouble getting the correct response.
Please tell me how can solve this problem?

from aiogram import Bot, Dispatcher, executor, types
from aiogram.dispatcher.filters.state import StatesGroup, State
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
import asyncio
import os as OSis
 
bot = Bot(token=OSis.getenv("TOKEN"), parse_mode=types.ParseMode.HTML)
dp = Dispatcher(bot, storage=MemoryStorage())
 
 
# State class:
class UserAnswer(StatesGroup):
    City = State()
 
 
@dp.message_handler(commands="start")
async def start(message: types.Message):
    # add button:
    markup = InlineKeyboardMarkup()
    start_button = InlineKeyboardButton(text='Select a city', callback_data="town_id")
    markup.add(start_button)
    await bot.send_message(message.chat.id, "Hello from the bot!", reply_markup=markup)
 
 
# Handler for displaying the result of a button click: start_button
@dp.callback_query_handler(lambda c: c.data == "town_id")
async def button_press(call: types.callback_query):
    """Displaying a list of cities in the form of buttons"""
    list_cities = ['Washington', 'Montgomery', 'Phoenix', 'Atlanta', 'Boise', 'Frankfort', 'Boston', 'Springfield', 'Helena', 'Nashville']
    while True:
        keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True)
        for name in list_cities:
            keyboard.row(types.KeyboardButton(name))
        await bot.answer_callback_query(call.id)
        await bot.send_message(call.message.chat.id, "Your city:", reply_markup=keyboard)
        # Set the status for the 1st response:
        await UserAnswer.City.set()
 
        # I tried to write the code below to handle the exception...
        enter_city = await get_answer_correct(call.message)
        if any(enter_city in item for item in list_cities):
            break
        else:
            await bot.send_message(call.message.chat.id, "CHOOSE YOUR CITY:", reply_markup=keyboard)
            await asyncio.sleep(5)  # I tried to slow down the loop but it didn't work
 
@dp.message_handler(state=UserAnswer.City)
async def get_answer_correct(message: types.Message):
    # Recording the user's response after clicking the city button or entering text in the field
    answer_correct_city = message.text
    print('answer_correct_city =', answer_correct_city)
    return answer_correct_city

def main():
    executor.start_polling(dp)

if __name__ == '__main__':
    main()

答案1

得分: 1

尝试使用InlineKeyboardButtons而不是简单的键盘按钮,就像在"select a city"中所做的那样。它会看起来像这样:

keyboard = InlineKeyboardMarkup(one_time_keyboard=True)

for city in cities:
    new_city = InlineKeyboardButton(f"{city}", callback_data=f"{city}")
    keyboard.row(new_city)

@dp.message_handler(commands=["start"])
async def bot_message(message: types.Message):
    await bot.send_message(message.from_user.id, "Text", reply_markup=keyboard)

@dp.callback_query_handler(text="insert the name of city 1 here")
async def send_the_city(call: types.CallbackQuery):
    await bot.send_message(call.from_user.id, "Your city: Insert the name of city 1 here")

@dp.callback_query_handler(text="insert the name of city N here")
async def send_the_city(call: types.CallbackQuery):
    await bot.send_message(call.from_user.id, "Your city: Insert the name of city N here")

内联按钮不依赖于输入文本,因此键盘不会折叠。

英文:

Try using InlineKeyboardButtons instead of simple Keyboard buttons like you did in "select a city". It will look like this:

keyboard = InlineKeyboardMarkup(one_time_keyboard=True)

for city in cities:
    new_city = InlineKeyboardButton(f"{city}", callback_data=f"{city}")
    keyboard.row(new_city)

@dp.message_handler(commands=["start"])
async def bot_message(message: types.Message):
    await bot.send_message(message.from_user.id, "Text", reply_markup=keyboard)

@dp.callback_query_handler(text="insert the name of city 1 here")
async def send_the_city(call: types.CallbackQuery):
    await bot.send_message(call.from_user.id, "Your city: Insert the name of city 1 here")
    
@dp.callback_query_handler(text="insert the name of city N here")
async def send_the_city(call: types.CallbackQuery):
    await bot.send_message(call.from_user.id, "Your city: Insert the name of city N here")

Inline buttons do not depend on input text and thus the keyboard will not collapse.

答案2

得分: 1

Anna,感谢你提供的好主意!它帮助我想出了其他选项。例如,我从一个机器人接收到一个城市响应。现在我在考虑如何在另一个带有处理程序的函数中调用 choose_city 变量 - message_handler :))

@dp.message_handler(commands="start")
async def button_press(message: types.Message):
    markup = InlineKeyboardMarkup(row_width=2)
    for city in cities:
        markup.insert(InlineKeyboardButton(text=f"{city}", callback_data=f"{city}"))
    await bot.send_message(message.from_user.id, "HELLO! ❤", reply_markup=markup)

@dp.callback_query_handler()
async def send_the_city(call: types.CallbackQuery):
    if any(call.data in x for x in cities):
        await bot.answer_callback_query(call.id)
        await bot.send_message(call.from_user.id, call.data)
        choose_city = call.data
        print('call =', choose_city)  # Ok

我通过异常处理解决了我的问题,尽管我拒绝使用“选择城市”按钮和 callback_query_handler :))

英文:

Anna, thanks for the good idea! It helped me come up with other options. For example, I received a city response from a bot. Now I'm thinking how to call the choose_city variable in another function with a handler - message_handler :))

@dp.message_handler(commands="start")
async def button_press(message: types.Message):
    markup = InlineKeyboardMarkup(row_width=2)
    for city in cities:
        markup.insert(InlineKeyboardButton(text=f"{city}", callback_data=f"{city}"))
    await bot.send_message(message.from_user.id, "HELLO! ❤", reply_markup=markup)

@dp.callback_query_handler()
async def send_the_city(call: types.CallbackQuery):
    if any(call.data in x for x in cities):
        await bot.answer_callback_query(call.id)
        await bot.send_message(call.from_user.id, call.data)
        choose_city = call.data
        print('call =', choose_city)  # Ok

I solved my problem with exception handling, though I refused to use the 'Select a city' button and callback_query_handler :))

huangapple
  • 本文由 发表于 2023年6月9日 06:29:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76436100.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定