Ответы пользователя по тегу AIOgram
  • Как вызвать функцию, чтобы код (бот) продолжал работу?

    @codingoleg
    Пример работы на aiogram 2.25. После нажатия /long_task можно нажимать как /start, так и /long_task (запустится еще одна корутина). Также в параметрах executor.start_polling() есть loop, куда можно добавить задачи по крайней мере при старте бота, например, планировщик.
    import asyncio
    import os
    from aiogram import Bot, Dispatcher
    from aiogram.types import Message
    from aiogram.utils import executor
    
    bot = Bot(token=os.environ['token'])
    dp = Dispatcher(bot)
    
    async def long_task():
        for i in range(10):
            print(i)
            await asyncio.sleep(1)
    
    @dp.message_handler(commands=['start'])
    async def dp_start(message: Message):
        await message.answer('Test')
    
    @dp.message_handler(commands=['long_task'])
    async def run_long_task(message: Message):
        print('Старт')
        await long_task()  # Функция, которая долго исполняется
        print('Финиш')
    
    if __name__ == '__main__':
        executor.start_polling(dp, skip_updates=True)
    Ответ написан
  • Как адаптировать динамичную клавиатуру под разные сообщения?

    @codingoleg
    Пример на aiogram 2.25. Вместо user_1 у вас будет message.from_user.id или callback.from_user.id. Вместо словаря - база данных:
    from aiogram import Bot, Dispatcher, executor, types
    from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
    
    bot = Bot('')
    dp = Dispatcher(bot)
    
    user_1 = {'orders': {'заказ 1', 'заказ 2', 'заказ 3'}}
    
    @dp.message_handler(commands=['start'])
    async def list_orders(message: types.Message):
        if user_1['orders']:
            for order in user_1['orders']:
                await message.answer(
                    text=order,
                    reply_markup=InlineKeyboardMarkup().add(InlineKeyboardButton('Удалить', callback_data='Удалить заказ'))
                )
        else:
            await message.answer("no orders.")
    
    @dp.callback_query_handler(text='Удалить заказ')
    async def delete_order(callback: types.CallbackQuery):
        await callback.answer()
        order = callback.message.text
        if order in user_1['orders']:
            user_1['orders'].remove(order)
            await callback.message.answer(text=f'{order} удален')
        else:
            await callback.message.answer(text=f'{order} не найден')
        print(user_1['orders'])  # Для проверки
    
    executor.start_polling(dp)
    Ответ написан
    Комментировать
  • Как вызвать Callback без inline клавиатуры?

    @codingoleg
    Если вопрос только в поп-ап уведомлении, то в апи телеграма написано, что метод только для Inline клавиатур. Поэтому aiogram вам ничем не поможет. Если нужна проверка входящих данных, то можно использовать один из или все три варианта: 1. Машина состояний. 2. Функция проверки в аргументах декоратора. 3. Middleware для более сложных случаев. Вот вам 1 и 2 вариант:
    from aiogram import Bot, Dispatcher, executor, types
    from aiogram.types import ReplyKeyboardMarkup
    from aiogram.contrib.fsm_storage.memory import MemoryStorage
    
    bot = Bot('')
    storage = MemoryStorage()
    dp = Dispatcher(bot, storage=MemoryStorage())
    
    state_time = 'setTime'
    kb = ReplyKeyboardMarkup(row_width=10, one_time_keyboard=True)
    btns = (types.KeyboardButton(str(btn)) for btn in range(1, 31))
    kb.add(*btns)
    
    @dp.message_handler(commands=['start'])
    async def dp_choose_user(message: types.Message):
        await message.answer('Введите день:', reply_markup=kb)
        await dp.current_state().set_state(state_time)  # Вход в состояние ввода даты
    
    @dp.message_handler(lambda message: message.text.isdigit() and 1 <= int(message.text) <= 30, state=state_time)
    async def dp_choose_action(message: types.Message):
        await message.answer(text=f'Вы выбрали {message.text}')
        await dp.current_state().reset_state()  # Выход из состояния ввода даты
    
    @dp.message_handler(state=state_time)
    async def dp_choose_action(message: types.Message):
        await message.answer(text='Ошибка ввода даты. Введите еще раз.', reply_markup=kb)
    
    executor.start_polling(dp)
    Ответ написан
    Комментировать
  • Почему код может не работать?

    @codingoleg
    Не знаю, как вы это написали, но у меня весь код подсвечивает ошибками на версии 2.25 или 3.*. У вас мешанина из разных клавиатур и переменных. Также я бы не стал в одном хэндлере содержать несколько условий - проще их разнести. Вот вам готовый код, но не знаю, как вы дальше сможете. Ответом на выбор жанра должна быть уже функция с @dp.callback_query_handler(), а не @dp.message_handler, из-за того, что клавиатура инлайн.
    @dp.message_handler(text='Выбрать фильм')
    async def Vibr(message: types.Message):
        markups = types.ReplyKeyboardMarkup(one_time_keyboard=True)
        markups.add(types.KeyboardButton('Жанр'))
        await message.answer(f'Хорошо, давай выберем!', reply_markup=markups)
    
    @dp.message_handler(text='Жанр')
    async def choose_genre(message: types.Message):
        markupt = types.InlineKeyboardMarkup()
        for genre in ('Комедия', 'Приключения', 'Драма', 'Фэнтези'):
            markupt.add(types.InlineKeyboardButton(genre, callback_data=genre))
        await message.answer(f'Выбери жанр!', reply_markup=markupt)
    Ответ написан
    Комментировать
  • Как использовать одинаковые данные в разных хендлерах?

    @codingoleg
    1. Глобальные переменные (если не пугает потеря данных).
    2. База данных.
    Ответ написан
    Комментировать
  • Как отправлять список частями в Телеграм-боте?

    @codingoleg
    Не совсем понятно, в чем проблема. У тебя код и так выводит по 3 элемента после ввода 'go'.
    x = ['a', 'b', 'c', 'd', 'e', 'w', 'df', 'ww', 'x', 'qa', 'wsx']
    
    for i in range(0, len(x), 3):
        input('Введи "go" ')
        print(x[i: i + 3])
    print('Выход из цикла')

    В телеграм-боте скорее всего будет реализовано по-другому - рекурсивным вызовом хэндлера, пока список себя не исчерпает. Но большей информации нет.
    Ответ написан
  • Как отправить стикер в телеграм с компьютера?

    @codingoleg
    Отправка файлов и стикеров есть в документации https://core.telegram.org/bots/api#inputfile и https://core.telegram.org/bots/api#sendsticker. Если вы собираетесь больше 1 раза отправлять отдельный стикер, я бы добавил этот стикер в стикерпак и отправлял бы пользователю по ID стикера. Помимо BufferedInputFile можете глянуть соседние FSInputFile и URLInputFile. Вот вам 2 варианта на выбор:
    from aiogram import Bot, Dispatcher, F
    from aiogram import types
    from aiogram.types.input_file import BufferedInputFile
    import asyncio
    
    token = 'ВАШ_ТОКЕН'
    bot = Bot(token=token)
    dp = Dispatcher()
    
    # Открываем файл с компьютера
    with open('photos/photo.webp', 'rb') as file:
        input_file = BufferedInputFile(file.read(), 'any_filename')
    # Или устанавливаем ID стикера
    sticker_id = 'CAACAgIAAxkBAAEKdDVlHm_tbwKnOGandpJwjTBEUXy2zAAC3ggAAgi3GQLYQTVG1h5WQDAE'
    
    @dp.message(F.text == '/start')
    async def send_file(message: types.Message):
        # Загрузка файла с комьютера
        await bot.send_sticker(message.chat.id, input_file)
        # Или отправляем по ID стикера
        await bot.send_sticker(message.chat.id, sticker_id)
    
    asyncio.run(dp.start_polling(bot))
    Ответ написан
    Комментировать
  • Как сделать нормальные глобальные переменные?

    @codingoleg
    Если вас не пугает потеря этих данных, например, из-за перезагрузки бота и прочего, то можно сделать глобальную переменную - словарь. Ключом будет id пользователя или чата, а значением - то, что вы хотите сохранить для него.
    users = {
        12398767: {'name': 'Vasya'},
        98765467: {'name': 'Lena'}
    }
    
    def edit(user_id: int):
        global users
        users[user_id]['name'] = 'Petya'
    
    def read(user_id: int):
        print(users[user_id]['name'])
    
    edit(12398767)
    read(12398767)  # Petya
    print(users)  # {12398767: {'name': 'Petya'}, 98765467: {'name': 'Lena'}}
    Ответ написан
    1 комментарий
  • Как выключить цикл в тг боте?

    @codingoleg
    Для aiogram 2.25.1 я решил этот вопрос через добавление и удаление задач и глобальные переменные. Возможно, костыли, но работает. В данном случае будет запускаться только одна задача, которая проверяется флагом is_running.
    task = Future()
    is_running = False
    
    async def infinite_loop():
        counter = 0
        while True:
            await asyncio.sleep(1)
            print(counter)
            counter += 1
    
    @dp.message_handler(text='вкл/выкл код')
    async def all_message(message: types.Message):
        global task, is_running
        if message.from_user.id == int(ADMIN_ID):
            if is_running:
                await bot.send_message(message.from_user.id, "Код уже запущен")
            else:
                await bot.send_message(message.from_user.id,
                                       "Код запущен, если вы хотите отключить код, то нажмите /off")
                # Создаем задачу
                is_running = True
                task = asyncio.create_task(infinite_loop())
                # Добавляем в пул для выполнения
                await asyncio.gather(task)
    
    @dp.message_handler(commands=['off'])
    async def off_command(message: types.Message):
        global is_running
        if message.from_user.id == int(ADMIN_ID):
            if is_running:
                await bot.send_message(message.chat.id, "Код был остановлен")
                # Отменяем задачу
                task.cancel()
                is_running = False
                # Убираем из пула выполнения
                await asyncio.gather(task)
            else:
                await bot.send_message(message.chat.id, "Код еще не запущен")
    
    executor.start_polling(dp, skip_updates=True)

    Если вам нужно запустить несколько задач (одинаковых или нет) через команду вкл/выкл, просто удалите этот флаг и все проверки, связанные с ним. В этом случае проблема будет только с завершением более 1 задачи. Если нужно будете, напишите сюда.
    Ответ написан
    Комментировать
  • Почему не могу указать элемент из списка как аргумент?

    @codingoleg
    Не могу конкретно по aiogram сказать, но ваши 2 кода различны. Не совсем понятно, что вы хотите сделать. Несколько предположений:
    1. caption=post_data['text'] и caption='text' не эквивалентны. Первое - это значение по ключу 'text', а второе, видимо, сам ключ 'text' (вы не написали, что в словаре). Ошибка может быть из-за того, ему не нравится то, что по ключу 'text' в словаре.
    2. Условие if post_data.get('text') выполнится сразу же, если в словаре в принципе есть ключ 'text' и только 1 раз (или ни разу, если 'text' не в словаре), потому что ключ 'text' будет заменен на None этой строкой post_data['text'] = None. Словарь теперь содержит {..., 'text': None}. Если вы хотите другое поведение, вам нужно другое условие.
    3. Используйте key, value - так понятнее будет. Пример:
    post_data = {'photo': 'some_photo', 'video': 'some_video', 'text': 'some_text'}
    for key, value in post_data.items():
        if post_data.get('text'):
            album.add(type=key, media=value, caption=post_data['text'])
            post_data['text'] = None
        else:
            album.add(type=key, media=value)
    Ответ написан
    Комментировать
  • Как удалить inline keyboard?

    @codingoleg
    Эта ошибка возможна, если вы вызвали функции без аргументов chat_id и/или message_id. Бот не понимает, какое сообщение удалять.
    https://docs.aiogram.dev/en/stable/api/types/messa...

    Попробуйте вместо этого функцию для удаления только клавиатуры (aiogram 2.25.1):
    await callback.message.delete_reply_markup()
    или функцию для удаления и клавиатуры, и сопутствующего ей сообщения
    await callback.message.delete()

    Удалять можно не все сообщения:
    https://core.telegram.org/bots/api#deletemessage
    Ответ написан
    Комментировать