【问题标题】:Telegram Python Bot Inline Menu and DictionaryTelegram Python Bot 内联菜单和字典
【发布时间】:2021-07-12 09:59:12
【问题描述】:

Click Here to see the flowchart 我的 Telegram 机器人需要一些帮助。我正在尝试创建一个机器人,它允许我修改一组选定的字典值并在其末尾以某种方式显示字典键和值。如代码所示,现在我无法弄清楚如何找出用户单击了哪个按钮并将其反映在该键的相应值中。 (例如,(KEY)Shop A - (VALUE)Low Crowd、Compliant...等等,对于这个选定区域的其他商店)。请注意,我目前仅编写了区域 1 的代码作为示例 -> 它还必须能够使用他们自己的一组具有空值的预定义字典键来为其他选定区域工作。请参考图片以获得更好的理解

#!/usr/bin/env python
# pylint: disable=C0116
    
    import logging
    
    from telegram import Update, ForceReply, InlineKeyboardButton, InlineKeyboardMarkup
    from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackContext, CallbackQueryHandler
    
    # Enable logging
    logging.basicConfig(
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
    )
    
    logger = logging.getLogger(__name__)
    
    
    ############################ Keyboards #########################################
    def main_area_selection_kb():
        keyboard = [
            [
                InlineKeyboardButton("Area 1", callback_data='main_1'),
            ],
            [
                InlineKeyboardButton("Area 2", callback_data='main_2'),
            ],
            [
                InlineKeyboardButton("Area 3", callback_data='main_3'),
            ],
            [
                InlineKeyboardButton("Area 4", callback_data='main_4'),
            ],
            [
                InlineKeyboardButton("Area 5", callback_data='main_5'),
            ],
            [
                InlineKeyboardButton("Area 6", callback_data='main_6'),
            ],
        ]
        return InlineKeyboardMarkup(keyboard)
    
    def crowd_level_selection_kb():
        keyboard = [
            [
                InlineKeyboardButton("Low", callback_data='clvl_1'),
                InlineKeyboardButton("Moderate", callback_data='clvl_2'),
                InlineKeyboardButton("High", callback_data='clvl_3'),
                InlineKeyboardButton("Closed", callback_data='clvl_4'),
            ]
        ]
    
        return InlineKeyboardMarkup(keyboard)
    
    def compliance_kb():
        keyboard = [
            [
                InlineKeyboardButton("Compliant", callback_data='com_1'),
                InlineKeyboardButton("Not Compliant", callback_data='com_2'),
            ]
        ]
        return InlineKeyboardMarkup(keyboard)
    
    ############################ Selection #########################################
    def compliance_selection(update, _: CallbackContext) -> None:
        query = update.callback_query
        query.answer()
        if query.data == 'com_1':
            query.message.reply_text('Compliant')
        elif query.data == 'com_2':
            query.message.reply_text('Not Compliant')
    
    def crowd_level_selection(update, _: CallbackContext) -> None:
        query = update.callback_query
        query.answer() # How do I "pass" the dictionary in/return the value of the user selection back into the respective dictionary's key value?)
        if query.data == 'clvl_1':
            query.message.reply_text('You choose Low Crowd') 
        elif query.data == 'clvl_2':
            query.message.reply_text('You choose Moderate Crowd')
        elif query.data == 'clvl_3':
            query.message.reply_text('You choose High Crowd')
        elif query.data == 'clvl_4':
            query.message.reply_text('You choose Closed')
    
    def main_area_selection(update, _: CallbackContext) -> None:
        query = update.callback_query
    
        query.answer()
        # query.edit_message_text(text=f"Selected option: {query.data}")
        if query.data == 'main_1':
            query.message.reply_text('You choose Area 1')
            areamain(query)
        elif query.data == 'main_2':
            query.message.reply_text('You choose Area 2')
        elif query.data == 'main_3':
            query.message.reply_text('You choose Area 3')
        elif query.data == 'main_4':
            query.message.reply_text('You choose Area 4')
        elif query.data == 'main_5':
            query.message.reply_text('You choose Area 5')
        elif query.data == 'main_6':
            query.message.reply_text('You choose Area 6')
        else:
            query.message.reply_text('Error')
    
    ############################ Functions #########################################
    
    def start(update, context):
        """Send a message when the command /start is issued."""
        update.message.reply_text('Please Choose an Area', reply_markup=main_area_selection_kb())
    
    
    def areamain(update):
        areamaindict = {'Shop A': '', 'Shop B': '', 'Shop C': '', 'Shop D': '', 'Shop E': ''}
    
        for i in areamaindict:
            update.message.reply_text(f"{i} Crowd Level:", 
reply_markup=crowd_level_selection_kb())
            

            #Next step: Add in menu for compliance
            #Following that, Set this i value to <High/Medium/Low> Crowd and <Compliant/Not Compliant> once user selected both respective buttons
    
    ############################ Main #########################################
    def main():
        
        # Create the Updater and pass it your bot's token.
        updater = Updater("TOKEN")
    
        # Get the dispatcher to register handlers
        dispatcher = updater.dispatcher
    
        # on different commands - answer in Telegram
        dispatcher.add_handler(CommandHandler("start", start))
    
        ############################# Handlers #########################################
        updater.dispatcher.add_handler(CallbackQueryHandler(main_area_selection, pattern='main'))
        updater.dispatcher.add_handler(CallbackQueryHandler(crowd_level_selection, pattern='clvl'))
        updater.dispatcher.add_handler(CallbackQueryHandler(compliance_selection, pattern='com'))
    
    
        # Start the Bot/Listen for user input/messages
        updater.start_polling()
    
        # Run the bot until you press Ctrl-C or the process receives SIGINT,
        # SIGTERM or SIGABRT. This should be used most of the time, since
        # start_polling() is non-blocking and will stop the bot gracefully.
        updater.idle()
    
    
    if __name__ == '__main__':
        main()

