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 значительно упрощает процесс транскрибации голосовых сообщений и делает его более точным и надежным. Всем удачи в изучении!