How do I have my Bot respond with arguments?
Asked Answered
A

7

30

So I've built a Telegram bot, which can receive the following commands:

  • /list
  • /info 123

This works great, as I can catch /info and pass the additional arguments as ints. But, sadly, the Telegram clients don't see /info 123 as a complete command, but just the /info part. Is there a way to make it recognize the entirety of the command as the command?

I've tried Markdown-ing it: [/info 123](/info 123), but no joy. Is this possible?

Abbey answered 17/3, 2016 at 11:42 Comment(1)
Show us some code.Stoicism
A
22

I've reached out to @BotSupport with the same question, and he/they/it responded swiftly with the following answer:

Hi, at the moment it is not possible to highlight parameters of a command. I any case, you may can find a workaround if you use correct custom keyboards ;) — @BotSupport

Custom keyboards may be an option for someone, but not for me. The solution I've gone for is to give the command as /info123. As the bot receives all / commands, I check if the received command starts with info, and if so, I remove the info part. I convert the remaining string/int to arguments, and pass that along to the relevant command.

Abbey answered 23/3, 2016 at 9:55 Comment(4)
Thank you for your answer, but how do you check the command name, I am trying to find a way to catch all commands then to parse them. Thank you!Enthronement
@Enthronement that's all dependent on the framework you're using.Abbey
@ortonomy No, you don't. Registering commands with BotFather only make them show on user interface as a list when someone types "/", but you can implement commands that aren't listed - just don't register them in BotFather. Your bot will answer the commands regardless.Evenfall
Hi from 2024, is this still the correct answer 8 years later, or did we get something better? 👀Intoxicate
T
13

If you mean to pass the 123 as an argument for your command info and if you happen to use the python-telegram-bot, then here's how you do it:

dispatcher.add_handler(CommandHandler('hello', SayHello, pass_args=True))

According to the documentation: pass_args Determines whether the handler should be passed the arguments passed to the command as a keyword argument called args. It will contain a list of strings, which is the text following the command split on single or consecutive whitespace characters. Default is False.

Tetherball answered 1/5, 2018 at 18:43 Comment(2)
I get what you're saying - but if you provide feedback to the user, with a list of commands, you can't highlight or make the full /info 123 clickable. It'll just be /info that gets highlighted and thus sent.Abbey
@Abbey so you want a list of all the possible arguments, hardcoded so that they appear when the user clicks the / icon on the chat? I believe the only way to do that is to actually hardcode them as separate commands with an delimiter between the arguments such as /info_123 or /info_456. Those should actually appear in the dropdown list but they don't actually accept arguments, they are just two different commands that call the same underlying method with different arguments.Dennison
K
6

you can use RegexHandler() to do this.

Here is an example

def info(bot, update):
  id = update.message.text.replace('/info_', '')
  update.message.reply_text(id, parse_mode='Markdown')


def main():
  updater = Updater(TOKEN)
  updater.dispatcher.add_handler(RegexHandler('^(/info_[\d]+)$', info))
  updater.start_polling()

Usage

The command /info_120 will return 120
and /info_007 will return 007

UPDATE
for newer versions, you may use this method instead!

MessageHandler(filters.Regex(r'^(/info_[\d]+)$'), info)
Kootenay answered 29/12, 2018 at 15:26 Comment(2)
Aah, fair point, that would have been a good way to do it as well! Thanks :).Abbey
and now MessageHandler(filters.Regex(r'^(/info_[\d]+)$'), info)Inexperience
V
5

ForceReply

Upon receiving a message with this object, Telegram clients will display a reply interface to the user (act as if the user has selected the bot's message and tapped 'Reply'). This can be extremely useful if you want to create user-friendly step-by-step interfaces without having to sacrifice privacy mode.

a simple shot

enter image description here

In this case, a user should send a valid number with /audio command (e.g. /audio 3, if they forgot it, we can inform and force them to do so.

source:
https://core.telegram.org/bots/api#forcereply

Vulcanize answered 19/11, 2021 at 11:9 Comment(0)
D
4

To get the argument of command you don't even need to use pass_args as said Moein you can simply get it from context.args look at Github page. So you can pass as many arguments as you want and you will get a list of arguments! Here is an example from Github.

def start_callback(update, context):
  user_says = " ".join(context.args)
  update.message.reply_text("You said: " + user_says)

...

dispatcher.add_handler(CommandHandler("start", start_callback))
Deadly answered 2/9, 2020 at 9:7 Comment(0)
G
1

Adding a custom command to the existing list and then mentioning it in the reply worked for me.

custom_command = f'explore{random.randint(2, 6)}';
commands = [
    ...list of default commands...
    (custom_command, 'explore abc')
]
await bot.set_my_commands(
    commands=commands,
    scope=telegram.BotCommandScopeChat(
        chat_id=update.effective_chat.id
    )
)
await bot.send_message(chat_id=chat_id, text=f"Click /{custom_command} to proceed")
Gentes answered 27/6 at 17:12 Comment(0)
G
0

This is a fairly rudimentary way of creating kwargs from user input.

Unfortunately, it does require the user to be aware of the fields that can be used as parameters, but if you can provide informative response when the user doesnt provide any detectable kwarg style messages then you could probably make a better experience.

As I say, extremely rudimentary idea, and would probably be achieved faster with the regex filters available. And this would be much more reliable when checking input from the user of the "pesky" variety.

The script relies on || delimiter preceeding the command and as is shown will trim any extra characters like new lines and spaces

You can remove the extra check for commit as this is provided in order to tell the bot that you want to save your input to the database explicitly.

def parse_kwargs(update):
    commit = False
    kwargs = {}
    if update.message:
        for args in update.message.text.split('||')[1:]:
            for kw_pair in args.split(','):
                key, value = kw_pair.split('=')
                if key.strip() != 'commit':
                    kwargs[key.strip()] = value.strip()
                elif key.strip() == 'commit' and value.strip().lower() == 'true':
                    commit = True
    return kwargs, commit
Grilled answered 16/2, 2020 at 20:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.