Speech-to-text: Транскрибация Telegram Voice в текст используя OpenAI API
В статье рассмотрим как получить текст голосового сообщения в Telegram боте, используя API OpenAI.
Требования. У вас должна быть Linux система с установленным Python 3.10+. Если вы в России, потребуется VPN. В качестве Telegram фреймворка используется aiogram 3. Для успешного прохождения туториала необходимы некоторые знания aiogram 3.
Транскрибация — это перевод аудио в текст. В нашем случае: перевод голосового сообщения (voice) в текст.
OpenAI API
OpenAI API — это программный интерфейс приложения, который предоставляет доступ к технологиям искусственного интеллекта, разработанным и поддерживаемым OpenAI. Для решения нашей задачи нам понадобится модель Whisper от OpenAI.
Прежде чем продолжать, вам следует убедиться, что у вас есть доступ к OpenAI API. В данной статье описан подробный алгоритм регистрации и получения токена для использования OpenAI API: https://teletype.in/@loginovpavel/get-openai-token. Как только у вас удастся получить доступ, продолжайте.
Whisper Model — модель, способная транскрибировать аудио файлы в текст.
- Транскрибирование аудио файла на любом языке.
- Транскрибирование аудио файла и перевод текста на английский.
Для использования модели необходимо отправить байтовое представление аудио файла размером не более 25 мегабайтов в одном из доступных форматов на endpoint API. Мы будем использовать Python библиотеку openai для выполнения запросов к API в программе.
Пример из документации траскрибирующий аудио файл в текст:
# Листинг [1]
# Транскрибация аудио файла в текст
# Примечание: вам необходимо использовать
# OpenAI Python v0.27.0 для работы с этим кодом
import openai
audio_file = open("/path/to/file/german.mp3", "rb")
transcript = openai.Audio.translate("whisper-1", audio_file)Сперва открывается файл по пути "/path/to/file/german.mp3" в binary моде. Далее выполняется метод translate, который принимает название модели "whisper-1" и файл audio_file.
# Листинг [2]
# Ответ от модели, содержимое transcript
{
"text": "Текст аудио файла."
}Создание проекта и установка зависимостей
Для начала необходимо установить программу ffmpeg для работы с медиа файлами в ОС Linux. Это программа необходима для работоспособности одной из зависимостей проекта, подробнее о ней далее.
$ sudo apt install ffmpeg
Создайте папку с проектом и настройте виртуальное окружение. В окружение установите фреймворк aiogram 3 (для работы с Telegram API), библиотеку openai (для работы с OpenAI API) не ниже 0.27 версии и библиотеку pydub (для работы с аудио файлами).
$ pip install --pre aiogram $ pip install openai==0.27.0 $ pip install pydub
Для удобства будем работать в одном файле. Создайте новый файл bot.py и поместите туда следующий код. Поменяйте токен бота на свой.
# Листинг [3]
# Эхо бот на aiogram 3
import asyncio
from aiogram import Bot, Dispatcher, F, Router
from aiogram.types import Message
# Токен вашего телеграм бота
BOT_TOKEN = "5842123168:AAHyhAIFWeh4-8jYvo72eZeq18-9P2wQmaY"
router: Router = Router()
# Хендлер сообщений с которым будем работать
@router.message(F.content_type == "voice")
async def process_message(message: Message):
"""Принимает все голосовые сообщения и отвечает эхо."""
await message.answer(text="echo")
async def main():
bot: Bot = Bot(token=BOT_TOKEN)
dp: Dispatcher = Dispatcher()
dp.include_router(router)
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())У вас должна была получиться примерно следующая структура проекта:
project/ ├── env/ # Виртуальное окружение └── bot.py # Код с ботом
Запустите бота и проверьте работоспособность. На любое сообщение бот должен возвращать echo.
$ python bot.py
Если всё работает, двигаемся дальше.
Транскрибация аудио в текст
Продолжаем работать в файле bot.py, добавляя последующий код в него. Перед тем как начать работать с библиотекой openai, необходимо проинициализировать API токен. Импортируем библиотеку и инициализируем токен, который вы сгенерировали ранее.
# Листинг [4] # Инициализация openai ключа import openai openai.api_key = "sk-BhC44H9LVVtSE74BlbkGGtPs0OTGDx21tjPVu7bzl"
Выше был пример из документации OpenAI с транскрибацией (листинг №1). В нём использовался метод transcribe, класса Audio из модуля openai для создания запроса к OpenAI API. Также в классе Audio имеется метод atranscribe для выполнения этого же запроса, но в асинхронном режиме. Метод принимает два аргумента - название модели ("whisper-1") и файл для транскрибации.
# Листинг [5]
# Функция для транскрибации аудио файла
async def audio_to_text(file_path: str) -> str:
"""Принимает путь к аудио файлу, возвращает текст файла."""
with open(file_path, "rb") as audio_file:
transcript = await openai.Audio.atranscribe(
"whisper-1", audio_file
)
return transcript["text"]Функция принимает путь к аудио файлу file_path. Открывает файл на чтение в binary моде audio_file. Выполняет запрос методом atranscribe класса Audio, передавая название модели и сам файл. В листинге №2 указан формат ответа от модели, поэтому для возвращения результирующего текста обращаемся к ключу "text" ответа transcript.
Далее напишем функцию для сохранения голосового сообщения с сервера Telegram. Для этого подготовим директорию voice_files.
У вас должна была получиться следующая структура проекта:
project/ ├── env/ # Виртуальное окружение ├── voice_files/ # Хранилище войсов в .mp3 формате └── bot.py # Код с ботом
Импортируем io, Voice, AudioSegment.
# Листинг [6] # Необходимые импорты import asyncio import io from aiogram import Bot, Dispatcher, F, Router from aiogram.types import Message, Voice import openai from pydub import AudioSegment
# Листинг [7]
# Функция сохраняющая голосовое сообщение в mp3
async def save_voice_as_mp3(bot: Bot, voice: Voice) -> str:
"""Скачивает голосовое сообщение и сохраняет в формате mp3."""
voice_file_info = await bot.get_file(voice.file_id)
voice_ogg = io.BytesIO()
await bot.download_file(voice_file_info.file_path, voice_ogg)
voice_mp3_path = f"voice_files/voice-{voice.file_unique_id}.mp3"
AudioSegment.from_file(voice_ogg, format="ogg").export(
voice_mp3_path, format="mp3"
)
return voice_mp3_pathФункция принимает экземпляр бота bot для скачивания файлов и экземпляр голосового сообщения voice с необходимой информацией.
Голосовые сообщения скачиваются в формате .ogg, а модель Whisper с этим форматом не работает. Поэтому мы будем скачивать файл с сервера в переменную voice_ogg, затем конвертировать его в формат .mp3 в папку voice_files.
Метод bot.get_file принимает идентификатор файла голосового сообщения voice и возвращает информацию о файле. Нам нужен путь к файлу.
Создаем байтовую переменную voice_ogg в которую будет скачиваться голосовое сообщение с сервера в формате .ogg. Затем методом bot.download_file, который принимает путь к файлу на сервере и место назначения для сохранения, скачиваем файл. Передаем путь к файлу voice_file_info.file_path и место для сохранения voice_ogg.
Далее используем класс AudioSegment из библиотеки pydub для преобразования формата файла из .ogg в .mp3. Задаем путь для сохранения файла в переменную voice_mp3_path. Используем метод from_file для открытия файла и сразу же метод export для сохранения конвертированного файла по месту назначения, указывая форматы данных.
Функция возвращает путь к скаченному файлу.
Осталось за малым — соединить всё воедино в нашем обработчике. Для этого отредактируем его следующим образом:
# Листинг [8]
# Обработчик транскрибирующий голосовые сообщения
@router.message(F.content_type == "voice")
async def process_voice_message(message: Message, bot: Bot):
"""Принимает голосовое сообщение, транскрибирует его в текст."""
voice_path = await save_voice_as_mp3(bot, message.voice)
transcripted_voice_text = await audio_to_text(voice_path)
if transcripted_voice_text:
await message.reply(text=transcripted_voice_text)Наш обработчик process_voice_message принимает все голосовые сообщения пользователя, как указано в декораторе. Сперва идет вызов нашей функции save_voice_as_mp3 из листинга №7 для скачивания голосового сообщения в директорию voice_files в формате .mp3, она возвращает путь к скаченному файлу. Далее вызывается функция audio_to_text из листинга №5 для выполнения запроса к OpenAI API на транскрибацию. Функция возвращает текст аудио файла. Если модель разобрала речь, то возвращается не пустая строка, которую мы распечатываем в чат Telegram бота.
# Листинг [9]
# Телеграм бот транскрибирующий голосовые сообщения
import asyncio
import io
from aiogram import Bot, Dispatcher, F, Router
from aiogram.types import Message, Voice
import openai
from pydub import AudioSegment
openai.api_key = "sk-BhC44H9LVVtSE74BlbkGGtPs0OTGDx21tjPVu7bzl"
BOT_TOKEN = "5842123168:AAHyhAIFWeh4-8jYvo72eZeq18-9P2wQmaY"
router: Router = Router()
async def audio_to_text(file_path: str) -> str:
"""Принимает путь к аудио файлу, возвращает текст файла."""
with open(file_path, "rb") as audio_file:
transcript = await openai.Audio.atranscribe(
"whisper-1", audio_file
)
return transcript["text"]
async def save_voice_as_mp3(bot: Bot, voice: Voice) -> str:
"""Скачивает голосовое сообщение и сохраняет в формате mp3."""
voice_file_info = await bot.get_file(voice.file_id)
voice_ogg = io.BytesIO()
await bot.download_file(voice_file_info.file_path, voice_ogg)
voice_mp3_path = f"voice_files/voice-{voice.file_unique_id}.mp3"
AudioSegment.from_file(voice_ogg, format="ogg").export(
voice_mp3_path, format="mp3"
)
return voice_mp3_path
@router.message(F.content_type == "voice")
async def process_voice_message(message: Message, bot: Bot):
"""Принимает все голосовые сообщения и транскрибирует их в текст."""
voice_path = await save_voice_as_mp3(bot, message.voice)
transcripted_voice_text = await audio_to_text(voice_path)
if transcripted_voice_text:
await message.reply(text=transcripted_voice_text)
async def main():
bot: Bot = Bot(token=BOT_TOKEN)
dp: Dispatcher = Dispatcher()
dp.include_router(router)
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())В статье мы рассмотрели эффективный способ получения текстовых версий голосовых сообщений в Telegram боте, используя API OpenAI. Использование OpenAI API значительно упрощает процесс транскрибации голосовых сообщений и делает его более точным и надежным. Всем удачи в изучении!