Ответы пользователя по тегу AIOgram
  • Как сделать после ввода сообщения выполнение функции в aiogram?

    Vindicar
    @Vindicar
    RTFM!
    У тебя две функции, которые заявляют "я могу обработать любое сообщение". aiogram использует первую из них, потому что как иначе он поймёт, когда какую использовать?
    Почитай про Finite State Machine и как их использовать в aiogram.
    Ответ написан
    Комментировать
  • Как получить user.id боту aiogram 2.23.1 через ответ на сообщение?

    Vindicar
    @Vindicar
    RTFM!
    Из постановки задачи: тебе надо работать с сообщением, так?
    Открываешь документацию и ищешь класс, описывающий сообщение. Подсказка: обычно такой класс называется Message.
    Внимательно просматриваешь его свойства и методы, ищешь всё, что касается ответов (ключевые слова: reply, response и т.п.).
    Находишь свойство reply_to_message. Читаешь:
    reply_to_message: Message | None
    Optional. For replies in the same chat and message thread, the original message. Note that the Message object in this field will not contain further reply_to_message fields even if it itself is a reply.

    Тип данных (Message | None) и подсказка Optional говорят о том, что в этом поле может лежать либо None (очевидно, если сообщение не является ответом), либо ещё один объект Message (тогда это сообщение, на который был ответ).
    Теперь как разобраться с автором сообщения. Аналогично ищем свойства и методы класса Message по ключевым словам user, author и т.п. Находим свойство from_user.
    from_user: User | None
    Optional. Sender of the message; empty for messages sent to channels. For backward compatibility, the field contains a fake sender user in non-channel chats, if the message was sent on behalf of a chat.

    Достаточно, чтобы понять, что в этом свойстве должен лежать объект, описывающий автора сообщения.

    Теперь осталось собрать вместе логику работы бота:
    1. Бот получает уведомление о сообщении
    2. Бот проверяет, было ли сообщение отправлено в тот чат, где он должен работать (свойство chat)
    3. Бот проверяет, отправлено ли сообщение тобой (свойство from_user)
    4. Бот проверяет, является ли сообщение ответом (свойство reply_to_message)
    5. Бот получает оригинальное сообщение и извлекает его отправителя
    6. Бот банит этого отправителя

    Как забанить пользователя - упражнение для читателя.
    Учись искать и разбираться в документации, без этого навыка никуда.
    Ответ написан
    4 комментария
  • Как отправлять сообщения по расписанию с aiogram3?

    Vindicar
    @Vindicar
    RTFM!
    Открываем страницу пакета, читаем пример.
    В конце видим рабочий цикл aioschedule, где периодически вызывается корутина aioschedule.run_pending().
    У тебя этого нет. Т.е. ты планируешь вызов своей корутины, но не выполняешь код, который этот вызов сделает.
    Поскольку у тебя scheduler() вызывается через create_task(), то можно прямо в тело scheduler() дописать что-то типа
    while True:
        await aioschedule.run_pending()
        await asyncio.sleep(0.1)

    Вот только зачем ты делаешь await create_teask()? Это убивает смысл create_task(), так как ты ждёшь завершения созданной фоновой задачи. Вместо этого сохрани таск в глобальную переменную - так он точно не будет собран сборщиком мусора, и ты сможешь при необходимости вызвать метод cancel(), чтобы прервать цикл внутри scheduler().
    Ответ написан
  • Как запустить функцию вместе с ботом aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Во-первых, переводим слово "warning". Это не ошибка, это предупреждение.
    Во-вторых, погуглить не пробовал?
    В ранних версиях asyncio get_event_loop() создавал рабочий цикл asyncio, если он ещё не был создан, и возвращал существующий, если он был. Потом от этого поведения решили отказаться. Пока что оно ещё работает, но потом сломается.
    Так что в начале программы используй new_event_loop(), а если нужно получить ссылку на цикл в корутине - get_running_loop()

    И я удивлюсь, если окажется, что ошибка именно в этом. У тебя где-то ещё должен быть косяк. Скорее всего одна из запускаемых корутин выполняет длительную операцию синхронно.
    Ответ написан
  • Почему код работает не так как нужно?

    Vindicar
    @Vindicar
    RTFM!
    А почему он не должен этого делать? У тебя asd() объявлена, но нигде не упоминается и не вызывает, так что бот о ней ничего не знает.
    Ответ написан
  • Как сделать параллельный цикл aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Выносишь цикл проверки в отдельную корутину check_loop(), в main() делаешь
    async def main():
        logging.basicConfig(level=logging.INFO)
        async with ClientSession() as session:  # сессию лучше по сто раз не создавать
            check_task = asyncio.create_task(check_loop(session))  # создай её однажды и передай в check_loop
            try:
                bot = Bot(
                    token='"'
                )
                await dp.start_polling(bot)
            finally:
                check_task.cancel()  # внутри check_loop() сгенерируется прерывание asyncio.CancelledError

    Единственное, придётся в коде/конфиге прописать id чата, куда check_loop() будет отправлять сообщение с результатами.
    Ответ написан
    Комментировать
  • Отправка сообщения aiogram в произвольной функции без handler использовав существующий bot?

    Vindicar
    @Vindicar
    RTFM!
    Очевидно, хранить существующего бота где-то. Или в глобальной переменной, или переделать функцию в метод класса и хранить ссылку на бота в поле класса. Главное, чтобы эта ссылка была в поле видимости твоего кода.

    Но я бы заметил, что слишком частое редактирование сообщения - не лучшая идея. Я бы разбил процесс на две части - обработчик обновлений от OpenAI складывает в какой-то буфер полученные части текста, а бот время от времени проверяет буфер и дописывает всё, что там лежит, в сообщение.
    Ответ написан
    1 комментарий
  • Как вывести значения таблицы SQLite3 в inline-кнопках?

    Vindicar
    @Vindicar
    RTFM!
    А ты прочитай свой код внимательно.
    @router.message(F.text == 'Каталог')
    async def catalog(message : Message):
        categories_kb = InlineKeyboardBuilder()
        categories = db.get_group_name_from_db()
        for category in categories:
            categories_kb.add(InlineKeyboardButton(text=categories, callback_data=f'category_'))  # чему-чему равен text?
        return categories_kb.adjust(2).as_markup()  # ты же понимаешь, что строка ниже не выпонится?
    
        await message.answer('Выберите категорию товара:', reply_markup=await categories)  # что ещё за await? categories - это список.
        # или ты имел ввиду categories_kb?
    Ответ написан
    5 комментариев
  • Как float данные из БД добавить в массив и найти самое близкое число к числу из БД?

    Vindicar
    @Vindicar
    RTFM!
    Тебе не нужно вычитывать все данные из БД, чтобы потом искать их на питоне - задача прекрасно решается в рамках SQL запроса.
    Если под "самым близким" числом ты понимаешь самое близкое по модулю, то задача звучит так: найти в таблице число, модуль разности которого с заданным числом минимален.
    Например, если у нас таблица Numbers, в которой есть столбец num, содержащий искомые числа, то запрос будет иметь вид:
    SELECT * FROM Numbers ORDER BY ABS(num - заданное_число) ASC LIMIT 1

    Т.е. мы для все строк в Numbers рассчитываем разность между num и заданным числом, находим модуль, сортируем по возрастанию этого модуля (т.е. сортируем числа от близких к далёким), а потом берём первый (т.е. самый близкий) результат.

    К своему коду адаптируешь самостоятельно.
    Ответ написан
    3 комментария
  • Ошибка в aiogram :'cannot import name 'executor' from 'aiogram'', почему?

    Vindicar
    @Vindicar
    RTFM!
    Под какую версию aiogram код, и какая версия установлена у тебя? aiogram изменил API при переходе с версии 2 на версию 3.
    Ответ написан
    Комментировать
  • Как в машинном состоянии принимать несколько файлов?

    Vindicar
    @Vindicar
    RTFM!
    await FileSendingGroup.next() выполняет переход на следующее состояние.
    Если ты можешь понять, когда пользователь послал последний файл, выполняй этот переход только тогда.
    Ответ написан
  • Как сравнить пустое значение из БД?

    Vindicar
    @Vindicar
    RTFM!
    Учи матчасть. Всё делается одним запросом.
    SELECT referal_id, COUNT(*) FROM users GROUP BY referal_id

    Группировка сделает так, что для каждого referal_id будет выведена одна строка, а групповые функции посчитают некий итог для каждой группы строк с одним и тем же значением referal_id. В частности, COUNT() посчитает сколько строк в группе.
    Ответ написан
    Комментировать
  • Как отправить аудиофайл в боте телеграм Python?

    Vindicar
    @Vindicar
    RTFM!
    Сначала проверь путь. Ты указываешь относительный путь к файлу, а он рассчитывается исходя из текущей рабочей директории. Которая может совпадать или не совпадать с директорией где лежит скрипт, это зависит от способа запуска скрипта.

    Так что лучше ориентируйся так. sys.argv[0] содержит путь к скрипту, а модуль pathlib позволяет манипулировать путями.
    import sys
    from pathlib import Path
    
    BASE_DIR = Path(sys.argv[0]).parent.resolve()  # каталог скрипта
    AUDIO = BASE_DIR / 'audio.mp3'  # файл в каталоге скрипта
    #......
    async def send_songs(message):
        await message.answer("Hello!")
        await message.answer("World!")
        audio = AUDIO.open('rb')
        await bot.send_audio(message.chat.id, audio)
    Ответ написан
  • Как сохранить форматирование текста в боте Aiogram?

    Vindicar
    @Vindicar
    RTFM!
    У тебя какая версия aiogram, вторая или третья?
    Если вторая, то смотри параметр parse_mode у send_message().
    parse_mode (typing.Union[base.String, None]) – Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot’s message.


    Насчёт третьей версии я не в курсе, но наверняка тоже надо parse_mode указать.
    Ответ написан
  • С чем может быть связана ошибка "asyncio.exceptions.CancelledError"?

    Vindicar
    @Vindicar
    RTFM!
    Открой доки и почитай. CancelledError выбрасывается в корутине, когда она завёрнута в таск через create_task() и на этом таске вызван метод cancel(). Это позволяет прервать выполнение корутины через выбрасывание специального исключения. Исключение не наследуется от Exception, поэтому обычный try-except его не ловит, если только специально не указать try ... except CancelledError. Так сделано, потому что при выходе через всплывание исключения будут отрабатывать все нормальные питоновские механизмы: блоки finally, блоки with и так далее.
    Я полагаю, команда на остановку бота делает cancel() на его главной корутине, скорее всего запущенной внутри start_polling(). Это исключение всплывает в твой main(). Но поскольку main() выполняется в asyncio.run(), то исключение всплывает туда. Это исключение не имеет особого смысла вне asyncio, так что я полагаю, run() ловит это исключение и вместо него выбрасывает KeyboardInterrupt() как ближайший не-асинхронный эквивалент. Это исключение всплывает на верхний уровень и останавливает интерпретатор.

    Ты можешь ловить CancelledError в main(), чтобы спокойно завершить работу бота. Ну или ловить KeyboardInterrupt() в теле скрипта, на вызове asyncio.run().
    Ответ написан
    2 комментария
  • Почему асинхронный телебот увеличивает кол-во потоков?

    Vindicar
    @Vindicar
    RTFM!
    while True:
                print(1)
                await asyncio.sleep(1)

    Корутина может выполняться в нескольких экземплярах параллельно. У тебя в коде вечный цикл, поэтому старые запущенные экземпляры никогда не завершаются, так что при запуске новых у тебя появляется всё больше и больше экземпляров.
    Ответ написан
  • Как исправить повторную отправку сообщения телеграм бота в коде Python Aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Включи голову и пройди программу по шагам.
    # Функция отображения 
    async def show_pages(chat_id, page):
        ...
        # тут ты отправляешь сообщение!
        sent_message = await bot.send_message(chat_id, text='Выберите страницу:', reply_markup=keyboard)
        return sent_message.message_id
    
    # Обработчик кнопок
    async def callback_handler(query: types.CallbackQuery):
        ...
        message_id = await show_page(query.message.chat.id, page=current_page)  # <-- show_page() отправляет сообщение!
        # Редактируем сообщение вместо отправки нового <-- не вместо, а после отправки нового
        await bot.edit_message_text(chat_id=query.message.chat.id, message_id=query.message.message_id, text='Выберите страницу:',
                                    reply_markup=InlineKeyboardMarkup())  # <-- сносишь клавиатуру у старого сообщения


    Я бы переписал show_page() так, чтобы она возвращала подготовленную для пагинации клавиатуру, а потом уже эту клавиатуру использовал в коде, который show_page() вызывает.
    Альтернативно, переделай show_page() так, чтобы она всегда редактировала переданное ей существующее сообщение. Тогда при первом показе ты сначала отправляешь "Подождите..." а потом это сообщение отдаёшь для переделки show_page(). При последующих ты переиспользуешь это сообщение.
    Но нужно иметь ввиду - вроде есть лимит времени на правку сообщения.
    Ответ написан
    Комментировать
  • Почему бот не реагирует на inline клавиатуру?

    Vindicar
    @Vindicar
    RTFM!
    Почему ru_bot() вообще отдекорирован как обработчик события, если ты эту функцию вызываешь вручную?
    И, самое главное, откуда в модуле ru берётся dp, и тот ли это dp, что и в main?

    Я подозреваю, что не тот, а свой собственный. Тогда не удивительно, что регистрация обработчиков в нём не имеет эффекта...

    Если это так

    Переделай импортируемые модули так, чтобы в них можно было передать объект dp из main. Например, так:
    # ru.py
    
    def setup(dp):
        @dp.message_handler()
        async def ru_bot(message: types.Message):  # да, эти функции описаны внутри setup()
            ...
    
        @dp.callback_query_handler()
        async def handle_callback_ru(callback_query: types.CallbackQuery):
            ...
    
    # main.py
    
    dp = ...  # создаёшь диспетчер бота
    import ru
    ru.setup(dp)  # регаешь обработчики из ru
    ...  # запускаешь бота


    Ответ написан
  • Finite State Machine Python, как вызвать функцию с переменной state?

    Vindicar
    @Vindicar
    RTFM!
    У тебя проблема молотка.
    С 99% вероятностью тебе не нужно вызывать такие функции, они являются обработчиками событий и вызываются самим фреймворком aiogram. Если тебе нужно повторно использовать код в таком обработчике, вынеси его в отдельную функцию, которая не работает ни с состоянием, ни с событием.

    Допустим, у тебя есть код:
    @state_router.message(MyState.stateA)
    async def process_stateA(message: Message, state: FSMContext) -> None:
        data = await state.get_data()
        result = message.text + str(data['some_key'])  # это типа логика обработки
        await message.reply(result)

    Его надо будет отрефакторить так:

    def do_stuff(msgtext: str, some_value) -> str:
        return msgtext + str(some_value)
    
    @state_router.message(MyState.stateA)
    async def process_stateA(message: Message, state: FSMContext) -> None:
        data = await state.get_data()
        result = do_stuff(message.text, data['some_key'])
        await message.reply(result)

    И тогда ты сможешь при необходимости вызвать снова do_stuff(), не трогая process_stateA().
    Ответ написан
    1 комментарий
  • Как вызвать функцию, чтобы код (бот) продолжал работу?

    Vindicar
    @Vindicar
    RTFM!
    Загони код распознвания речи в отдельный поток с помощью asyncio.get_event_loop().run_in_executor()
    Ответ написан
    4 комментария