Задать вопрос
Ответы пользователя по тегу TeleBot
  • Как вернуться из модуля обратно в main?

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

    Если же у тебя более сложная ситуация, придётся выкручиваться. Например: main описывает бота, который используется модулем, который уже предоставляет сервис через этого бота. Тут ситуация усложняется телеботом, который не особенно пригоден для многомодульных ботов. Хотя есть приём, который можно сравнить с внедрением зависимостей.

    module1.py
    # бота передаём как параметр внутрь функции install_module
    # если у тебя будут другие глобальные ресурсы, скажем, соединение с СУБД, можно передавать их также
    def install_module(bot) -> None:  
        # да, мы описываем функцию прямо внутри другой функции. Так можно
        @bot.message_handler(commands=['some_command', ])
        def my_command(message):
            ...  # тут логика команды
    
        # и ещё одну...
        @bot.message_handler(commands=['other_command', ])
        def my_other_command(message):
            ...  # тут логика команды

    Тогда в main.py будет что-то вроде
    import telebot
    bot=telebot.TeleBot('TOKEN')
    # импортируем и активируем модуль
    import module1
    module1.install_module(bot)  # install_module() модуля должна вызываться строго однажды
    # модулей может быть несколько
    import module2
    module2.install_module(bot)
    # когда всё установлено, запускаем бота
    bot.infinity_polling()

    Идею можно развить таким образом: пусть твои модули лежат не рядом с main.py, а в подпапке modules. Тогда можно сделать что-то такое, чтобы автоматически подгрузить все модули из этой папки при старте бота.
    from pathlib import Path
    import sys
    import importlib
    
    import telebot
    
    bot=telebot.TeleBot('TOKEN')
    
    MAIN_DIR = Path(sys.argv[0]).parent.resolve()  # папка где лежит скрипт бота
    MODULES_DIR = MAIN_DIR / 'modules'  # лежащая рядом папка modules
    for item in MODULES_DIR.glob('*'):   # перебираем файлы и папки в папке modules
        # игнорируем папки и файлы, начинающиеся с _ или с .
        if item.name.startswith('_') or item.name.startswith('.'):
            continue
        # item - это имя пригодного для импорта модуля?
        if (item.isfile() and item.name.endswith('.py')) or (item.isdir() and (item / '__init__.py').isfile()):
            # да импортируем и активируем модуль
            module = importlib.import_module('modules.'+item.name)
            module.install_module(bot)
    
    # когда всё установлено, запускаем бота
    bot.infinity_polling()
    Ответ написан
    2 комментария
  • Почему не работает код python для телеграмм бота?

    Vindicar
    @Vindicar
    RTFM!
    У тебя, судя по скрину, используется виртуальное окружение проекта (.venv).
    Ты в него ставил либу, или в глобальный интерпретатор?
    Ответ написан
    Комментировать
  • Как исправить ошибку: (init__.py:7144 MainThread) ERROR TeleBot: "message_handler: Commands filter should be list of strin gs (commands), unknown typ?

    Vindicar
    @Vindicar
    RTFM!
    Commands filter should be list of strings

    @bot.message_handler(commands={'start'})
    У тебя commands - не список, а множество (set).
    Ответ написан
    Комментировать
  • Как написать тг бот-секундомер на питоне?

    Vindicar
    @Vindicar
    RTFM!
    В коде дикая каша - или у тебя отступы уехали чёрт знает куда. Такое не заработает.
    Начни с официальных примеров, найди среди них наиболее похожий - скажем, вот этот таймер. Разберись, как он устроен, и потихоньку модифицируй.
    Разумеется, предполагается, что ты хотя бы насколько-то знаешь питон. Если это не так - откладываешь бота и учишь язык.
    Ответ написан
    Комментировать
  • У меня ошибка TypeError: 'list' object is not callable Что делать?

    Vindicar
    @Vindicar
    RTFM!
    Всё перепробовал, а прочитать внимательно - не пробовал.
    Почему ты вообще трогаешь message_handlers, это не декоратор, а список установленных обработчиков. Даже по названию можно догадаться - handlers во множественном числе.
    Тебе нужен message_handler.
    Смотри официальные примеры.
    Ответ написан
    Комментировать
  • Как сделать чтобы извлекался user_id пользователя, а не бота?

    Vindicar
    @Vindicar
    RTFM!
    Читаем доки telebot.
    https://docs.python-telegram-bot.org/en/stable/tel...
    message (telegram.MaybeInaccessibleMessage, optional) - Message sent by the bot with the callback button that originated the query

    Выделение моё. Теперь понятно, почему ты получаешь id самого бота?
    А если чуть выше глянуть, там ещё интереснее.
    from_user (telegram.User) – Sender.


    Привыкай находить и читать документацию, там много интересного.
    Ответ написан
    1 комментарий
  • Бот на python/telebot не приветствует новых пользователей, что не так?

    Vindicar
    @Vindicar
    RTFM!
    А почему ты вызываешь bot.polling()? Это для асинхронных ботов, а твой синхронный. Используй infinity_polling().
    Вообще, читай официальные примеры, вроде вот этого, и сравнивай со своим кодом.
    Ответ написан
  • Как сделать так, чтобы бот, написанный на модуле telebot, включал у пользователя режим ответа на cообщение?

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

    send_message(...)
    reply_markup (telebot.types.InlineKeyboardMarkup or telebot.types.ReplyKeyboardMarkup or telebot.types.ReplyKeyboardRemove or telebot.types.ForceReply) – Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user.

    Выделение моё.
    Т.е. вместо клавиатуры передаёшь специальный объект. А дальше тыкаешь по ссылке ForceReply и смотришь что это за объект и как его сконструировать.
    Ответ написан
  • Бот перестает работать после определенного блока, как исправить?

    Vindicar
    @Vindicar
    RTFM!
    Ну так ты не озаботился изучением работы инлайн-кнопок, вот и результат.
    У тебя две функции отмечены декоратором
    @bot.callback_query_handler(func=lambda call: True)

    Эта проблема встречается регулярно, и на этом сайте уже есть несколько вопросов по ней.
    Вот один из них, с моим ответом.
    Ответ написан
    Комментировать
  • Как заставить бота ждать ответа пользователя?

    Vindicar
    @Vindicar
    RTFM!
    Ну для начала твоя лесенка из if-elif-elif-... - плохое решение.
    Сделай нормальную структуру данных вместо пачки переменных. Используй словарь, или ещё что. Например, такого вида:
    # словарь, где ключ - строка с названием пунка отправления, а значение - ещё словарь,
    #   где ключ - строка с названием пункта назначения, а значение - список,
    #     где элементы - пары строк ("время отправления", "время прибытия")
    # Тогда с таким словарём можно будет работать так:
    bus_timetable: dict[str, dict[str, list[tuple[str, str]]]] = {
        # ты словарь заполняешь по результатам парсинга, ну и то хорошо
        # я для примера запишу прямо так
        'Владимир' : {
            'Муром': [
                ('8:00', '11:00'),
                ('9:00', '12:00'),
                ('10:00', '13:00'),
            ],
        },
    }
    point_from = 'Владимир'
    point_to = 'Муром'
    # для примера вывожу в консоль, для бота перепишешь сам
    print(f'Автобус из {point_from} в {point_to}')  
    for departure, arrival in bus_timetable[point_from][point_to]:
        print(f'Отходит в {departure}, прибывает в {arrival}')

    Тогда тебе не потребуется делать кучу веток для разных городов, достаточно лишь определить значения point_from и point_to. Более того, ты можешь просто перечислить ключи внешнего словаря при создании кнопок:
    kbd_from = types.ReplyKeyboardMarkup(resize_keyboard=True)
    buttons = [types.KeyboardButton(point_from) for point_from in bus_timetable]  # список кнопок
    kbd_from.add(*buttons)  # если надо добавить все кнопки сразу

    Похожий приём возможен и для определения кнопок для городов назначения.

    А теперь по тому, как сделать выбор. Тут есть два варианта, но давай пока поговорим о ReplyKeyboardMarkup, которую ты используешь.
    Если ты хочешь использовать ReplyKeyboardMarkup, то стоит помнить - её кнопки дают тот же эффект, как если бы пользователь просто ввёл текст кнопки сам. Поэтому тебе потребуется использовать register_next_step_handler(). Ты не привёл код своей попытки, но в целом идея несложная. В основном обработчике события ты проверяешь, что текст сообщения содержится в bus_timetable (оператор in в помощь) - это значит, что текст сообщения содержит название известного боту города.
    Тогда ты делаешь вызов register_next_step_handler() и ставишь обработчик второго сообщения. Единственное "но": тебе нужно будет обработчику передать первый выбранный город. Это будет выглядеть как-то так:
    @bot.message_handler(content_types=['text'])
    def first_message_handler(message):
        if message.text in bus_timetable:  # назвали известный город? Это пункт отправления
            kbd = ...  # тут определяешь клавиатуру, опираясь на города в bus_timetable[message.text]
            response = bot.reply_to(message, "А теперь назовите пункт назначения", reply_markup=kbd)
            # обрати внимание: все параметры после указания функции second_message_handler будут
            # переданы в эту функцию при её вызове. А вызвана она будет, когда пользователь ответит.
            bot.register_next_step_handler(response, second_message_handler, message.text)
        elif ...  # нам назвали не город - тут можно проверить другие команды
    
    def second_message_handler(message, point_from):
        # а эта функция будет вызвана только когда пользователь уже назвал пункт отправления
        # point_from будет содержать название города, отправленное пользователем.
        if message.text in bus_timetable[point_from]:  # нам назвали допустимый пункт назначения
            bus_rides = bus_timetable[point_from][message.text]  # список рейсов
            ...  # дальше перебираем список bus_rides и выводим его пользователю
        else:  # пользователь назвал что-то другое
            ...  # говорим пользователю, что он дурак
    Ответ написан
    1 комментарий
  • Почему Telegram бот не отвечает?

    Vindicar
    @Vindicar
    RTFM!
    Ну тебе же английским по белому написано:
    RuntimeError: This Application was not initialized via `Application.initialize`!

    Нужно перед вызовом application.start() добавить аналогичный вызов initialize().

    И да, ты пытаешься трогать элементы управления своего окна из другого потока. Так нельзя.
    Ответ написан
    Комментировать
  • Почему возникает ошибка при создании Telegram бота?

    Vindicar
    @Vindicar
    RTFM!
    Открываем официальные примеры, находим простейший эхобот, и начинаем с него.
    В частности, смотрим, каким методом запускается работа бота.
    Спойлер
    bot.infinity_polling()
    Ответ написан
    Комментировать
  • Почему когда отвечаю на сообщение в чате, сообщение не присылается пользователю в бота обртано?

    Vindicar
    @Vindicar
    RTFM!
    У тебя handle_message() стоит первым - поэтому бот будет пытаться использовать его для любых текстовых сообщений. А поскольку у тебя там тупо if, без какой-либо реакции на неожиданные сообщения, то если if не выполнился, бот молча ничего не сделает.
    Ответ написан
    Комментировать
  • Стоит ли использовать ООП для бота на Telebot?

    Vindicar
    @Vindicar
    RTFM!
    Ну почему бы и нет?
    Вон, discord.py вообще реализует механизм когов (cogs), который позволяет заключать отдельные наборы поведений в класс, и подгружать/выгружать этот класс по ходу работы.
    Нечто подобное можно построить на базе почти любой библиотеки чат-ботов, особенно если с выгрузкой заморачиваться не требуется.
    Просто если у тебя только один набор связанных поведений, то и класс с обработчиками будет один - и смысл тогда?
    Ответ написан
    Комментировать
  • Ошибка TypeError: work_command() missing 1 required positional argument: 'points' что делать?

    Vindicar
    @Vindicar
    RTFM!
    @bot.message_handler(content_types=['text'])
    def work_command(message, points):


    Бот ничего не знает про points и откуда оно берётся. Бот ожидает, что любая функция, отмеченная как обработчик сообщений, принимает ровно один параметр - объект принятого сообщения. Если это условие не выполняется, это твой косяк.

    если делать global points то будет у всех один баланс

    Вовсе нет. Ты не обратил внимание, что у тебя points - словарь, где ключ - id пользователя? (к слову, кто код писал? уж точно не разраб-крут). У тебя для разных id пользователей будут отдельные элементы в словаре, с отдельными значениями.

    Другое дело, что словарь не переживёт перезапуска бота...
    Ответ написан
  • Как сделать бота поддержки с при помощи библиотеки telebot?

    Vindicar
    @Vindicar
    RTFM!
    Не пытайся объявлять обработчики событий динамически, внутри других обработчиков. Это не будет работать так, как ты это ожидаешь!
    А для начала определись с ответом на вопрос: если есть несколько одновременных обращений, то как бот поймёт, кому отвечает оператор?

    Один из вариантов

    Оператор должен явно отвечать (через соотв. пункт меню) на сообщение бота.
    Тогда бот должен хранить список вида "id сообщения в группе, id пользователя. Можешь хранить в БД или ином хранилище (БД в конечном итоге будет проще всего).

    В этом случае логика бота по обработке сообщения будет такая:
    1. Если сообщение в личке: отправить копию сообщения в группу, сохранить в БД id пользователя и id отправленного ботом сообщения.
    2. Если сообщение в группе, и это ответ: поискать в БД id сообщения, на которое ответ. Если id найдено - извлечь соответствующее id пользователя, отправить ему копию сообщения.
    3. Если id не найдено: что должен сделать бот?
    4. Если сообщение в группе, но это не ответ: что должен сделать бот?

    Можно также прикреплять к записи в БД дату, чтобы время от времени можно было выкидывать из БД старые сообщения. Это уже упражнение для читателя.
    Ответ написан
    Комментировать
  • Бот отправляет 2 раза сообщение, которое не нужно отправлять в данный момент + не хочет отправлять результаты в группу, Как решить эти 2 проблемы?

    Vindicar
    @Vindicar
    RTFM!
    return (test_g, test_k)
    bot.send_message(айди группы, f'@{message.from_user.username} / {message.from_user.id} отправил тест на проверку\nЕго варианты были\nhttps://forms.gle/{test(message)[0]}\nhttps://forms.gle/{test(message)[1]}')


    Полнейшая чушь.

    Во-первых, запомни, что обработчики событий (всё, что декорировано message_handler() или подобным) не следует вызывать самостоятельно. Вот просто не следует. Их вызывает бот по мере надобности. Как следствие, возвращать из них тоже ничего не следует - бот это проигнорирует, а ты эти значения не получишь.

    Во-вторых, выучи концепцию побочных эффектов при вызове функции и держи её в голове. Ты на ровном месте делаешь два вызова test(), которая имеет побочные эффекты в виде отправки сообщения, а потом удивляешься, что два раза отправляются сообщения! Причем именно что на ровном месте. Вот тебе что, грозят болтающееся отрезать за сохранение результата test() в ещё одну локальную переменную перед использованием этого результа? Конечно, это непринципиально, потому что test() вызывать нельзя (см. пункт 1), но всё равно показательно.

    А что касается передачи инфы о действиях пользователя - заведи хранилище вида "id пользователя - пара ссылок". Подойдёт даже словарь, если тебе не нужно, чтобы инфа переживала перезапуск бота. И вот оттуда уже в well() вытаскивай инфу о том, что проходил текущий пользователь.

    Учись программировать, потом пиши ботов. Не наоборот.
    Ответ написан
    Комментировать
  • Как при создании телеграмм бота сложить несколько переменных?

    Vindicar
    @Vindicar
    RTFM!
    Это потому что текст сообщения пользователя - строка. Для строк, "1" + "1" = "11", потому что сложение строк - это конкатенация.
    Преобразуй строки в числа. Для целых это просто
    s = "11"
    x = int(s)  # x = 11

    Для дробных чисел сложнее. Конечно, можно сделать по аналогии:
    s = "1.1"
    x = float(s)  # x = 1.1

    Но тут требуется десятичная точка, т.е. "1,1" не прокатит. Отчасти это можно компенсировать заменой, например,
    s = "1,1"
    x = float(s.replace(",", "."))  # x = 1.1

    Коряво, но сработает.
    Ответ написан
    Комментировать
  • Как причесать текст в telegram боте?

    Vindicar
    @Vindicar
    RTFM!
    Ты уж решай - или ты хочешь структурированный ответ, например, json, или ты хочешь простой текст.
    В зависимости от этого формулируй запрос и указывай тип ожидаемого ответа.
    Если хочешь json - имеет смысл приложить образец jsonки, чтобы в ней были те поля, которые ты ожидаешь получить.
    Ответ написан
    Комментировать
  • Почему не работает база данных sqlite3 для телеграм бота?

    Vindicar
    @Vindicar
    RTFM!
    cursor.executemany('''
            INSERT INTO bugs (bug_name, bug_info, developer) VALUES (?, ?, ?)
        ''', (bug_name_var, bug_info_var, developer))


    Почему тут executemany()? Ты вызываешь его, как будто это простой execute().
    Ответ написан
    Комментировать