Ответы пользователя по тегу TeleBot
  • Как взять фото из SQLite и отправить через телеграм бота?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Для начала, картинки - бинарные файлы. Какой тип у поля в базе данных? Если текстовый - поздравляю, картинки уже побились необратимо.

    После пересоздания базы с нужным типом данных у этого поля (BLOB) придётся заново загрузить все файлы.

    А теперь самое главное: хранить файлы в базе - плохая идея. Правильно хранить их отдельно как файлы в файловой системе, а в базе хранить имя файла. Рекомендую сразу же переделать.
    Ответ написан
    3 комментария
  • Нужна помощь/совет - Telegram бот?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В pythonanywhere в бесплатном тарифе доступен ограниченный список сайтов https://www.pythonanywhere.com/whitelist/
    Ответ написан
    Комментировать
  • Как динамически изменять InlineButton?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Существует метод bot.edit_message_text, которым можно отредактировать ранее отправленное сообщение. Соответственно, редактируем, передавая старый текст (если его не надо менять) и новую клавиатуру.

    Примеров в интернетах много, вон хотя бы в моём личном боте: https://github.com/shurshur/glagolitic-bot/blob/ma...
    Ответ написан
    Комментировать
  • Почему хандлер не срабатывает повторно?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Этот бот очень странно написан, и вообще непонятно, как в нём хоть что-то работает.

    Начнём с того, что вот это:

    global operator
    operator = call.message.chat.id


    будет означать, что в переменной operator всегда будет id чата последнего оператора, нажавшего кнопку join_dialog_btn. Аналогично будут проблемы с user_help_id. В итоге не будет это одновременно работать ни с несколькими операторами, ни с несколькими пользователями.

    Далее, НЕ НАДО создавать в функции другие функции без чёткого понимания, зачем это нужно, и тем более не надо их оборачивать регистрирующими декораторами. Это работает совсем не так, как кажется.

    Когда оператор Вася получит своего первого пользователя, будет вызван декоратор @bot.message_handler(func=lambda message: message.from_user.id == Вася). После того, как Вася отработает по пользователю и получит следующего, будет создан ещё один обработчик с таким же декоратором, но так как один такой обработчик (с такими условиями) уже в цепочке есть, то будет вызван первый, который полагается на локальные переменные от предыдущего вызова supportWait. Довольно заметно, что ты с этим уже сталкивался и именно поэтому локальные переменные (operator и user_help_id) сделал глобальными, но это, разумеется, не поможет, так как абсолютно неправильно.

    Что тут надо сделать?

    1. Вынести все обработчики на верхний уровень и избавиться от дурной практики регистрации их через декораторы внутри функции каждый раз при их вызове.

    2. Отделить логику оператора от логики пользователя - это следует делать отдельными обработчиками со своей логикой.

    3. Где-то хранить соответствие chat_id пользователя - chat_id назначенного оператора. Можно завести словарь, но в целом можно и через FSM Телебота (но тогда нельзя будет отслеживать, что пользователя уже кто-то взял).

    4. Не забывать, что пользователь может успеть оставить несколько сообщений до того, как оператор примет запрос - их все нужно не потерять.

    Можно сделать примерно так:

    spoiler
    operator_ids = [список id операторов]
    
    @bot.message_handler(func=lambda message: message.chat.id in operator_ids)
    def handle_operator_message(message):
    # обработка сообщения оператора в состоянии, когда ему ничего не назначено
    # можно например ругнуться чтобы ждал появления обращений
    
    # состояния пользователей, в частности чтобы накапливать сообщения от начала обращения
    # до назначения оператора
    user_states = {}
    
    @bot.message_handler(func=lambda message: True)
    def handle_user_message(message):
    # обработка сообщения пользователя в состоянии, когда он только что обратился
        # посылаем сообщение с кнопкой всем операторам
        # (задача со звёздочкой: всем операторам, у которых никто не назначен)
        # в кнопке передаём callback_data=join_dialog_btn:CHAT_ID_ПОЛЬЗОВАТЕЛЯ
        # запоминаем сообщение
        user_states[message.chat.id] = {"messages":[message]}
        # затем регистрируем отдельный обработчик
        bot.register_next_step_handler(message, handle_user_unassigned)
    
    # обработчик собирает сообщения пользователя
    def handle_user_unassigned(message, user_data):
        user_states[message.chat.id]["messages"].append(message)
    
    # обработчик сообщений пользователя после назначения оператора
    # этот обработчик выставится из обработчика сообщения оператора.
    # используя register_next_step_handler_by_chat_id
    def handle_user_assigned(message, operator_id):
        # посылаем сообщение оператору (operator_id)
    
    def handle_operator_assigned(message, user_id):
        # посылаем сообщение юзеру (user_id)
    
    # в кнопке передаётся chat_id пользователя
    # в принципе, можно в кнопку засунуть больше данных, в том числе json до 64 символов
    @bot.callback_query_handler(func=lambda call: call.data.startswith('join_dialog_btn:'))
        user_chat_id = int(call.data.split(":")[1])
        for operator_id in operators_id:
            if operator_id != call.chat.id:
                 # посылаем остальным операторам "пользователя взял в работу оператор Вася"
        # также выплёвываем все накопленные сообщения пользователя этому оператору
        for msg in user_states[user_chat_id]["messages"]:
             # тут делаем forward_message
        # выставляем обработчик оператору
        bot.register_next_step_handler(message, handler_operator_assigned, user_chat_id)
        # теперь надо переключить пользователя на оператора, используя его chat_id
        bot.register_next_step_handler_by_chat_id(user_chat_id, handle_user_assigned, call.chat.id)
        # обрати внимание, что это выставляет обработчик юзеру, а не оператору!
    
    # в итоге всей этой конструкции в чате operator_id действует обработчик handle_operator_assigned
    # с параметром user_id, а в чате user_id - handle_user_assigned с параметром operator_id, и можно
    # в них сразу посылать полученные сообщения (только не forward_message, конечно,
    # чтобы не светить имя оператора)


    Это очень примерно, нужно много чего дорабатывать, включая сценарии завершения работы, переключения на другого оператора итд итп, контроль за тем, чтобы пользователя не взяли два оператора одновременно. А если бот асинхронный/многопоточный/на вебхуках - то ещё чтобы не возникло особых спецэффектов из-за пересечения взаимодействий...

    spoiler
    Важно отметить, что полноценные взрослые чат-сервисы делают совершенно не так. В них обычно даже не используется Telegram, вместо этого оператор работает через web-интерфейс (а может и отдельное приложение), в котором можно контролировать всю историю взаимодействия, переключаться между пользователями (нормальная ситуация если оператор ведёт нескольких пользователей параллельно), подтягивать данные из CRM/клиентской базы, интегрировать справочники типовых ответов или чат-ботов, итд итп. Также, например, нормальные обработки таймаутов (если пользователь или оператор не отвечает в нужный срок...)

    И делать это лучше, например, на брокерах очередей (типа rabbitmq). Чтобы не нужно было вот этого замороченного собирания сообщений до назначения оператора в какой-то список и не было риска, что пользователь успеет что-то ещё написать в процессе назначения оператору.
    Ответ написан
  • Как получить цвет пользователя в telegram на python?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Если в Bot API нет такой информации, то никак. А в Bot API её на текущйи момент вообще нет. Можно только узнать о наличии premium-подписки. https://core.telegram.org/bots/api#user
    Ответ написан
    2 комментария
  • Как можно получить просмотры на посте в канале телеграм, если бот опубликовал пост, имея на руках чат айди и айди сообщения?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В Bot API - никак. Этот API работает на событиях и не позволяет получать информацию по ранее отправленным сообщениям, и события вида "что-то изменилось в числе просмотров" не предусмотрено.

    Только пользоваться клиентским API (MTProto) на базе библиотеки telethon или pyrogram. Изображать из себя обычного пользователя и смотреть историю сообщений в канале.
    Ответ написан
    Комментировать
  • Как правильно оформить код для телеграмм бота (калькулятор систем счисления) с кнопками?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В функции bot_message надо проверять обе кнопки:
    if message.text == 'текст первой кнопки':
        ...
    elif message.text == 'текст второй кнопки':
        ...
    else:
        bot.send_message(message.chat.id, 'Моя твоя не понимать...')


    Сейчас же обрабатывает только одну, вторая не обрабатывается.

    Далее нетрудно заметить, что в коде два раза объявляются функции с одинаковыми именами. Последующее определение перекроет предыдущее, и работать будут только последние.

    Вообще говоря, мне кажется не очень осмысленным делать два варианта перевода между системами счисления. Не лучше ли спросить основание исходной и конечной и затем провести преобразование в общем случае? Заодно можно научиться делать перевод между произвольными системами счисления вплоть до 36-ричной? 10 арабских цифр плюс ещё 26 символов латиницы можно использовать как цифры, и даже формула для всех букв алфавита ord(i) - ord('A') + 10 будет хорошо работать...
    Ответ написан
    1 комментарий
  • Callback-кнопка в модуле telebot (язык python) не обновляет свое содержание. Что делать?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Потому что при каждом вызове sayanswer будет создаваться новый обработчик callback_query_handler(func=lambda callback: callback.data), добавляясь к списку уже имеющихся. И естественно, что тот, который "застолбил" позицию первым, будет вызываться до скончания жизни запущенного бота. И естественно, что в нём значение url будет таким, каким было при первом запуске sayanswer.

    Главная ошибка тут в том, что НЕЛЬЗЯ внутри функции объявлять другие функции, не понимая чётко, зачем это нужно. Иногда так делают для решения конкретных задач. Но в данном случае это совершенно не нужно и создаёт незапланированное поведение. Функцию check выносим на уровень выше. И не используем в ней переменные из функции sayanswer. Если нужно что-то передать в check - передаём через callback_data.

    Например, можно передать "btn1:кот". В check использовать декоратор с фильтром func=lambda callback: callback.data.startswith("btn1:"). В самой функции откусывать btn1: от начала и уже только тогда формировать запрос к внешнему сервису.
    Ответ написан
    Комментировать
  • Проблема с python?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Потому что надо учить язык, читать документацию и официальные примеры, а не по видео пытаться что-то там сделать. Где в этом коде делается поллинг? Естественно, без него скрипт будет сразу завершаться и работать не начнёт.
    Ответ написан
    2 комментария
  • Как отловить удалённое сообщение в Telebot?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Telegram Bot API не поддерживает сообщение о фактах удаления сообщений. Также через API нельзя читать историю сообщений. Поэтому эта задача не имеет решения с помощью ботов.

    Это можно сделать только с помощью клиентского API (MTProto), имитирующего реального пользователя ("юзербот").
    Ответ написан
  • Телебот forward_message как скрыть автора?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Что мешает вместо форварда просто отправить такое же сообщение с идентичным содержанием от имени самого бота?

    В доках метод клиентского апи, не Bot API. Нетрудно видеть, что в Bot API нет аналогичного параметра https://core.telegram.org/bots/api#forwardmessage
    Ответ написан