Ответы пользователя по тегу Telegram
  • Зачем нужен декоратор @dp и все в этом духе, типо @dp.message_handler() в aiogram?

    Vindicar
    @Vindicar
    RTFM!
    На пальцах: чтобы бот работал, его функции должны вызываться при наступлении определённых событий (например, входящего сообщения). Проблема в том, что aiogram знает о возможных событиях, но ему нужно сказать, какие функции когда вызывать. Обычно это называется "зарегистрировать обработчик".
    В питоне функции - объекты первого рода, т.е. их можно сохранять в переменные, передавать как параметры, возвращать как результат и вообще поступать с ними как с любым другим значением.
    Т.е. по идее можно было бы сделать так:
    async def echo(message: Message):
        text = f"Привет, ты написал {message.text}"
        await bot.send_message(chat_id=message.from_user.id, text=text)
    
    dp.register_function_for_message(echo)  # это не настоящий метод aiogram, только пример

    Тогда каждому объявленному обработчику событий соответствовал бы вызов метода, ответственного за регистрацию этого обработчика.

    Но то же самое можно сделать через декораторы. Декоратор - это сокращённый вызов функции, которая принимает в качестве параметра другую функцию.
    Т.е. вот это
    @dp.message_handler()
    async def echo(message: Message):
        text = f"Привет, ты написал {message.text}"
        await bot.send_message(chat_id=message.from_user.id, text=text)

    абсолютно эквивалентно вот этому
    _decorator = dp.message_handler()
    
    async def echo(message: Message):
        text = f"Привет, ты написал {message.text}"
        await bot.send_message(chat_id=message.from_user.id, text=text)
    
    echo = _decorator(echo)

    Как видишь, очень похоже на "простую" регистрацию обработчика, но записывается чуть короче.
    Ответ написан
  • В pythonanywhere запускаю код телеграм бота, но выдает ошибку. Все библиотеки установлены. Когда запускаю код в PyCharm все работает. Как ее решить?

    Vindicar
    @Vindicar
    RTFM!
    Читай документацию и правила ресурса, на котором хостишься!
    pythonanywhere не позволяет коннектиться куда попало. У них есть белый список сайтов, и даже сайты из белого списка доступны только если ты используешь их прокси. Адрес прокси proxy.server:3128 (это приватный адрес, доступный только изнутри сети pythonanywhere). Как настроить прокси в aiogram - гугли.
    Ответ написан
    Комментировать
  • Telegram bot, отправка текущего времени в сообщении?

    Vindicar
    @Vindicar
    RTFM!
    Модуль datetime в помощь. В частности, класс datetime.datetime, его методы now() и strftime().
    Только нужно иметь ввиду, что этот класс вернёт текущее время по часам того компа, на котором запущен бот, а не по часам клиента.
    Ответ написан
    Комментировать
  • Как сделать так, чтобы при появлении нового файла в папке, он отправлялся в telegram bot?

    Vindicar
    @Vindicar
    RTFM!
    1. Запусти бота.
    2. Задействуй пакет watchdog
    3. В обработчике событий watchdog проверяй, что событие нас интересует, и говори боту отправить файл.
    Ответ написан
    Комментировать
  • Как реализовать отправку сообщения ботом при обновлении бд?

    Vindicar
    @Vindicar
    RTFM!
    pochka3648, сделай своё API. Например, первый бот слушает сокет, второй к нему коннектится, и пишет в сокет данные.
    Если не требуется мгновенное оповещение, пусть первый бот периодически проверяет таблицу на наличие новых записей.
    Ответ написан
    Комментировать
  • Почему не работает код дальше?

    Vindicar
    @Vindicar
    RTFM!
    dp.register_callback_query_handler(go1, lambda call: True)

    Потому что ты сказал "А всё, что не обрабатывается вышележащими обработчиками, пускай обрабатывает go1". Как следствие, до go2 дело не доходит.
    Чини lambda call: ..., чтобы правильно определял, какие события отдавать go1.
    Ответ написан
    Комментировать
  • Как сделать что бы бот выдавал сколько пользователь в боте?

    Vindicar
    @Vindicar
    RTFM!
    В обработчике команды /start записывать в базу текущую дату (например, в виде timestamp).
    По запросу узнать текущую дату, получить дату из базы, вычесть, перевести в дни.
    См. модуль datetime.
    Ответ написан
    Комментировать
  • Как узнать и зафиксировать время, когда пользователь нажал inline-кнопку?

    Vindicar
    @Vindicar
    RTFM!
    Использовать time.time() не хочется, чтобы избежать конфликта с Телеграм при неправильно установленном времени на локальной машине пользователя.

    Тогда только спрашивать время у какого-то доверенного сервера, по NTP или иному протоколу.
    Ответ написан
  • Как продолжить работу бота?

    Vindicar
    @Vindicar
    RTFM!
    Потому что надо документацию читать, и понимать, за что отвечает параметр func в callback_query_handler(), а не перепечатывать с ютуба.
    Для общего понимания можешь глянуть мой старый ответ.
    Если коротко, ты сам сказал телеботу, что full_calc() должна обрабатывать ВСЕ нажатия на кнопки.
    Ответ написан
  • Почему возникает ошибка в telethon?

    Vindicar
    @Vindicar
    RTFM!
    Вообще не разбираюсь в асинхронных вещах.

    Откладываешь бота, разбираешься как следует, возвращаешься к боту. Без понимания этого механизма бота сложнее hello world не написать.

    В чем может быть дело?

    Для работы асинхронного кода он должен быть запущен через рабочий цикл (т.н. реактор, в терминах asyncio - event loop). Этот цикл обычно занимает тот поток, где он создан, и поочерёдно планирует выполнение вызванных корутин (async функций). Когда корутина делает await-вызов, она приостанавливается, а реактор занимается другими делами (в частности, выполняет этот вызов), пока вызов не завершится. После чего корутина продолжает работу.
    asyncio создаёт реактор автоматически для главного потока, но не для вспомогательных потоков. Просто потому, что обычно весь код асинхронного приложения работает в рамках реактора, а иметь несколько реакторов в разных потоках - это извращение. Но если очень нужно, ты можешь вызвать asyncio.new_event_loop() в твоём новом потоке, чтобы создать реактор, а потом задать этот реактор для потока вызовом asyncio.set_event_loop() (в этом же потоке). И только после этого запускать там асинхронный код.
    Ответ написан
    Комментировать
  • Как в telegram bot после каждого сообщения пользователя обновлять время в бд?

    Vindicar
    @Vindicar
    RTFM!
    Почитай про INSERT ... ON CONFLICT UPDATE.
    Ответ написан
    Комментировать
  • Телеграм-бот. Как сохранить второе сообщение от пользователя?

    Vindicar
    @Vindicar
    RTFM!
    У тебя должен быть отдельный обработчик входящих сообщений, а не часть обработчика нажатия на кнопку..
    При этом бот должен помнить, ведёт ли данный пользователь игру в настоящий момент, или нет.
    Ответ написан
  • Из за чего команда 9Abelora выполняется первее чем raspisanie?

    Vindicar
    @Vindicar
    RTFM!
    Изучай документацию, а не "уроки" с ютуба.
    @bot.callback_query_handler(func=lambda call: True)
    def callback_inline(call):
       ...

    func принимает функцию, которая должна по параметру call (сведения о нажатии кнопки) определить, будет ли данный обработчик обрабатывать это нажатие. Соответственно, функция вида lambda call: True всегда будет отвечать "да, я буду обабатывать!".

    При этом бот вызовет первый "согласившийся" обработчик, и ТОЛЬКО его. Как следствие, наличие одного обработчика с func=lambda call: True блокирует все нижележащие обработчики, так как этот "всеядный" обработчик будет брать на себя все нажатия кнопок (независимо от того, понимает ли он их). До остальных обработчиков дело просто не дойдёт.

    Чтобы это разрулить, надо прописывать не lambda call: True, а функцию, которая реально будет различать, какой набор кнопок у пользователя, и какая кнопка была нажата. Самый простой способ это сделать - сделать этакую иерархию в строке call.data. Например:
    9a.tomorrow
    9a.week
    9a.today
    10a.tomorrow
    10a.week
    10a.today

    Тогда ты сможешь прописать обработчики вида:
    @bot.callback_query_handler(func=lambda call: call.data.startswith('10a.'))
    def callback_inline_for_10a(call):
       ...  # тут обрабатываем кнопки для 10А
    
    @bot.callback_query_handler(func=lambda call: call.data.startswith('9a.'))
    def callback_inline_for_9a(call):
       ...  # тут обрабатываем кнопки для 9А


    Ну а создание кнопок, соответственно, будет иметь вид
    item1 = types.InlineKeyboardButton("Домашнее задание на завтра", callback_data='10a.tomorrow')
    Ответ написан
    4 комментария
  • Не отправляются фотографии пользователю в библеотеке telebot, что делать?

    Vindicar
    @Vindicar
    RTFM!
    def raspisanie(message):
    def raspisanie(call):
    Ничего странного не замечаешь?
    Ответ написан
  • Как отправить сообщений в определенное время telebot?

    Vindicar
    @Vindicar
    RTFM!
    телебот - это синхронная библиотека. Он не предусматривает длительной работы обработчиков.
    Так что тебе придётся выносить ожидание момента (тот же пакет schedule) в отдельный поток.
    Но я без понятия, безопасно ли обращаться к методам telebot из других потоков.
    Ответ написан
  • Возможно-ли добавить в бота телеграмм (pyTelegramBotAPI), подставление картинки поверх основной картинки?

    Vindicar
    @Vindicar
    RTFM!
    Возможно.
    За готовым кодом - на фриланс. Сюда - с конкретными вопросами по реализации.
    Ответ написан
  • Как обслуживать юзеров по очереди телебот?

    Vindicar
    @Vindicar
    RTFM!
    global user_id
    Ну как бы вот виновник. Глобальные переменные. Они общие на всего бота и на всех пользователей. Если тебе нужно дифференцировать пользователей - делай это сам.
    Делай хранилище "ключ-значение", где ключ - ID пользователя, значение - хранимые для этого пользователя данные. При обработке сообщения читай ID пользователя, доставай из хранилища данные, и уже сообразно им обрабатывай сообщение.
    Таким хранилищем может быть простой словарь (если не нужно сохранять состояние между перезапусками бота), БД или ещё что.

    Не знаю, есть ли в telebot реализация Finite State Machine, но обычно для реализации сценариев используют её. Идея та же - для каждого юзера храним его текущее состояние (шаг в сценарии) и ассоциированные с ним данные.
    Ответ написан
    2 комментария
  • Как реализовать запись следующего сообщения?

    Vindicar
    @Vindicar
    RTFM!
    На гитхабе вариант с несколькими стейтсами, а мне нужен один.

    В приведённом примере явно два состояния - ожидание фразы "ввести имя" и ожидание собственно имени. Одним тут не обойдёшься. Или изменяй сценарий (нафиг вообще вводить фразу "ввести имя"?) или используй два состояния.
    Ответ написан
    Комментировать
  • Как создать список из картинок и текста и выводить рандомным способом?

    Vindicar
    @Vindicar
    RTFM!
    Ну про random.choice() ты знаешь. В чём проблема-то?
    Если нужно соответствие картинки и текста, то просто храни текст и картинку одним элементом списка - например, через кортеж.
    tarot_list = [
        ('image1.jpg', 'Текст 1'),
        ('image2.jpg', 'Текст 2'),
    ]

    Тогда потом просто делаешь:
    image, text = random.choice(tarot_list)
    и вперёд!
    Ответ написан