【问题讨论】:

  • 在回调处理程序中拆分 callback.data 像这样 _, number = callback.data.split("_") 然后一个基本的 if else 会帮助你,比如 if number = 4: do something ....
  • 嗨@AlenPaulVarghese 感谢您的建议!我想寻求进一步的澄清。你能给我看一个简单的实现例子吗?因为我似乎看不到它如何使我能够确定用户单击了哪个按钮并将其反映在相应的字典键值中。

标签: python telegram telegram-bot python-telegram-bot telegram-api


【解决方案1】:

注意,投诉没有实现,希望大家能用同样的设计思路来实现。

#!/usr/bin/env python
# pylint: disable=C0116

import logging
from typing import Dict

from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
    Updater,
    CommandHandler,
    CallbackContext,
    CallbackQueryHandler,
)

# Enable logging
logging.basicConfig(
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
)

logger = logging.getLogger(__name__)

temporary_data: Dict[int, dict] = {}


def compliance_kb():
    return InlineKeyboardMarkup(
        [
            [
                InlineKeyboardButton("Compliant", callback_data="com_1"),
                InlineKeyboardButton("Not Compliant", callback_data="com_2"),
            ]
        ]
    )


# ########################### Selection #########################################
def compliance_selection(update, _: CallbackContext) -> None:
    query = update.callback_query
    query.answer()
    if query.data == "com_1":
        query.message.reply_text("Compliant")
    elif query.data == "com_2":
        query.message.reply_text("Not Compliant")


def crowd_level_selection(update, _: CallbackContext) -> None:
    global temporary_data
    query = update.callback_query
    query.answer()
    main_area_number = query.data.split("_")[-1]

    # we need to identify the shop right? for that we can take the message for example Shop C Crowd Level:
    # so taking the first 6 charachter from the message we got the key

    shop_level = update.effective_message.text[:6]
    update.effective_message.delete()
    if "clvl_1" in query.data:
        query.message.reply_text(
            f"You choose Low Crowd of main area {main_area_number}"
        )
        temporary_data[query.from_user.id]["shop_data"][shop_level][
            "crowd_level"
        ] = "Low"
    elif "clvl_2" in query.data:
        query.message.reply_text(
            f"You choose Moderate Crowd of main area {main_area_number}"
        )
        temporary_data[query.from_user.id]["shop_data"][shop_level][
            "crowd_level"
        ] = "Moderate"
    elif "clvl_3" in query.data:
        query.message.reply_text(
            f"You choose High Crowd of main area {main_area_number}"
        )
        temporary_data[query.from_user.id]["shop_data"][shop_level][
            "crowd_level"
        ] = "High"
    elif "clvl_4" in query.data:
        query.message.reply_text(f"You choose Closed of main area {main_area_number}")
        temporary_data[query.from_user.id]["shop_data"][shop_level][
            "crowd_level"
        ] = "Closed"

    from pprint import pprint

    print(shop_level)
    pprint(temporary_data)


