Рубрики
Без рубрики

Как преобразовать записи речи в текст с помощью Python

Научитесь транскрибировать речь в записях, таких как MP3, в текст с помощью Python и AssemblyAI API.

Автор оригинала: Matt Makai.

Когда у вас есть запись, на которой говорят один или несколько человек, это полезно чтобы иметь высокоточный и автоматизированный способ извлечения произнесенных слов в текст. Получив текст, вы можете использовать его для дальнейшего анализа или как функция доступности.

В этом руководстве мы будем использовать веб-приложение для преобразования речи в текст с высокой точностью. интерфейс программирования под названием AssemblyAI для извлекать текст из записи MP3 (также поддерживаются многие другие форматы).

С помощью кода из этого руководства вы сможете получить аудиофайл что содержит речь например, этот пример, который я записал и выведите очень точную транскрипцию текста, например:

An object relational mapper is a code library that automates the transfer of 
data stored in relational, databases into objects that are more commonly used
in application code or EMS are useful because they provide a high level 
abstraction upon a relational database that allows developers to write Python 
code instead of sequel to create read update and delete, data and schemas in 
their database. Developers can use the programming language. They are 
comfortable with to work with a database instead of writing SQL...

(the text goes on from here but I abbreviated it at this point)

Требования к руководству

В этом руководстве мы будем использовать следующие зависимости: который мы установим буквально через мгновение. Убедитесь, что у вас также установлен Python 3, желательно установить 3.6 или новее , в вашей среде:

Мы будем использовать следующие зависимости, чтобы завершить это руководство:

Весь код в этом сообщении в блоге доступен с открытым исходным кодом по лицензии MIT. на GitHub в разделе каталог transcribe-speech-text-script репозитория blog-code-examples . Используйте исходный код по своему усмотрению для своих собственных проектов.

Настройка среды разработки

Перейдите в каталог, в котором вы храните свой Python виртуальные среды. Я храню свой в подкаталоге с именем venvs в доме моего пользователя каталог. Создайте новый virtualenv для этого проекта, используя следующие команда.

python3 -m venv ~/venvs/pytranscribe

Активируйте virtualenv с помощью сценария оболочки activate :

source ~/venvs/pytranscribe/bin/activate

После выполнения указанной выше команды в командной строке появится измените так, чтобы имя virtualenv добавлялось к исходный формат командной строки, поэтому, если ваша подсказка просто $ , теперь он будет выглядеть следующим образом:

(pytranscribe) $

Помните, что вы должны активировать виртуальный сервер в каждом новом терминале. окно, в котором вы хотите использовать зависимости в файле virtualenv.

Теперь мы можем установить пакет requests в активированный но в остальном пустой virtualenv.

pip install requests==2.24.0

Найдите вывод, подобный следующему, чтобы убедиться в правильности пакеты были установлены правильно из PyPI.

(pytranscribe) $ pip install requests==2.24.0
Collecting requests==2.24.0
  Using cached https://files.pythonhosted.org/packages/45/1e/0c169c6a5381e241ba7404532c16a21d86ab872c9bed8bdcd4c423954103/requests-2.24.0-py2.py3-none-any.whl
Collecting certifi>=2017.4.17 (from requests==2.24.0)
  Using cached https://files.pythonhosted.org/packages/5e/c4/6c4fe722df5343c33226f0b4e0bb042e4dc13483228b4718baf286f86d87/certifi-2020.6.20-py2.py3-none-any.whl
Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 (from requests==2.24.0)
  Using cached https://files.pythonhosted.org/packages/9f/f0/a391d1463ebb1b233795cabfc0ef38d3db4442339de68f847026199e69d7/urllib3-1.25.10-py2.py3-none-any.whl
Collecting chardet<4,>=3.0.2 (from requests==2.24.0)
  Using cached https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl
