Как создать телеграмм-бота, подобного Shazam, с использованием Python
Когда вы слушаете музыку на улице, например, в баре или магазине, и она вам действительно нравится, разве вам не интересно, как называется песня и имя певца?
Это случалось со мной много раз, и есть только одно решение. Shazam. Загрузите его и нажмите на всплывающую кнопку, чтобы определить музыку.
В этой статье мы собираемся создать аналогичное приложение, чтобы искать песню и исполнителя. Быстрый и простой способ разработать этот проект в области Data Science – создать Telegram-бота на Python.
Когда вы слушаете музыку, вы записываете звук. Этот бот переведёт аудио в текст и найдёт для вас название песни и исполнителя. Давайте начнем!
Часть 1: Создание Telegram-бота с помощью Python
Этот урок будет разделён на две части. В первой части мы сосредоточимся на создании telegram-бота, который сможет определить песню и выдать информацию о ней и её исполнителе. Далее мы развернём telegram-бота для fly.io , которая представляет собой одну из многих платформ, позволяющих создавать, запускать и масштабировать приложения в облаке.
- Требования
- Установка библиотек
- Первые шаги по созданию бота для Telegram
- Расшифровка аудиозаписи песни
- Получение информации о песне
Требования
Перед началом программирования на Python необходимо выполнить несколько шагов.
- Зайдите в Telegram, найдите @botfather и нажмите на первый появившийся результат.
- Нажмите кнопку “Пуск”, чтобы начать диалог с BotFather.
- Напишите команду /newbot и следуйте инструкциям, предложенным на скриншоте. После создания бота вы получите токен от BotFather, позволяющий вам получить доступ к Telegram API.
- Введите имя вашего telegram-бота.
Установка библиотек
Прежде всего, установите библиотеку python, которая позволяет создать telegram-бота с помощью нескольких строк кода. Она называется pyTelegramBotAPI.
pip install pyTelegramBotAPI
Чтобы расшифровать аудио, я собираюсь использовать Steamship API. Перед установкой пакета вам необходимо установить nodej. На Windows вам нужно установить его отсюда и добавить путь в переменную окружения PATH, в то время как в ubuntu вам нужно ввести две строки кода:
sudo apt install nodejs
sudo apt install npm
После этого вы, наконец, сможете установить Steamship CLI в свою IDE Python.
pip install steamship
npm install -g @steamship/cli
ship login
Как только он будет установлен, мы перейдём к третьему API, который позволяет нам находить песню из аудио. Это возможно, получив доступ к результатам поиска Google через этот API, называемый SerpApi.
pip install google-search-results
Первые шаги по созданию бота для Telegram
Как только вы получили токен API Telegram и создали Telegram-бота, который должен появиться в вашем приложении Telegram, мы можем начать изучать pyTelegramBotAPI, который предоставляет реализации на Python для создания Telegram-бота используя несколько строк кода.
Существует много других различных библиотек python, которые позволяют создавать Telegram-ботов, но поскольку я нашел много руководств, в которых использовалась эта библиотека, и документация была хорошо составлена, я выбрал её для своего небольшого проекта.
import os
import json
...
from steamship import Steamship, TaskState
import telebot
from serpapi import GoogleSearch
f = open("cred.json", "rb")
params = json.load(f)
BOT_TOKEN = params['BOT_TOKEN']
bot = telebot.TeleBot(BOT_TOKEN)
У нас есть файл cred.json
, содержащий токен бота и ключи API для Steamship и SerpApi:
{
"BOT_TOKEN":<your_bot_token>,
"API_KEY":<your_serpapi_key>,
"STEAM_API_KEY":<your_steamship_api_key>
}
В строке 11 мы просто создаём экземпляр TeleBot
, который представляет собой класс, предоставляющий функции для обработки сообщений в Telegram. Например, давайте определим обработчик сообщений, который возвращает сообщение “Вставьте аудио вашей песни”, если вы пишете в чате /start
или /hello
.
@bot.message_handler(commands=['start', 'hello'])
def send_welcome(message):
bot.reply_to(message, "Insert the audio of your song!")
bot.infinity_polling()
В конце кода мы запускаем бота с помощью bot.infinity_polling()
У вас должен получиться аналогичный результат, как на скриншоте выше, после запуска python bot.py
на терминале.
После функции send_welcome
, мы можем определить другую функцию, называемую telegram_bot
, которая будет работать с аудиофайлами типа “voice”.
@bot.message_handler(content_types=['voice'])
def telegram_bot(message,bot_token=params["BOT_TOKEN"]):
# insert audio
file_info = bot.get_file(message.voice.file_id)
# extract telegram's url of the audio
audio_url = 'https://api.telegram.org/file/bot{}/{}'.format(bot_token,file_info.file_path)
bot.infinity_polling()
Мы заинтересованы в получении общедоступного URL вашего аудиофайла, отправленного боту. Чтобы проверить правильность URL-адреса, скопируйте следующий путь, заменив токен бота и путь к файлу в вашем браузере. Если это сработает, он должен загрузить аудио на ваш локальный компьютер.
https://api.telegram.org/file/bot<bot_token>/<file_path>
Последняя операция, которую нам нужно выполнить – это преобразование аудио из OGA в формат MP3. Это важный шаг, поскольку файл OGA не поддерживается для транскрипции.
def convert_oga_to_mp3(audio_url):
file = requests.get(audio_url)
urllib.request.urlretrieve(audio_url,'audio.oga')
subprocess.run(["ffmpeg", "-i", 'audio.oga', 'audio.mp3'])
data = open('audio.mp3', 'rb')
def get_url_mp3(bot_token,message):
bot.reply_to(message, 'Searching song...')
data = open('audio.mp3', 'rb')
ret_msg = bot.send_voice(message.chat.id,data)
file_info = bot.get_file(ret_msg.voice.file_id)
audio_url = 'https://api.telegram.org/file/bot{}/{}'.format(bot_token,file_info.file_path)
return audio_url
@bot.message_handler(content_types=['voice'])
def telegram_bot(message,bot_token=params["BOT_TOKEN"]):
# insert audio
file_info = bot.get_file(message.voice.file_id)
# extract telegram's url of the audio
audio_url = 'https://api.telegram.org/file/bot{}/{}'.format(bot_token,file_info.file_path)
convert_oga_to_mp3(audio_url)
audio_url = get_url_mp3(bot_token,message)
bot.infinity_polling()
Чтобы преобразовать аудио в mp3-файл, мы собираемся использовать оболочку ffmpeg, которая позволяет конвертировать различные аудиофайлы с помощью командной строки. Прежде чем воспользоваться ей, вам необходимо будет её установить. Если вы работаете на Windows, ознакомьтесь с этим руководством, в котором показаны все шаги, в то время как на Linux вам нужна только командная строка sudo apt install ffmpeg
.
После преобразования, достигнутого в строке 4 в функцию convert_oga_to_mp3
, нам нужно снова извлечь URL нового аудиофайла, который в конце будет иметь другой формат.
Расшифровка аудиозаписи песни
Теперь мы подошли к самой интересной части руководства, которая помогает нам достичь целей telegram-бота. Прежде чем идти дальше, войдите сюда, чтобы получить ключ API. Во-первых, мы хотим расшифровать аудио с помощью Steamship API. Функция transcribe_audio
принимает в качестве входных данных URL-адрес аудио, полученный ранее, и экземпляр Steamship, который представляет собой класс, предоставляющий функции и методы для многих приложений искусственного интеллекта. В данном случае речь идет о транскрипции звука.
# transcribe audio with Steamship's API
def transcribe_audio(audio_url: str, ship: Steamship):
instance = ship.use("audio-markdown", "audio-markdown-crows-v27")
transcribe_task = instance.invoke("transcribe_url", url=audio_url)
task_id = transcribe_task["task_id"]
status = transcribe_task["status"]
retries = 0
while retries <= 100 and status != TaskState.succeeded:
response = instance.invoke("get_markdown", task_id=task_id)
status = response["status"]
if status == TaskState.failed:
print(f"[FAILED] {response}['status_message']")
break
print(f"[Try {retries}] Transcription {status}.")
if status == TaskState.succeeded:
break
time.sleep(2)
retries += 1
markdown = response["markdown"]
return markdown
...
@bot.message_handler(content_types=['voice'])
def telegram_bot(message,bot_token=os.getenv("BOT_TOKEN")):
client = Steamship(api_key=os.getenv("STEAM_API_KEY"))
...
markdown = transcribe_audio(audio_url, client)
bot.reply_to(message, markdown)
bot.infinity_polling()
Код может быть обобщён несколькими строками:
- В строке 3 мы указываем, что собираемся использовать пакет
audio_markdown
для транскрибирования аудио, а затем генерировать выходные данные Markdown. - В следующей строке мы вызываем метод
transcribe_url
, вызываяinvoke
. Нам также нужно передать наш URL-адрес аудио. - В середине функции мы вызываем метод
get_markdown
, который позволит нам получить транскрипцию аудио. Количество повторных попыток ограничено 100, чтобы избежать бесконечных циклов в случае, если это не увенчается успехом. - Функция возвращает транскрипцию в конце, и мы получаем результирующий текст в telegram-боте.
Получение информации о песне
После получения транскрипции мы переходим к следующему шагу, который заключается в обнаружении названия и исполнителя песни. Это возможно реализовать с помощью SerpApi, который представляет собой API, позволяющий получать доступ к результатам Google и других веб-сайтов.
## search the trascription on Google using SerpAPI
def search_words(words):
params_serp = {
"q": words,
"hl": "en",
"gl": "us",
"google_domain": "google.com",
"api_key": params['API_KEY']
}
search = GoogleSearch(params_serp)
results = search.get_dict()
if 'organic_results' in results.keys():
if 'title' in results['organic_results'][0].keys():
return results['organic_results'][0]['title']
else:
return ''
else:
return ''
@bot.message_handler(content_types=['voice'])
def telegram_bot(message,bot_token=params["BOT_TOKEN"]):
...
client = Steamship(api_key=params["STEAM_API_KEY"])
markdown = transcribe_audio(audio_url, client)
bot.reply_to(message, markdown)
result = search_words(markdown)
...
if result == '':
bot.reply_to(message, 'Song not found!')
else:
bot.reply_to(message, result)
bot.infinity_polling()
Нам нужно передать словарь в GoogleSearch
с параметрами, такими как слова песни, ключ API SerpApi. Мы собираемся получить результаты от Google. Он возвращает вывод JSON, который может быть преобразован в словарь Python, чтобы получить доступ к информации. После этого отправителю будет отправлено текстовое сообщение.
Часть 2: Развёртывание Telegram-бота для Fly.io
До сих пор мы реализовывали процесс работы чат-бота, который произойдёт, если пользователь запустит следующую команду:
python bot.py
Но это означает, что бот будет работать только тогда, когда вы запустите этот код, а это непрактично. Предпочтительно, чтобы telegram-бот был всегда доступен и люди могли его опробовать.
По этой причине нам необходимо развернуть Telegram-бота. Сначала я хотел использовать Heroku, которая является ещё одной платформой с закрытым исходным кодом для развёртывания приложений, но она больше не предлагает бесплатный доступ.
Итак, я выбрал Fly.io как облачный сервис, потому что он предоставляет бесплатный тарифный план и имеет хорошую документацию.
- Создание requirements.txt и Dockerfile
- Подключение к Fly.io
- Запуск приложения
- Развёртывание приложения
1. Создание requirements.txt и Dockerfile
Чтобы запустить его в производство, нам нужен файл requirements.txt , который содержит все зависимости python. Он может быть автоматически создан путём запуска командной строки pipreqs в вашем терминале. Вы должны установить pipreqs, чтобы заставить командную строку работать. Это пакеты python, требуемые проектом:
google_search_results==2.4.1
pyTelegramBotAPI==4.9.0
python-dotenv==0.21.1
requests==2.28.1
steamship==2.3.5
В дополнение к этому файлу нам также нужен другой файл, называемый Dockerfile
, который должен быть таким:
FROM python:3.10.2
WORKDIR /bot
COPY requirements.txt /bot/
RUN pip install -r requirements.txt
RUN apt-get update
RUN apt-get install ffmpeg -y
RUN apt-get install nodejs -y
RUN apt-get install npm -y
COPY . /bot
CMD python bot.py
2. Подключение к Fly.io
Третье требование – это установка flyctl
, командной строки, которая позволит развернуть наше приложение. Вы можете найти инструкцию здесь. Она может отличаться в зависимости от вашей операционной системы.
Если вы не создали Fly.io учетная запись, вам необходимо сделать это, запустив командную строку:
flyctl auth signup
В случае, если у вас уже есть учетная запись, вам нужно только войти в систему, скопировав в терминал следующую строку:
fly auth login
3. Запуск приложения
Чтобы начать работу с этим проектом, мы можем ввести в командную строку следующий код:
flyctl launch
Он запросит у вас следующую информацию:
- Напишите название приложения.
- Выберите регион для развёртывания.
- Хотите ли вы настроить базу данных Postgresql. В нашем случае ответ – нет.
- Хотите ли вы создать резервную базу данных Redis прямо сейчас. В нашем случае ответ – нет.
- Хотите ли вы развернуть приложение прямо сейчас. На данный момент ответ – “нет”. Мы сделаем это позже.
Перед развёртыванием приложения я также решил использовать функциональность, предоставляемую fly.io . Как вы, возможно, знаете, учётные данные являются конфиденциальными, и вы можете предпочесть не раскрывать свои секреты никому, кроме себя. Это возможно, связав следующие командные строки:
flyctl secrets set BOT_TOKEN=<your_bot_token>
flyctl secrets set STEAM_TOKEN=<your_steam_api>
flyctl secrets set API_KEY=<your_serpapi_key>
После запуска этих командных строк необходимо изменить код python. Мы больше не используем файл JSON с учётными данными, которые хранятся непосредственно на платформе fly.io. Например, таким образом мы можем получить доступ к токену Telegram-бота:
from dotenv import load_dotenv
load_dotenv()
bot = telebot.TeleBot(os.getenv("BOT_TOKEN"))
Вам нужно сделать то же самое для других ключей API. Вы можете проверить список командных строк с помощью следующей команды:
flyctl secrets list
4. Развёртывание приложения
Наконец-то мы “достигли вершины Эвереста”! Ещё одна командная строка, и всё готово:
flyctl deploy
Таким образом, наш контейнер docker с telegram-ботом собран и развёрнут. Код будет запущен в облаке, а не на локальном компьютере. Теперь telegram-бот будет работать для всех!
Заключительные мысли:
Я надеюсь, вам понравился этот проект в области Data Science. В Интернете доступно множество ресурсов, которые позволяют получить всё, что вы хотите. Вам нужны только творческий подход, терпение и усердная работа. Если у вас есть какой-либо из этих ингредиентов, нет никаких ограничений на то, что вы можете сделать. Код на GitHub находится здесь. Спасибо вам за чтение!