def main_area_selection(update, _: CallbackContext) -> None:
    global temporary_data
    temporary_data[update.effective_chat.id] = {}

    query = update.callback_query
    query.answer()
    each_shop_dict = {
        "Shop A": {"crowd_level": "null", "compliant": "null"},
        "Shop B": {"crowd_level": "null", "compliant": "null"},
        "Shop C": {"crowd_level": "null", "compliant": "null"},
        "Shop D": {"crowd_level": "null", "compliant": "null"},
        "Shop E": {"crowd_level": "null", "compliant": "null"},
    }  # or {f"Shop {k}":{"crowd_level": "null", "compliant": "null"} for k in ["A", "B", "C", "D", "E"]} but this makes confusion.

    update.effective_message.delete()
    if "main" in query.data:
        number = query.data.split("_")[-1]
        query.message.reply_text(f"You choose Area {number}")
        temporary_data[query.from_user.id].update(
            dict(main_area_number=int(number), shop_data=each_shop_dict)
        )
    for i in each_shop_dict:
        main_area_number = query.data.split("_")[-1]
        markup = InlineKeyboardMarkup(
            [
                [
                    InlineKeyboardButton(
                        "Low", callback_data=f"clvl_1_{main_area_number}"
                    ),
                    InlineKeyboardButton(
                        "Moderate", callback_data=f"clvl_2_{main_area_number}"
                    ),
                    InlineKeyboardButton(
                        "High", callback_data=f"clvl_3_{main_area_number}"
                    ),
                    InlineKeyboardButton(
                        "Closed", callback_data=f"clvl_4_{main_area_number}"
                    ),
                ]
            ]
        )
        query.message.reply_text(f"{i} Crowd Level:", reply_markup=markup)


# ########################### Functions #########################################


def start(update, context):
    """Send a message when the command /start is issued."""
    print(temporary_data.get(update.effective_chat.id, None))
    update.message.reply_text(
        "Please Choose an Area",
        reply_markup=InlineKeyboardMarkup(
            [
                [
                    InlineKeyboardButton("Area 1", callback_data="main_1"),
                ],
                [
                    InlineKeyboardButton("Area 2", callback_data="main_2"),
                ],
                [
                    InlineKeyboardButton("Area 3", callback_data="main_3"),
                ],
                [
                    InlineKeyboardButton("Area 4", callback_data="main_4"),
                ],
                [
                    InlineKeyboardButton("Area 5", callback_data="main_5"),
                ],
                [
                    InlineKeyboardButton("Area 6", callback_data="main_6"),
                ],
            ]
        ),
    )


# ########################### Main #########################################
def main():

    # Create the Updater and pass it your bot's token.
    updater = Updater("TOKEN")

    # Get the dispatcher to register handlers
    dispatcher = updater.dispatcher

    # on different commands - answer in Telegram
    dispatcher.add_handler(CommandHandler("start", start))

    # ############################ Handlers #########################################
    updater.dispatcher.add_handler(
        CallbackQueryHandler(main_area_selection, pattern="main")
    )
    updater.dispatcher.add_handler(
        CallbackQueryHandler(crowd_level_selection, pattern="clvl")
    )
    updater.dispatcher.add_handler(
        CallbackQueryHandler(compliance_selection, pattern="com")
    )

    # Start the Bot/Listen for user input/messages
    updater.start_polling()

    # Run the bot until you press Ctrl-C or the process receives SIGINT,
    # SIGTERM or SIGABRT. This should be used most of the time, since
    # start_polling() is non-blocking and will stop the bot gracefully.
    updater.idle()


if __name__ == "__main__":
    main()

【讨论】:

  • 再次嗨@Alen Paul Varghese 感谢您花时间回答我的问题,我已经尝试过您提供的代码,但我认为这不是我真正想要的,但是不用担心,因为我已经创建了一个流程图来向您展示我的预期机器人逻辑i.stack.imgur.com/Ge6W4.png 现在,我不知道如何将用户选择的预定义字典链接到内联按钮选择。 (简而言之,如何将内联按钮选择的输入传递到相应的字典键的值)
  • @Firwer 我再次编辑了一些更改检查
猜你喜欢
  • 2022-01-26
  • 2018-11-17
  • 2021-08-03
  • 1970-01-01
  • 2018-08-09
  • 1970-01-01
  • 2017-06-18
  • 2017-06-02
  • 2018-12-10
相关资源
最近更新 更多