Collecting idna<3,>=2.5 (from requests==2.24.0)
  Using cached https://files.pythonhosted.org/packages/a2/38/928ddce2273eaa564f6f50de919327bf3a00f091b5baba8dfa9460f3a8a8/idna-2.10-py2.py3-none-any.whl
Installing collected packages: certifi, urllib3, chardet, idna, requests
Successfully installed certifi-2020.6.20 chardet-3.0.4 idna-2.10 requests-2.24.0 urllib3-1.25.10

У нас установлены все необходимые зависимости, поэтому мы можем начать кодирование приложения.

Загрузка, инициализация и расшифровка аудио

У нас есть все необходимое для создания нашего приложения, которое преобразует аудио в текст. Мы собираемся построить это приложение в трех файлах:

Создайте новый каталог с именем pytranscribe для хранения этих файлов как мы их пишем. Затем перейдите в новый каталог проекта.

mkdir pytranscibe
cd pytranscribe

Нам также необходимо экспортировать наш ключ API AssemblyAI в качестве переменной среды. Зарегистрируйте учетную запись AssemblyAI и войдите в панель управления AssemblyAI , затем скопируйте «Ваш токен API», как показано на этом снимке экрана:

Панель управления AssemblyAI.
export ASSEMBLYAI_KEY=your-api-key-here

Обратите внимание, что вы должны использовать команду export в каждом окне командной строки. что вы хотите, чтобы этот ключ был доступен. Сценарии, которые мы пишем, будут не сможете получить доступ к API, если у вас нет токена, экспортированного как ASSEMBLYAI_KEY в среде, в которой выполняется сценарий.

Теперь, когда у нас есть каталог нашего проекта и ключ API установлен как переменная окружения, перейдем к написанию кода для первого файла который загрузит аудиофайлы в сервис AssemblyAI.

Загрузка аудиофайла для транскрипции

Создайте новый файл с именем upload_audio_file.py и поместите следующие код в нем:

import argparse
import os
import requests


API_URL = "https://api.assemblyai.com/v2/"


def upload_file_to_api(filename):
    """Checks for a valid file and then uploads it to AssemblyAI
    so it can be saved to a secure URL that only that service can access.
    When the upload is complete we can then initiate the transcription
    API call.
    Returns the API JSON if successful, or None if file does not exist.
    """
    if not os.path.exists(filename):
        return None

    def read_file(filename, chunk_size=5242880):
        with open(filename, 'rb') as _file:
            while True:
                data = _file.read(chunk_size)
                if not data:
                    break
                yield data

    headers = {'authorization': os.getenv("ASSEMBLYAI_KEY")}
    response = requests.post("".join([API_URL, "upload"]), headers=headers,
                             data=read_file(filename))
    return response.json()

Приведенный выше код импортирует пакеты argparse , os и requests . так что мы можем использовать их в этом скрипте. API_URL – это постоянная с базовым URL-адресом службы AssemblyAI. Мы определяем upload_file_to_api функция с одним аргументом, filename это должна быть строка с абсолютным путем к файлу и его имя файла.

Внутри функции мы проверяем, существует ли файл, затем используем Request фрагментированное кодирование передачи для потоковой передачи больших файлов в AssemblyAI API.

Функция getenv модуля os считывает API, установленный на в командной строке с помощью команды export с getenv . Убедись что вы используете эту команду export в терминале, где вы находитесь запускаем этот скрипт, иначе значение ASSEMBLYAI_KEY будет пустой. В случае сомнений используйте echo $ ASSEMBLY_AI , чтобы проверить, соответствует вашему ключу API.

Чтобы использовать функцию upload_file_to_api , добавьте следующие строки код в файле upload_audio_file.py , чтобы мы могли правильно выполнить этот код как сценарий, вызываемый командой python :

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("filename")
    args = parser.parse_args()
    upload_filename = args.filename
    response_json = upload_file_to_api(upload_filename)
    if not response_json:
        print("file does not exist")
    else:
        print("File uploaded to URL: {}".format(response_json['upload_url']))

