Ответы пользователя по тегу AIOgram
  • Решил попробовать в написание бота для TG, выходит ошибка RuntimeError?

    Vindicar
    @Vindicar
    RTFM!
    Без агрессии нельзя, это же интернет. Если тут не посылают, значит, что-то стряслось. =)

    Основой асинхронной программы является рабочий цикл (event loop). Он должен быть строго один. Я подозреваю, что у тебя создаётся более одного рабочего цикла, так как ты делаешь несколько вызовов get_event_loop() в придачу к asyncio.run().

    Я бы изменил код следующим образом: пусть класс базы данных принимает пул соединений как параметр конструктора. Аналогично, создай в основном файле глобальную переменную, которая будет хранить экземпляр этого класса. При создании присвой переменной None.

    А вот внутри main() уже делай всё остальное: создай экземпляр пула соединений, создать экземпляр класса БД (и закинь его в глобальную переменную), а потом запускай бота. Тогда у тебя все асинхронные операции будут происходить в рамках одного вызова main(), а значит, гарантированно в одном рабочем цикле.
    Ответ написан
    Комментировать
  • Почему не работает apscheduler?

    Vindicar
    @Vindicar
    RTFM!
    Так как ты не показал инициализацию scheduler, то спрошу: scheduler.start() не забыл вовремя вызвать?
    Также есть совет увеличить детализацию логов для скедулера.
    Ответ написан
    Комментировать
  • Не работает aioscheduler, aiogram 3. Как сделать что бы работал?

    Vindicar
    @Vindicar
    RTFM!
    @dp.message(CommandStart())  # обработчик события!
    async def dejur(message: Message):
        ...
    
        aioschedule.every().minute.do(dejur)  # планируем вызов функции

    Запомни раз и навсегда - никогда не вызывай обработчики событий напрямую.
    Если тебе нужно реализовать одну и ту же функциональность и в обработчике, и где-то ещё - вынеси эту функциональность в отдельную подпрограмму, и уже её вызывай и в обработчике, и в других местах.
    В твоём случае можно сделать что-то типа такого:
    async def send_duty_list(chat: int):
        print(1)
        global n,skipper
        if weekday():
            await bot.send_message(chat, text=f"Дежурные: {spisok[n]}")
            if skipper == True:
                if n!=14:
                    n = n+1
                else:
                    n=0
                return n
            else:
                skipper = True
                return skipper
    
    @dp.message(CommandStart())
    async def dejur(message: Message):
        await send_duty_list(message.chat.id)  # шлём ответ в тот же чат, где была команда
    
    
    async def scheduler():
        aioschedule.every().minute.do(send_duty_list, chat=1108995102)  # а тут шлём фиксированному юзеру
        while True:
            await aioschedule.run_pending()
            await asyncio.sleep(1)


    Кроме того, имей ввиду:
    async def on_startup(_):
        asyncio.create_task(scheduler())

    У тебя созданный объект задачи может быть собран сброщиком мусора - что, разумеется, прервёт задачу.
    Так что сохраняй ссылку на задачу куда-нибудь в глобальную переменную.
    scheduler_task = None
    
    async def on_startup(_):
        global scheduler_task
        scheduler_task = asyncio.create_task(scheduler())
    Ответ написан
    Комментировать
  • Как реализовать систему рекомендаций с телеграм боте на aiogram (по типу давинчика)?

    Vindicar
    @Vindicar
    RTFM!
    Наиболее простой способ примерно такой. Ранжируешь пользователей по тому, сколько у них лайков на тех же элементах, которые уже лайкнул ты. Возможно, стоит рассматривать только недавние лайки.
    Затем берёшь из этого списка N первых - они будут "образцами". Усредняешь их лайки, выбираешь наиболее лайкнутые элементы, которые ещё не лайкнул ты. Это и будут рекомендации.
    Ответ написан
  • Как отправить двумерный список через aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Изучай метод str.join(), его вполне достаточно.
    Ответ написан
    Комментировать
  • Как сделать чтобы бот ждал какое-то время, но при этом обрабатывал запросы?

    Vindicar
    @Vindicar
    RTFM!
    asyncio.sleep() вполне хватит.
    Бот должен знать своё состояние ("покой", "сбор игроков", "игра идёт", ну и так далее).
    Один обработчик (начало игры) проверяет, что сейчас состояние "покой", отправляет приглашение, ставит состояние "сбор игроков" и ждёт заданное время. По итогам ожидания проверяет список игроков. Если нужного числа игроков в списке нет, ставит состояние "покой", иначе "игра идёт".
    Второй обработчик (игрок присоединился) проверяет, что сейчас состояние "сбор игроков". Если да, добавляет отправителя в список игроков.

    Как хранить состояние, список игроков и другую игровую инфу, зависит от того, может ли параллельно идти несколько игровых сессий. Если не может, то достаточно простых глобальных переменных. Если может... всё сложнее.
    Ответ написан
    1 комментарий
  • Как правильно передать все параметры в функцию. aiogram3?

    Vindicar
    @Vindicar
    RTFM!
    Вся проблема в том, что мне нужно вызвать функцию "Tsize_3" в ручную

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

    Vindicar
    @Vindicar
    RTFM!
    Увы, под виндой достучаться до менеджера служб куда сложнее.
    Вариант А: оформить бота как службу через утилиту вроде NSSM.
    Тогда для перезапуска можно попробовать выполнить
    cmd.exe /C "net stop имя_твоей_службы && net start имя_твоей_службы"

    Ну или закинуть эту строку в cmd-файл и запускать уже его. Но поскольку подкоманды restart нет, то я не знаю, доживёт ли твой скрипт до выполнения net start.
    Вариант А2: то же самое, но использовать ctypes для обращения к Service Control Manager через WinAPI. Сразу скажу, это сложнее.

    Вариант Б: Очень примитивный, но корявый способ - завернуть запуск бота в батник(cmd-файл), где запускать бота в вечном цикле с ожиданием, и перезапускать его, если бот завершился с ненулевым кодом завершения.
    Что-то типа
    :restart
    python bot.py
    IF ERRORLEVEL 1 GOTO restart

    ERRORLEVEL проверяет, что код завершения больше или равен указанному.
    Тогда, если надо завершить работу бота, делаешь sys.exit(0), а для перезапуска sys.exit(1). Бонус: бот также перезапустится при непойманном исключении.

    Вариант В: Запустить скрипт бота напрямую, скажем, через os.startfile(sys.argv[0]), и сразу же выйти самому. Но приведённый вариант не дружит с виртуальным окружением, так что может потребоваться модификация вроде
    os.startfile('/path/to/venv/python3', 'open', sys.argv[0])
    . Если нужно ещё и параметры командной строки передать, дело усложняется.
    Ответ написан
    Комментировать
  • Как сделать чтоб функция принимала целый класс статусов в aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Вроде ты можешь просто передать желаемый StatesGroup при регистрации команды - так же, как ты регистрируешь команду для конкретного состояния.
    Ответ написан
  • Создание переменных в тг боте аиограм?

    Vindicar
    @Vindicar
    RTFM!
    Словарь, где ключ - id пользователя, а значение - данные, которые ты хочешь хранить для этого пользователя.
    Но такой словарь не переживёт перезапуска бота.
    Ответ написан
  • Как исправить ошибку "IndexError: list index out of range" для чат-бота телеграмм на библиотеке aiogram?

    Vindicar
    @Vindicar
    RTFM!
    А голову включить и код по шагам пройти не пробовал?
    dict_data_user = await state.get_data()
    list_data_user = []  # сначала список пуст
    for k, v in dict_data_user.items():  # начинаем цикл, первая итерация
        list_data_user.append(v)  # добавляем в список элемент. Длина списка равна 1.
        user_id = message.from_user.id
        id_product = list_data_user[0]  # читаем из списка элемент с индексом 0. ОК, он есть, мы его только что добавили
        full_name = list_data_user[1]  # откуда бы взяться элементу с индексом 1 в списке из одного элемента?!
        index_adress = list_data_user[2]
        number_phon = list_data_user[3]
        user_db.add_user(id_product=id_product, user_id=user_id, full_name=full_name,
                         index_adress=index_adress, number_phon=number_phon)
        await state.clear()

    Тут вопрос стоит, ты вообще понимаешь, что пишешь? Ты точно имел ввиду распаковку list_data_user, а не v или ещё чего-нибудь?
    Ответ написан
  • Aiogram3.8.0 Как можно сделать команды, которые будут без префикса не используя startwith?

    Vindicar
    @Vindicar
    RTFM!
    # с пробелом - параметры, без пробела просто совпадение.
    if message.text.startswith('command' + ' ') or message.text == 'command':
        ...

    Ну и разумеется, это надо проверять не деревом if-elif-else, а чем-то более вменяемым, чтобы можно было сразу параметры разбирать.
    Ответ написан
    Комментировать
  • Сообщения отправляются одному человеку хотя должный двум, как сделать так чтобы сообщения отправлялись 2 пользователям?

    Vindicar
    @Vindicar
    RTFM!
    Проверь, не одинаковые ли значения в user_id и poroh.
    Если так, проверяй, откуда берётся значение user_id.

    EDIT: Когда ты нажимаешь на "Да", это отдельное сообщение - отправленное от тебя!
    Т.е. server() вызывается дважды, один раз для запустившего (после выбора карты), второй раз для тебя (ответ да или нет). Это, к слову, несёт в себе ещё одну проблему - если два человека попросят запустить сервер одноврнменно, боту будет тяжело понять, на чей запрос ты ответил.
    Тебе надо использовать не ReplyKeyboardMarkup, а InlineKeyboardMarkup, так как там можно привязать к кнопке дополнительную инфу (строку), по которой бот сможет потом понять, к какому сообщению относилась кнопка.
    Ответ написан
  • Выдаёт ошибку в коде. Как исправить?

    Vindicar
    @Vindicar
    RTFM!
    Какая версия aiogram установлена? Точно та же, для которой написан код?
    Потому что есть подозрение, что не та.
    Ответ написан
    Комментировать
  • Как отправить сообщение в указанное время с помощью isoweekday из библиотеки datetime?

    Vindicar
    @Vindicar
    RTFM!
    dt_string = now.strftime("%d/%m/%Y %H:%M:%S")   # метка времени вида дд/мм/гггг чч:мм:сс
    if (dt_string == "19:04:00") and x == 6:  # ВНЕЗАПНО метка времени вида чч:мм:сс, дата куда-то пропала

    Что ты ожидал-то? =)

    А вообще, aioschedule в помощь, если у тебя будет несколько таких напоминашек.
    Там достаточно один раз наладить запуск рабочего цикла aioschedule, и дальше просто планировать что делать.
    Ответ написан
    7 комментариев
  • Почему возникает ошибка TypeError: 'Item' object is not iterable?

    Vindicar
    @Vindicar
    RTFM!
    У тебя get_category_item() возвращает только один предмет из категории, а ты думаешь, что она возвращает коллекцию предметов. Хотя ты сам делаешь scalar.
    Ответ написан
    Комментировать
  • Как реализовать изменение данных анкеты в БД через inline клавиатуру в телеграм боте?

    Vindicar
    @Vindicar
    RTFM!
    1. Если пользователь должен отправлять данные как текст сообщения, тебе нужен finite state machine (FSM). В aiogram уже есть реализация, почитай и погугли примеры.
    2. Никогда не формируй SQL запросы f-строками - слишком легко ошибиться, да и небезопасно.
    Ответ написан
    Комментировать
  • Можно ли и каким образом прописать команду telegram-боту обрабатывать только определенные изображения (скрины,документы), а остальные игнорировать?

    Vindicar
    @Vindicar
    RTFM!
    Простого способа нет. Метаданные могут кое-что подсказать - некоторые форматы изображений содержат комментарии, например, каким ПО файл был создан. Но метаданные могут отсутствовать или быть некорректными.
    Не говоря уже о том, что ваше определение "скриншоты, документы" - ОЧЕНЬ расплывчатое. Фотография экрана - это скриншот? А с точки зрения метаданных она будет неотличима от просто фотки. Фотография девушки с паспортом в руках - считается документом или нет?

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

    Vindicar
    @Vindicar
    RTFM!
    Надо хоть немножечко осознавать, как работает asyncio.
    create_task() возвращает объект класса Task, представляющий собой фоновую задачу. Эта задача уже запланирована к выполнению в рабочем цикле (loop) asyncio, и будет выполняться в фоне пока текущая корутина ожидает какой-нибудь другой операции.

    Но если тебе надо дождаться завершения работы задачи, ты можешь сделать await на этом объекте.
    Тогда текущая корутина приостановится, пока задача не завершится, и получит или возвращённое задачей значение, или выкинутое задачей исключение.
    А теперь посмотри на свой код:
    await asyncio.create_task(start_checking_price(1800))

    Ты создаёшь задачу - и тут же говоришь программе, что тебе надо дождаться её завершения!
    Ну как бы программа и делает в точности то, что ты от неё требуешь...
    Подчёркиваю красным: await asyncio.create_task(some_coro(...)) не имеет смысла практически никогда! Если тебе нужно запустить корутину и дождаться результата, делаешь просто await some_coro(...).
    А вот если тебе нужно запустить корутину параллельно текущей... Получится что-то типа такого:
    # ...
        check_task = asyncio.create_task(start_checking_price(1800))  # нету await, мы не ждём созданную задачу!
    
        try:
            await dp.start_polling()
        finally:
            check_task.cancel()  # отменяем корутину
            # внутри start_checking_price() текущий выполняемый await выкинет исключение CancelledError
            # это исключение всплывёт наружу, если мы сделаем await, и позволит отработать 
            # блокам finally, with и т.п. инструментам. Также можно явно поймать это исключение,
            # чтобы обработать отмену корутины. Но в твоём случае это не требуется.
            try:
                await check_task  # даём корутине отработать завершение
            except asyncio.CancelledError:  # ловим всплывшее CancelledError
                pass  # всё ок, никакие действия не требуются
            await my_bot.close()
    Ответ написан
    7 комментариев
  • Как сделать после ввода сообщения выполнение функции в aiogram?

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