1

I'm creating a bot that sends math problems in image format. I wanted to create two two functions for different commands, so that one command only sends one genre of question, while the other sends another genre. Example: /random sends general problems, while /comb sends combinatorial problems.

My attempt:

@dp.message_handler(commands=['random', 'comb'])
async def random_cat(message: types.Message):
    captions = ["Nice problem!", "Niceeeeee :eyes:",
                "Noice", "Very cool"]
    caption = random.choice(captions)
    asyncio.create_task(fetch_cat())
    if dp.message_handler(commands=['random']):
        for image in [random.choice(["quest1.jpg", "quest2.jpg", "quest4.jpg", "quest5.jpg", "quest6.jpg",
                                    "quest7.jpg", "quest8.jpg","quest9.jpg", "quest10.jpg", "quest11.jpg", "quest12.jpg"])]:
            f = open(image, 'rb')
            photo = f.read()
            f.close()        
    elif dp.message_handler(commands=['comb']):
        for item in [random.choice(["quest14.jpg", "quest15.jpg"])]:
            r = open(item, 'rb')
            photo = r.read()
            r.close()             
    # _id = random.random()
    await bot.send_photo(chat_id=message.chat.id,
                         photo=photo,
                         caption=emojize(
                             caption) if caption == captions[1] else caption,
                         reply_to_message_id=message.message_id)
if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)

Even with the code, the bot sends the same messages for the same command. How to solve this? If possible, how can I change the codes to be able to put new commands for other types of questions in the future?

CallMeStag
  • 5,467
  • 1
  • 7
  • 22
Jhon Oliver
  • 149
  • 6
  • create two separated functions `@dp.message_handler(commands=['random'])` and `@dp.message_handler(commands=['comb'])` - and it will be simpler to find problem – furas Mar 08 '22 at 01:27
  • I'm not sure if this is correct `if dp.message_handler(commands=['random']):` - because `message_handler()` is not for checking command. I think it should be `if message == 'random':` but if this doesn't work then better run every command in separated function. – furas Mar 08 '22 at 01:29

1 Answers1

2

dp.message_handler(commands=['random']) is NOT for checking command but for assigning function to command.

I tested and it has to be

if message.text == '/random':
    # ... code ...

elif  message.text == '/comb':
    # ... code ...

and if you want to run commands with parameters then use str.startswith()

if message.text.startswith('/random'):
    # ... code ...

elif message.text.startswith('/comb'):
    # ... code ...

Or you can split message to get command and arguments as list.

    cmd, *args = message.text.split(" ")
    
    if cmd == '/random':
       # ... code ...

    elif cmd == '/comb':
        # ... code ...

If there is no arguments then args will be empty list.


Full working code:

Because some code is the same for /random and /comb so I moved it to separated function send_question()

And I keep images in global variables - they don't have to be created again and again when command is executed.

import logging
from aiogram import Bot, Dispatcher, executor, types
import os
import random
import asyncio

API_TOKEN = os.getenv('TELEGRAM_TOKEN')
print(API_TOKEN)

# Configure logging
logging.basicConfig(level=logging.INFO)

# Initialize bot and dispatcher
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot)

# ------------------------------------------

def emojize(x):
    return x

async def send_question(message, all_photos):
    
    captions = ["Nice problem!", "Niceeeeee :eyes:", "Noice", "Very cool"]
    caption = random.choice(captions)
    print('caption:', caption)

    image = random.choice(all_photos)
    print('image:', image)

    with open(image, 'rb') as f:
        photo = f.read()

    asyncio.create_task(fetch_cat())

    await bot.send_photo(chat_id=message.chat.id,
                         photo=photo,
                         caption=emojize(caption) if caption == captions[1] else caption,
                         reply_to_message_id=message.message_id)

# ------------------------------------------

random_photos = ["quest1.jpg", "quest2.jpg", "quest3.jpg", "quest4.jpg",
                 "quest5.jpg", "quest6.jpg", "quest7.jpg", "quest8.jpg",
                 "quest9.jpg", "quest10.jpg", "quest11.jpg", "quest12.jpg"]            

comb_photos = ["quest14.jpg", "quest15.jpg"]
    
@dp.message_handler(commands=['random', 'comb'])
async def random_cat(message: types.Message):

    print(message.text)
    #print(dp.message_handler(commands=['random']))
    
    cmd, *args = message.text.split(" ")
    print(cmd, args)
    
    if cmd.startswith('/random'):
        await send_question(message, random_photos)
    elif cmd.startswith('/comb'):
        await send_question(message, comb_photos)

# ------------------------------------------

if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)

EDIT:

You can also run it as two separated functions

@dp.message_handler(commands=['random'])
async def random_cat(message: types.Message):
    
    await send_question(message, random_photos)

@dp.message_handler(commands=['comb'])
async def random_cat(message: types.Message):

    await send_question(message, comb_photos)
furas
  • 134,197
  • 12
  • 106
  • 148
  • 1
    Also, you can accept a `command` into the handler like this: `async def random_cat(message: types.Message, command: Command.CommandObj): ...`, and use `command.command` and `command.args` for command and its arguments respectively. `Command` for type hint can be imported from `aiogram.dispatcher.filters`. – evgfilim1 Mar 15 '22 at 04:37