Приведенный выше код создает объект ArgumentParser , который позволяет приложение для получения единственного аргумента из командной строки чтобы указать файл, к которому мы хотим получить доступ, прочитать и загрузить в AssmeblyAI сервис.

Если файл не существует, сценарий выведет сообщение, которое файл не может быть найден. На счастливом пути, где мы находим правильный файл по этому пути, затем файл загружается с использованием код в функции upload_file_to_api .

Выполните завершенный скрипт upload_audio_file.py , запустив его на в командной строке с помощью команды python . Заменить FULL_PATH_TO_FILE с абсолютным путем к файлу, который вы хотите загрузить, например /Users/matt/devel/audio.mp3 .

python upload_audio_file.py FULL_PATH_TO_FILE

Предполагая, что файл найден в указанном вами месте, когда скрипт завершит загрузку файла, он распечатает сообщение, подобное этому с уникальным URL:

File uploaded to URL: https://cdn.assemblyai.com/upload/463ce27f-0922-4ea9-9ce4-3353d84b5638

Этот URL-адрес не является общедоступным, его может использовать только служба AssemblyAI, поэтому нет еще один сможет получить доступ к вашему файлу и его содержимому, кроме вас и их API транскрипции.

Важная часть – это последний раздел URL-адреса, в этом примере это 463ce27f-0922-4ea9-9ce4-3353d84b5638 . Сохраните этот уникальный идентификатор потому что нам нужно передать его в следующий скрипт, который инициирует услуга транскрипции.

Начать транскрипцию

Затем мы напишем код, чтобы начать транскрипцию. Создать новый файл с именем initiate_transcription.py . Добавьте следующее код в новый файл.

import argparse
import os
import requests


API_URL = "https://api.assemblyai.com/v2/"
CDN_URL = "https://cdn.assemblyai.com/"


def initiate_transcription(file_id):
    """Sends a request to the API to transcribe a specific
    file that was previously uploaded to the API. This will
    not immediately return the transcription because it takes
    a moment for the service to analyze and perform the
    transcription, so there is a different function to retrieve
    the results.
    """
    endpoint = "".join([API_URL, "transcript"])
    json = {"audio_url": "".join([CDN_URL, "upload/{}".format(file_id)])}
    headers = {
        "authorization": os.getenv("ASSEMBLYAI_KEY"),
        "content-type": "application/json"
    }
    response = requests.post(endpoint, json=json, headers=headers)
    return response.json()

У нас есть тот же импорт, что и в предыдущем скрипте, и мы добавили новая константа, CDN_URL , которая соответствует отдельному URL-адресу, где AssemblyAI хранит загруженные аудиофайлы.

Функция initiate_transcription по существу просто устанавливает один HTTP-запрос к AssemblyAI API для запуска транскрипции обработать аудиофайл по указанному URL-адресу. Вот почему передача file_id важна: это завершает URL-адрес аудиофайл, который мы просим AssemblyAI извлечь.

Завершите файл, добавив этот код, чтобы его можно было легко вызывается из командной строки с аргументами.

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("file_id")
    args = parser.parse_args()
    file_id = args.file_id
    response_json = initiate_transcription(file_id)
    print(response_json)

Запустите сценарий, выполнив команду python на initiate_transcription и передайте уникальный идентификатор файла вы сохранили с предыдущего шага.

# the FILE_IDENTIFIER is returned in the previous step and will
# look something like this: 463ce27f-0922-4ea9-9ce4-3353d84b5638
python initiate_transcription.py FILE_IDENTIFIER

API отправит ответ JSON, который этот скрипт распечатает в командная строка.

