Ответы пользователя по тегу Telegram
  • Бот обратной связи на Aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Ну во-первых, "не получилось" - это, конечно, офигенно детальное и полезное описание проблемы.

    Во-вторых, я подозреваю, что дело вот в этом:
    photo=message.photo[0].file_id
    Наверняка если к сообщению не приложено фото, коллекция photo пуста, тогда попытка обращения к нулевому элементу выкинет исключение, так как этого нулевого элемента просто нет. Проверяй, есть ли вообще что-то в message.photo.
    Ответ написан
    Комментировать
  • Как в reply_markup добавить больше переменных с копками?

    Vindicar
    @Vindicar
    RTFM!
    bot.send_photo(message.chat.id, photo, " Выберите нужную функцию:",
    parse_mode="html", reply_markup=tg, info)

    reply_markup=tg - аргумент, переданный по имени
    info - аргумент, переданный позиционно.
    Питон не позволяет указывать позиционные аргументы ПОСЛЕ именованных. Укажи для info имя аргумента, в который ты хочешь передать это значение, по аналогии с reply_markup= или parse_mode=.
    Ответ написан
    Комментировать
  • Как убрать лишние знаки?

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

    fectchone() возвращает кортеж, в твоём случае кортеж с одним элементом. Скобки - это строковое представление кортежа. Как вытащить значение из кортежа - читай по ссылке.

    Кортежи, списки и словари - это вообще азы языка. Их надо знать, и узнавать с первого взгляда.
    Ответ написан
    Комментировать
  • Как ипортировать функции из файлов?

    Vindicar
    @Vindicar
    RTFM!
    Ещё один товарищ не учил Питон, но рвётся написать божественного бота...

    Когда ты импортируешь файл (модуль), этот модуль выполняется - практически так же, как если бы ты его запустил непосредственно. Различие есть, но небольшое. Теперь посмотрим на твои файлы.
    В первом файле ты объявляешь переменную bot. Она существует в пространстве имён первого файла (модуля).
    Если ты в нём делаешь import second_file, в нём тоже присутствует создание переменной bot - в локальном пространстве имён этого модуля. Это две разные переменные, и два разных экземпляра класса Telebot.
    Поэтому когда ты выполняешь в одном файле bot.run() (ну или как там бот запускается), ты запускаешь только один экземпляр. Второй остаётся неактивированным, и всё, что к нему привязано, не работает.

    Тебе надо как-то передать переменную bot во-второй файл, не нарвавшись при этом на циклический импорт (чтобы не было "первый импортирует второй, а второй - первый").
    Тут поможет ещё один простой факт: в питоне всё - операторы. Т.е. объявление функции - это оператор. Его можно помещать куда угодно, внутрь любого блока программы: внутрь if, внутрь цикла, внутрь другой функции. Он выполнится при выполнении соответствующего блока.
    Так что ты можешь завернуть свои обработчики из второго файла в функцию, принимающую ссылку на bot. А потом импортировать эту внешнюю функцию в первый файл и там её вызвать.
    #второй файл, second_file.py
    import telebot
    from telebot import types
    # эта функция создаст все обработчики и зарегистрирует их в предоставленном боте
    # вызывай её строго один раз за скрипт
    def register_handlers(bot):
        # а тут уже пошли обработчики
        @bot.message_handler(commands=['start'])
        def start(message):
            markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
            btn0 = types.KeyboardButton(' Каталог фильмов')
            btn1 = types.KeyboardButton(" Каталог фильмов")
            btn2 = types.KeyboardButton(' Случайный фильм')
            btn3 = types.KeyboardButton(' Предложить фильм')
            markup.add(btn0, btn1, btn2, btn3)
            bot.send_message(message.from_user.id, ' Привет, {0.first_name}. Я Kinomorph - бот, с которым ты можешь найти интересный фильм для просмотра вечером\n \n Если у тебя есть номер или название фильма, ввести его можно прямо сейчас'.format(message.from_user), reply_markup=markup)
    
    # любой код, который не должен исполняться при импорте, оформляй так:
    if __name__ == '__main__':   # переменная __name__ содержит имя, под которым импортируется модуль
        print('Этот код выполнится ТОЛЬКО если файл запущен напрямую.')
        print('Он не выполнится при импорте файла.')


    # первый файл, main.py
    import telebot
    import config
    import second_file  # модуль импортируется - в нём __name__ будет равно "second_file", а не "__main__"
    
    # инициализация
    bot = telebot.TeleBot(config.Token)
    second_file.register_handlers(bot)  # тут вызывается импортированная функция
    Ответ написан
    Комментировать
  • Почему не работает bot_func.stop(Client, module Pyrogram)?

    Vindicar
    @Vindicar
    RTFM!
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    Зачем?!
    Если у тебя бот асинхронный, просто сделай саму функцию GetUserByUsername() async.
    Ответ написан
  • Не выполгяется последняя часть кода @bot.callback_query_handler(func=lambda call:True) def callback2(call): почему и как исправить?

    Vindicar
    @Vindicar
    RTFM!
    @bot.callback_query_handler(func=lambda call:True)
    func говорит боту, когда вызывать обработчик. Бот вызывает только ОДИН обработчик (первый подходящий).
    func=lambda call:True означает, что обработчик должен вызываться для ВСЕХ кнопок.
    Научись различать обработчики по call.data. Например, пусть у одной группы кнопок data начинается с "foo.", а у другой - с "bar.".
    item = types.InlineKeyboardButton('4', callback_data='foo.question1')
    item2 = types.InlineKeyboardButton('3', callback_data='foo.question2')

    gotov = types.InlineKeyboardButton('Готов', callback_data='bar.gotov')

    Тогда ты сможешь прописать два обработчика:
    @bot.callback_query_handler(func=lambda call:call.data.startswith('foo.'))

    и
    @bot.callback_query_handler(func=lambda call:call.data.startswith('bar.'))


    Разумеется, вместо foo и bar можно придумать свои префиксы, в том числе многоуровневые (типа callback_data='questions.q1.answer1').
    Ответ написан
    1 комментарий
  • Как обратится к функции вне handler?

    Vindicar
    @Vindicar
    RTFM!
    global resault_func
    resault_func = fi(fil)

    Примерно так и обращайся.
    Ответ написан
    1 комментарий
  • Цикл для обработчика кнопок?

    Vindicar
    @Vindicar
    RTFM!
    def handle_button(call_data: str):
            try:
                fileid = int(call_data) - 1  # определяем id файла по значению call_data
            except ValueError:
                return
            markup = InlineKeyboardMarkup()
            bttn_contact = (InlineKeyboardButton(text = " Связаться с менеджером", callback_data = "contact")) 
            markup.add(bttn_contact)
            bttn_home = (InlineKeyboardButton(text = " Начало", callback_data = "home"))
            markup.add(bttn_home)
            with open(f'data/{fileid}_info.txt', 'r', encoding = "utf-8") as file:
               content = file.read()
            # if тут не нужен, сработает и без него.
            for x in range(0, len(content), 4095):
                bot.send_message(call.message.chat.id,content[x:x+4095],reply_markup=markup)

    Ну а в обработчике просто дергаешь handle_button(call.data).
    Ответ написан
    Комментировать
  • Как сделать так, чтобы бот телеграмм пересылал данные, которые ввел пользователь в другой аккаунт?

    Vindicar
    @Vindicar
    RTFM!
    Смотри в сторону Finite State Machine.
    Если коротко, твой бот должен для каждого пользователя помнить, на каком этапе он находится, и обрабатывать события соответственно.
    "Я получил сообщение от Васи. Вася сейчас на этапе ввода имени. Значит, нужно записать текст сообщения как имя, попросить ввести номер, и перевести Васю на этап ввода номера."
    Многие библиотеки для чатботов уже имеют ту или иную реализацию FSM, как раз для реализации таких вот сценариев. Читай документацию на ту библиотеку, которую ты собираешься использовать.
    Если у неё этого нет, или эта реализация тебе почему-то не подходит, то можно попробовать наколхозить её самому. Как я уже говорил, всё, что реально нужно - для каждого пользователя помнить, на каком этапе он находится.
    Ответ написан
    Комментировать
  • Как правильно одновременно запустить двух Telegram ботов одной программой на Python?

    Vindicar
    @Vindicar
    RTFM!
    Ну потому что ты фигню написал.
    th_bot = Thread(target=pyrobot(), args=())
    th_userbot = Thread(target=aiobot(), args=())

    Ты пытаешься запустить в качестве потока значение, возвращаемое функцией pyrobot(). А так как она уходит в цикл и значения не возвращает, то далее ничего не происходит. До вызова конструктора Thread() дело не доходит. С aiobot() аналогично.

    Еще раз:
    pyrobot() - вызов функции
    pyrobot - ссылка на функцию

    EDIT:
    Оба бота - асинхронные на базе asyncio, им для работы нужен цикл-реактор (event loop). Вообще не факт, что хорошая идея запускать их в потоках.
    Тут есть два варианта, сразу даже не скажу, что проще.
    Вариант А, лобовой: каждый бот создаёт своё собственные реактор через asyncio.new_event_loop(), потом задаёт его как текущий для своего потока через asyncio.set_event_loop(loop). Если ботам не требуется взаимодействовать, то это может быть проще. Если требуется... будут проблемы. Два реактора в одной программе - это не хорошо.

    Вариант Б, адекватный:
    И вызов app.run(), и вызов executor.start_polling(dp, skip_updates=True) скорее всего под капотом создают асинхронную функцию (корутину), и запускают её в реакторе. Тогда ты можешь обойтись без потоков, заставив обоих ботов работать на одном реакторе. Нужно будет зарыться в доки, или даже глянуть исходники.

    Например, для пирограмма написано такое:
    When calling this method (app.run()) without any argument it acts as a convenience method that calls start(), idle() and stop() in sequence. It makes running a single client less verbose.

    Т.е. вместо вызова app.run() ты можешь изменить код так:
    async def pyrobot():  # обрати внимание, теперь функция асинхронная!
        print("pyro started")
        @app.on_message(filters.chat("some_chat"))
        async def print_pyrogram():
            print("Pyrogram")
        # это вместо вызова app.run(), как написано в доках.
        await app.start()
        try:
            await app.idle()
        finally:
            await app.end()

    Затем делаешь аналогичный трюк с aiobot(). Нужно посмотреть в доках на аиограм, как именно.

    И потом запускаешь обоих ботов кодом вида...
    asyncio.run(asyncio.gather(pyrobot(), aiobot()))
    Ответ написан
    3 комментария
  • Как отправлять текст соответствующий картинке в телеграм боте на Python?

    Vindicar
    @Vindicar
    RTFM!
    1. вынеси random.choice(os.listdir('test')) в переменную, например, img
    2. используй os.path.splitext(os.path.basename(img))[0], чтобы получить имя файла картинки без расширения
    3. Не забудь отправить файл через photo = open('test/' + img, 'rb')
    4. PROFIT
    Ответ написан
    2 комментария
  • Бот рандомно выбирает вопрос, но проверяет по ответам для 1 вопроса, как исправить?

    Vindicar
    @Vindicar
    RTFM!
    if x == 1:
        @bot.message_handler(content_types="text")
        def send(message):
            ...

    Так работать НЕ будет. Ты явно не очень понимаешь, что делаешь.

    1. Должна быть только одна функция, декорированная как @bot.message_handler(content_types="text"). Если их несколько, отработате только одна.

    2. Ты должен хранить сведения:
    - Какой вопрос был последним задан тому или иному пользователю
    - Какие вопросы были уже заданы тому или иному пользователю
    В рамках обучения их можно хранить в словаре, но в реальном боте потребуется постоянное хранилище (например, БД), в котором эти сведения пережили бы перезапуск бота

    3. Внутри обработчика @bot.message_handler ты должен получить ID пользователя, отправившего сообщение, взять из описанного выше хранилища номер последнего заданного вопроса (если есть), и уже на основании этого номера судить о том, правильный ли ответ.
    Ответ написан
  • Как убрать скобки?

    Vindicar
    @Vindicar
    RTFM!
    1. Убрать list(). Обратиться по индексу 0 - bd[0].
    2. Почитать про списки и кортежи.
    Ответ написан
    Комментировать
  • Бот на Telebot падает, когда отправляешь второй одинаковый запрос в БД sqllite. Как исправить?

    Vindicar
    @Vindicar
    RTFM!
    Если ты хочешь при любом действии пользователя убедиться, что он в базе, то тебе нужен не просто INSERT, а INSERT ON CONFLICT IGNORE или INSERT ON CONFLICT UPDATE. Если тебе требуется что-то обновлять (например, хранить для пользователя момент последнего обращения к боту), то нужен второй. Если не требуется, то лучше первый.
    Ответ написан
    Комментировать
  • Как передать апдейт телеграм боту о том что парсер обновил БД?

    Vindicar
    @Vindicar
    RTFM!
    Вариантов много. Самый простой - храни в БД время обновления (например, время, когда была добавлена запись), и пусть его бот периодически проверяет. Хорошо работает в том плане, что БД может обновляться разными источниками, бот о них знать не обязан. Но вносит лаг между обновлением данных и реакцией бота. Да и бот базу понапрасну дергает.

    Так как в тегах postgre, почитай про команду NOTIFY. Она вроде примерно про то же самое.

    Также есть вариант с сокетом - бот слушает UDP-сокет, парсер на него посылает пакет с оповещением. Плюс в том, что оповещать может любая программа, которая может до этого сокета достучаться.
    Ответ написан
    1 комментарий
  • Почему не принимает сообщение?

    Vindicar
    @Vindicar
    RTFM!
    text=(int)
    Это не будет работать.
    Учи, как пользоваться реализацией FSM (finite state machine) в aiogram.
    Ответ написан
    Комментировать
  • Как сделать, чтобы телеграм бот принимал обрабатывал сообщение по команде?

    Vindicar
    @Vindicar
    RTFM!
    человек вводил команду(/start например), после этого бот просил написать что нибудь, человек писал какой то текст и бот что то делал с ним

    Тебе нужны Finite State Machines (автоматы состояний). Стоит почитать, что это вообще такое.
    Проблема в том, что в pyTelegramBotAPI их реализации из коробки вроде нет. Есть сторонние библиотеки, которые нужно искать. Ну или реализовывать самому.

    Идея, в общем-то, простая: тебе нужно для каждого пользователя хранить его текущее состояние (например, ввёл он команду /start или нет). Тогда в обработчике сообщения ты сможешь узнать состояние этого пользователя, и решить, что делать с этим сообщением.
    Сложности будут, когда тебе потребуется хранить какие-то ещё данные вместе с сообщением.
    Ответ написан
    Комментировать
  • Как вывести данные из массива в сообщение?

    Vindicar
    @Vindicar
    RTFM!
    for product in select_db():
        @dp.callback_query_handler(text=product['name_but'])
        async def pole(message: types.message):
            await bot.send_message(message.from_user.id, product['desk'], reply_markup=but.nav_button)

    Ты делаешь глупость.
    Просто потому, что после того, как этот код отработает, созданные тобой копии обработчика pole() останутся, и будут мешать.
    Используй один, более общий обработчик callback_query_handler, и в нём уже смотри, какой текст тебе пришёл, какой пользователь его отправил, и что с этим текстом надо делать.
    Ответ написан
    1 комментарий
  • Как динамично создавать кнопки?

    Vindicar
    @Vindicar
    RTFM!
    Кнопка добавляется вызовом определённого метода. Параметры метода могут быть не константами, а переменными. В Питоне есть циклы.

    Вот и всё. Выбираешь список показываемых продуктов, делаешь цикл по результатам, для каждого генерируешь кнопку, подставив сведения о продукте вместо текста кнопки.

    Единственный вопрос, как различить, какая кнопка была нажата. Тут уже зависит от библиотеки.
    Ответ написан
    Комментировать
  • Как ответить пользователю через бота?

    Vindicar
    @Vindicar
    RTFM!
    Хранить где-то (в БД, например) какое сообщение закрытого чата соответствует какому пользователю. При получении сообщения-ответа в закрытом чате узнать ID отвеченного сообщения, посмотреть в базе, какой пользователь отправил оригинал, переслать текст этому пользователю.
    Ответ написан