Telegram бот на Python, отправка файлов, встроенная клавиатура
Это вторая часть статьи, где мы продолжим создавать нашего телеграм бота на Python, и научим его отправлять файлы и выводить настраиваемую клавиатуру.
Отправка файлов Telegram API
В Telegram API есть три способа отправки файлов, для демонстрации воспользуемся методом sendPhoto и добавим три функции для отправки фотографии.
Первая способ: Предоставить файл по URL, Telegram скачает и отправит его (максимальный размер 5 МБ).
def send_photo_url(chat_id, img_url): requests.get(f'/sendPhoto?chat_id=&photo=')
Второй способ: Отправить файл с компьютера (максимальный размер фотографий — 10 МБ, для остальных файлов — 50 МБ).
def send_photo_file(chat_id, img): files = requests.post(f'/sendPhoto?chat_id=', files=files)
Третий способ: Отправить, передав в параметрах file_id файла который уже хранится где-то на серверах Telegram (ограничений нет).
def send_photo_file_id(chat_id, file_id): requests.get(f'/sendPhoto?chat_id=&photo=')
Проверка
Почти все готово, осталось немного отредактировать функцию check_message и приступим к проверке бота.
def check_message(chat_id, message): if message.lower() in ['привет', 'hello']: send_message(chat_id, 'Привет :)') elif message.lower() in 'фото по url': # Отправить URL-адрес картинки (телеграм скачает его и отправит) send_photo_url(chat_id, 'https://ramziv.com/static/assets/img/home-bg.jpg') elif message.lower() in 'фото с компьютера': # Отправить файл с компьютера send_photo_file(chat_id, 'photo.jpg') elif message.lower() in 'фото с сервера телеграм': # Отправить id файла (файл уже хранится где-то на серверах Telegram) send_photo_file_id(chat_id, 'AgACAgIAAxkBAAMqYVGBbdbivL53IzKLfUKUClBnB0cAApy0MRtfMZBKHL0tNw9aITwBAAMCAAN4AAMhBA')
import requests import time TOKEN = 'токен' URL = 'https://api.telegram.org/bot' def get_updates(offset=0): result = requests.get(f'/getUpdates?offset=').json() return result['result'] def send_message(chat_id, text): requests.get(f'/sendMessage?chat_id=&text=') def send_photo_url(chat_id, img_url): requests.get(f'/sendPhoto?chat_id=&photo=') def send_photo_file(chat_id, img): files = requests.post(f'/sendPhoto?chat_id=', files=files) def send_photo_file_id(chat_id, file_id): requests.get(f'/sendPhoto?chat_id=&photo=') def check_message(chat_id, message): if message.lower() in ['привет', 'hello']: send_message(chat_id, 'Привет :)') elif message.lower() in 'фото по url': # Отправить URL-адрес картинки (телеграм скачает его и отправит) send_photo_url(chat_id, 'https://ramziv.com/static/assets/img/home-bg.jpg') elif message.lower() in 'фото с компьютера': # Отправить файл с компьютера send_photo_file(chat_id, 'photo.jpg') elif message.lower() in 'фото с сервера телеграм': # Отправить id файла (файл уже хранится где-то на серверах Telegram) send_photo_file_id(chat_id, 'AgACAgIAAxkBAAMqYVGBbdbivL53IzKLfUKUClBnB0cAApy0MRtfMZBKHL0tNw9aITwBAAMCAAN4AAMhBA') def run(): update_id = get_updates()[-1]['update_id'] # Присваиваем ID последнего отправленного сообщения боту while True: time.sleep(2) messages = get_updates(update_id) # Получаем обновления for message in messages: # Если в обновлении есть ID больше чем ID последнего сообщения, значит пришло новое сообщение if update_id < message['update_id']: update_id = message['update_id'] # Присваиваем ID последнего отправленного сообщения боту # Отвечаем тому кто прислал сообщение боту check_message(message['message']['chat']['id'], message['message']['text']) if __name__ == '__main__': run()
Таким образом вы можете отправить документ, видео, или аудиофайл заменив в URL метод sendPhoto на подходящий.
- sendVoice Используйте этот метод для отправки аудиофайлов, если вы хотите, чтобы клиент Telegram отображал файл как воспроизводимое голосовое сообщение.
- sendDocument Используйте этот метод для отправки общих файлов.
- sendAudio Используйте этот метод для отправки аудиофайлов, если вы хотите, чтобы клиент Telegram отображал их в музыкальном проигрывателе.
- sendVideo Используйте этот метод для отправки видеофайлов, клиент Telegram поддерживают видео в формате mp4 (другие форматы могут быть отправлены как документ ).
- sendPhoto Используйте этот метод для отправки фотографий.
С полным списком методов можно ознакомиться здесь
Встроенная клавиатура
Добавим две функции для вывода настраиваемой клавиатуры в телеграм
InlineKeyboardMarkup - Этот объект представляет собой встроенную клавиатуру, которая появляется рядом с отправленным сообщением.
def inline_keyboard(chat_id, text): reply_markup = ]]> data = requests.post(f'/sendMessage', data=data)
ReplyKeyboardMarkup - Этот объект представляет собой настраиваемую клавиатуру с параметрами ответа
def reply_keyboard(chat_id, text): reply_markup = < "keyboard": [["Фото по url", "Сайт"], ["Привет"]], "resize_keyboard": True, "one_time_keyboard": True>data = requests.post(f'/sendMessage', data=data)
Отредактируем функцию check_message для вывода нашей клавиатуры
def check_message(chat_id, message): if message.lower() in ['привет', 'hello']: send_message(chat_id, 'Привет :)') elif message.lower() in 'сайт': inline_keyboard(chat_id, 'Вы можете ознакомиться\nс товаром на сайте') elif message.lower() in 'фото по url': # Отправить URL-адрес картинки (телеграм скачает его и отправит) send_photo_url(chat_id, 'https://ramziv.com/static/assets/img/home-bg.jpg') elif message.lower() in 'фото с компьютера': # Отправить файл с компьютера send_photo_file(chat_id, 'photo.jpg') elif message.lower() in 'фото с сервера телеграм': # Отправить id файла (файл уже хранится где-то на серверах Telegram) send_photo_file_id(chat_id, 'AgACAgIAAxkBAAMqYVGBbdbivL53IzKLfUKUClBnB0cAApy0MRtfMZBKHL0tNw9aITwBAAMCAAN4AAMhBA') else: reply_keyboard(chat_id, 'Вот что я умею')
Проверка
Проверим как все работает
Отправим боту сообщение Сайт
Если отправить сообщение на которые бот не может дать ответ, он выведет клавиатуру и сообщение Вот что я умею
import requests import time import json TOKEN = 'токен' URL = 'https://api.telegram.org/bot' def get_updates(offset=0): result = requests.get(f'/getUpdates?offset=').json() return result['result'] def send_message(chat_id, text): requests.get(f'/sendMessage?chat_id=&text=') def send_photo_url(chat_id, img_url): requests.get(f'/sendPhoto?chat_id=&photo=') def send_photo_file(chat_id, img): files = requests.post(f'/sendPhoto?chat_id=', files=files) def send_photo_file_id(chat_id, file_id): requests.get(f'/sendPhoto?chat_id=&photo=') def inline_keyboard(chat_id, text): reply_markup = ]]> data = requests.post(f'/sendMessage', data=data) def reply_keyboard(chat_id, text): reply_markup = < "keyboard": [["Фото по url", "Сайт"], ["Привет"]], "resize_keyboard": True, "one_time_keyboard": True>data = requests.post(f'/sendMessage', data=data) def check_message(chat_id, message): if message.lower() in ['привет', 'hello']: send_message(chat_id, 'Привет :)') elif message.lower() in 'сайт': inline_keyboard(chat_id, 'Вы можете ознакомиться\nс товаром на сайте') elif message.lower() in 'фото по url': # Отправить URL-адрес картинки (телеграм скачает его и отправит) send_photo_url(chat_id, 'https://ramziv.com/static/assets/img/home-bg.jpg') elif message.lower() in 'фото с компьютера': # Отправить файл с компьютера send_photo_file(chat_id, 'photo.jpg') elif message.lower() in 'фото с сервера телеграм': # Отправить id файла (файл уже хранится где-то на серверах Telegram) send_photo_file_id(chat_id, 'AgACAgIAAxkBAAMqYVGBbdbivL53IzKLfUKUClBnB0cAApy0MRtfMZBKHL0tNw9aITwBAAMCAAN4AAMhBA') else: reply_keyboard(chat_id, 'Вот что я умею') def run(): update_id = get_updates()[-1]['update_id'] # Присваиваем ID последнего отправленного сообщения боту while True: time.sleep(2) messages = get_updates(update_id) # Получаем обновления for message in messages: # Если в обновлении есть ID больше чем ID последнего сообщения, значит пришло новое сообщение if update_id < message['update_id']: update_id = message['update_id'] # Присваиваем ID последнего отправленного сообщения боту # Отвечаем тому кто прислал сообщение боту check_message(message['message']['chat']['id'], message['message']['text']) if __name__ == '__main__': run()
Вот и все, теперь бот может не только поприветствовать, но и отправить файл, и вывести настраиваемую клавиатуру. Скоро я выпушу третью часть, где мы добавим оплату через QIWI кошелек, или любой другой функционал который вы пожелаете. (напишите мне если вы хотите третью часть побыстрее)
Дополнительную информацию о методах вы можете получить в документации.
Telegram боты. Загружаем файлы больше 50мб
Telegram боты позволяют автоматизировать многие процессы. Их использование не ограничивается одним чатом, по сути — бот это всего лишь интерфейс ввода-вывода, который помимо текста также может принимать и передавать файлы: изображения, видео, аудио, документы…
- Для пользователей максимальный размер файла — 1.5Гб
- Боты ограничены размером всего лишь в 50мб
Telegram API
Раз пользователи могут загружать файлы до 1.5Гб — значит и мы можем — для этого создадим агента (назвал чтобы не путать с ботами) который будет работать в связке с нашим Telegram ботом. Для этого потребуется отдельный аккаунт и Telegram API.
Для начала идем на https://core.telegram.org и по инструкции регистрируем приложение, в итоге вы должны получить api_id и api_hash
Что делает агент?
Бот не может загружать файлы больше 50мб, но если у него есть file_id уже загруженного на сервера Telegram файла — то он может его пересылать. Так что алгоритм следующий
- Приложение, работающее на сервере через Bot API формирует файл для отправки
- Вызывает агента для загрузки файла на сервера Telegram
- Получает от агента file_id
- Пользуется загруженным файлом
Пример кода
Потребность загружать большие файлы появилась при написании @AudioTubeBot — изначально аудиофайл разбивался на части и отправлялся по частям. Функционал загрузки больших файлов было решено вынести в отдельное приложение, которое вызывается через subprocess.check_call
#!/usr/bin/env python3 # -*- coding: utf-8 -*- from telethon import TelegramClient from telethon.tl.types import DocumentAttributeAudio import mimetypes entity = 'AudioTube_bot' #имя сессии - все равно какое api_id = 1959 api_hash = '88b68d6da53fe68c1c3541bbefc' phone = '+79620181488' client = TelegramClient(entity, api_id, api_hash, update_workers=None, spawn_read_thread=False) client.connect() if not client.is_user_authorized(): # client.send_code_request(phone) #при первом запуске - раскомментить, после авторизации для избежания FloodWait советую закомментить client.sign_in(phone, input('Enter code: ')) client.start() def main(argv): file_path = argv[1] file_name = argv[2] chat_id = argv[3] object_id = argv[4] bot_name = argv[5] duration = argv[6] mimetypes.add_type('audio/aac','.aac') mimetypes.add_type('audio/ogg','.ogg') msg = client.send_file( str(bot_name), file_path, caption=str(chat_id + ':' + object_id + ':' + duration), file_name=str(file_name), use_cache=False, part_size_kb=512, attributes=[DocumentAttributeAudio( int(duration), voice=None, title=file_name[:-4], performer='')] ) client.disconnect() return 0 if __name__ == '__main__': import sys main(sys.argv[0:])
Комментарии:
Вот и весь код — тут используется библиотека Telethon — при запуске программе передается путь к файлу для отправки, имя файла, chat_id — для кого предназначается данный файл), имя бота, который вызвал агента(например у меня это beta и release боты).
client.send_file
Просто загрузить файл на сервер через upload, получить file_id и передать его боту — не выйдет, file_id работает только внутри чата, в котором он был создан — чтобы наш бот мог переслать файл пользователю по file_id — агент должен переслать ему этот файл
— тогда бот получит свой file_id для этого файла и сможет распоряжаться им.
caption=str(. ) — wat?!
Агент пересылает файлы только боту, добавляя комментарий в caption-у меня это:
- chat_id конечного пользователя
- длительность трека
- object_id в базе данных, к которому нужно привязать file_id, чтобы повторно не загружать файл(индексация, оптимизация и все такое)
Пример вызова в коде бота
На диске в path_file_mp3 уже сохранен файл для загрузки, вызываем подпрограмму и ждем ее завершения.
status = subprocess.check_call( "python3.6 audiotubeagent36/main.py " + path_file_mp3 + ' ' + audio_title + '.'+ us_audio_codec + ' ' + str(chat_id) + ' ' + str(pool_object['_id']) + ' ' + config.BOT_NAME + ' ' + str(duration),shell=True)
В обработчике входящих сообщений делаем что то подобное
if message.content_type in ['document','audio']: user_id = message.from_user.id bot_settings = SafeConfigParser() bot_settings.read(config.PATH_SETTINGS_FILE) c_type = message.content_type if functions.check_is_admin(bot_settings, user_id): if c_type == 'audio': file_id = message.audio.file_id audio_title = message.audio.title else: file_id = message.document.file_id audio_title = message.document.file_name[:-4] client_chat_id = message.caption if client_chat_id.find(u':') != -1: client_chat_id, q_pool_obj_id, duration_s = re.split(r':',client_chat_id) #добавляем file_id в базу q_pool.update_request_file_id(str(q_pool_obj_id), str(file_id)) #пересылаем конечному адресату bot.send_audio(int(client_chat_id), file_id,caption='', duration=int(duration_s), title=audio_title, performer='') return