{'audio_end_at': None, 'acoustic_model': 'assemblyai_default', 'text': None, 
 'audio_url': 'https://cdn.assemblyai.com/upload/463ce27f-0922-4ea9-9ce4-3353d84b5638', 
 'speed_boost': False, 'language_model': 'assemblyai_default', 'redact_pii': False, 
 'confidence': None, 'webhook_status_code': None, 
 'id': 'gkuu2krb1-8c7f-4fe3-bb69-6b14a2cac067', 'status': 'queued', 'boost_param': None, 
 'words': None, 'format_text': True, 'webhook_url': None, 'punctuate': True, 
 'utterances': None, 'audio_duration': None, 'auto_highlights': False, 
 'word_boost': [], 'dual_channel': None, 'audio_start_from': None}

Обратите внимание на значение ключа id в ответе JSON. Это Идентификатор транскрипции, который нам нужен для получения результата транскрипции. В этом примере это gkuu2krb1-8c7f-4fe3-bb69-6b14a2cac067 . Скопируйте идентификатор транскрипции в вашем ответе, потому что он нам понадобится для проверьте, когда процесс транскрипции завершился на следующем шаге.

Получение результата транскрипции

Мы загрузили и начали процесс транскрипции, так что давайте результат, как только он будет готов.

Время, необходимое для получения результатов, может зависеть от размера файла, поэтому следующий скрипт отправит HTTP-запрос к API и отчитается статус транскрипции или распечатайте результат, если он завершен.

Создайте третий файл Python с именем get_transcription.py и поместите следующие код в него.

import argparse
import os
import requests


API_URL = "https://api.assemblyai.com/v2/"


def get_transcription(transcription_id):
    """Requests the transcription from the API and returns the JSON
    response."""
    endpoint = "".join([API_URL, "transcript/{}".format(transcription_id)])
    headers = {"authorization": os.getenv('ASSEMBLYAI_KEY')}
    response = requests.get(endpoint, headers=headers)
    return response.json()


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("transcription_id")
    args = parser.parse_args()
    transcription_id = args.transcription_id
    response_json = get_transcription(transcription_id)
    if response_json['status'] == "completed":
        for word in response_json['words']:
            print(word['text'], end=" ")
    else:
        print("current status of transcription request: {}".format(
              response_json['status']))

Приведенный выше код имеет тот же импорт, что и другие скрипты. В этом новую функцию get_transcription , мы просто вызываем AssemblyAI API с нашим ключом API и идентификатором транскрипции из предыдущего шаг (не идентификатор файла). Мы получаем ответ JSON и верни это.

В основной функции мы обрабатываем идентификатор транскрипции, который передается как аргумент командной строки и передается в get_transcription функция. Если ответ JSON от Функция get_transcription содержит статус completed , тогда мы распечатать результаты транскрипции. В противном случае распечатайте текущий статус: либо в очереди , либо обработка перед он завершен .

Вызов скрипта с помощью командной строки и идентификатора транскрипции из предыдущего раздела:

python get_transcription.py TRANSCRIPTION_ID

Если сервис еще не начал работать над расшифровкой стенограммы, то он вернет в очереди следующим образом:

current status of transcription request: queued

Когда сервис в настоящее время работает с аудиофайлом, он вернуть processing :

current status of transcription request: processing

Когда процесс будет завершен, наш скрипт вернет текст транскрипция, как вы видите здесь:

An object relational mapper is a code library that automates the transfer of 
data stored in relational, databases into objects that are more commonly used
in application code or EMS are useful because they provide a high level 

...(output abbreviated)

Вот и все, у нас есть транскрипция!

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

Что дальше?

Мы только что закончили писать сценарии, которые вызывают API AssemblyAI для транскрибировать записи с речью в текстовый вывод.

Затем взгляните на более сложную документацию, которая идет помимо основ в этом руководстве:

Вопросов? Сообщите мне через тикет о проблеме на репозиторий Full Stack Python , в Твиттере @fullstackpython или @mattmakai . Что-то не так с этим сообщением? Вилка источник этой страницы на GitHub и отправьте запрос на перенос.