Pull to refresh

Распознание длинных аудио сервисом Yandex SpeechKit из командной строки bash/shell через API

Reading time5 min
Views7.4K

Довольно давно Яндекс предоставляет платные сервисы по синтезу и распознанию речи. К сожалению, интерфейса для регулярного использования сервисов нет, поэтому на досуге написал скрипт, который позволяет через консоль взаимодействовать с Яндексом.

Как это работает и зачем вообще нужно

Есть много разных (в том числе бесплатных) возможностей как синтеза, так и распознания речи. Яндекс и Сбер предлагают свои сервисы по распознанию, у Яндекса это speech-kit, у Сбера SmartSpeech (до конца 2021 года даёт бесплатный доступ).

Экономика распознания очень простая: на рынке услуги стоят от 10 рублей за минуту, плюс вопросы к скорости и качеству и много чего ещё. Бесплатные варианты не рассматривали, так как нужно было решение сразу более-менее готовое. Яндекс предлагает цену в 1 рубль за минуту, при скорости распознания в 10 раз быстрее чем длительность дорожки. Если скорость не важна, то цена вообще 25 копеек.

Полученный результат в чистом виде использовать нельзя, это просто набор строчек, разбитых по паузам (более-менее соответствует предложениям), без знаков препинания. Кстати сервис Сбера обещает расставлять запятые, но его пока не пробовал.

Итак, то, что предлагает Яндекс (и другие), пока что просто вспомогательный инструмент, который, впрочем, может значительно ускорить определенные процессы. На рынке уже появились организации, которые на основе их решений предлагают транскрибацию. Если коротко, то получается так: загружается дорожка, получается сырой текст, который берет в работу человек, пересушивает, вносит правки. Экономия времени – нужно меньше печатать.

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

Чтобы начать, нужно:

  • Создать платёжный аккаунт (Яндекс даёт гранты на тестовое использование)

  • Создать сервисный аккаунт

  • Создать бакет на Яндекс-облаке

Два простых запроса

У Яндекса есть свой CLI для работы с командой строкой, нужно его поставить. Дальше в целом тут всё просто, один запрос на распознание, второй запрос на получение результата. Собственно, всё строится вокруг деталей этих двух запросов.

Запрос на распознание:

curl -sX POST \
    -H "Authorization: Api-Key <ключ-api-сервисного-аккаунта>" \ 
    -d '@params.json' \
    https://transcribe.api.cloud.yandex.net/speech/stt/v2/longRunningRecognize

В заголовке передаём ключ-api от сервисного аккаунта, и нужно сформировать файл params.json. В нём прописываются: язык распознания, модель (доступно 4 вида) и ссылка на файл для распознания.

cat > params.json << -EOF
{
    "config": {
    "specification": {
        "languageCode": "ru-RU", 
        "model": "hqa"
        }
    },
        "audio": {
            "uri": "https://storage.yandexcloud.net/<имя-бакета>/<путь-к-файлу>"
        }
    }
-EOF

Если с языком и моделью всё в целом, ясно, то с адресом файла возникают определенные сложности. Сам Яндекс подробно описывает как можно закинуть файл в облако своими руками прямо в браузере, а вот, как это делать из командной строки, выяснить сложнее.

Оказывается, Яндекс-облако работает на CLI Амазона, который тоже нужно поставить отдельно, другого способа закинуть файл в бакет, я не нашёл.

После установки, получаем следующую строчку для загрузки файла:

aws --endpoint-url=https://storage.yandexcloud.net \
    s3 cp <название-файла> s3://<имя-бакета>/<название-файла>

Запрос на результат распознания:

curl -sH "Authorization: Api-Key <ключ-api-сервисного-аккаунта>" \
    https://operation.api.cloud.yandex.net/operations/{operationId} 

Чтобы его отправить нам нужно знать id операции {operationID}, но об этом ниже.

Получаем набор из трёх команд:

  1. Загрузка файла

  2. Запрос на распознание

  3. Запрос на результат распознания

Ответ на запрос на распознание, извлечение id операции

Загружаем файл (получаем адрес его ссылки), отправляем запрос на распознание, дальше опять начинаются детали. После отправки запроса на распознание приходит вот такой ответ:

{
 "done": false,
 "id": "e03sup6d5h7rq574ht8g",
 "createdAt": "2019-04-21T22:49:29Z",
 "createdBy": "ajes08feato88ehbbhqq",
 "modifiedAt": "2019-04-21T22:49:29Z"
}

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

grep 'id' <имя-файла> | sed 's/^.*: "//' | sed 's/",*$//'

Теперь можно сформировать запрос на получение результата.

Запрос результата

Ответ на запрос приходит двух видов: готов ("done": true) и не готов ("done": false),  возникает необходимость проверки условия, если результат не готов, то нужно отправить ещё запрос, если готов, то можно извлекать текст.

Можно работать с тем же файлом, куда сохранялся результат вывода запроса на распознание, можно перенаправить вывод в другой файл. Теперь при помощи grep можно проверить статус операции и если результата нет гонять её по кругу, пока не будет получен успех.

curl -sH "Authorization: Api-Key <ключ-api-сервисного-аккаунта>" \
    https://operation.api.cloud.yandex.net/operations/{operationID} > log.txt

isready=$(grep 'done' log.txt | sed 's/^.*: //' | sed 's/,*$//')

if [[ $isready == "false" ]]; then
    while [[ $isready == "false" ]]; do
        curl -sH "Authorization: Api-Key <ключ-api-сервисного-аккаунта>" \
            https://operation.api.cloud.yandex.net/operations/{operationID} > log.txt
        isready=$(grep 'done' log.txt | sed 's/^.*: //' | sed 's/,*$//')
        sleep 60 # пожалеем сервер не будем спамить без конца
        if [[ $isready == "true" ]]; then		
            break
        fi	
    done
fi

Если распознание завершено, придёт ответ, который нужно привести в нормальный вид. При помощи grep и sed оставляем строчки с текстом, сохраняем в файл result.txt.

grep "text" log.txt | sed 's/^.*: "//' | sed 's/",*$//' | sed -e G > result.txt

В итоге получаем вот такой нехитрый набор из 5 команд, который можно собрать в скрипт:

#Загрузка файла в облако
aws --endpoint-url=https://storage.yandexcloud.net \
            s3 cp <название-файла> s3://<имя-бакета>/<название-файла> 

#Создание файла с параметрами
cat > params.json << -EOF
{
    "config": {
    "specification": {
        "languageCode": "ru-RU", 
        "model": "hqa"
    }
},
    "audio": {
         "uri": "https://storage.yandexcloud.net/<имя-бакета>/<путь-к-файлу>"
     }
}
-EOF

#Запрос на распознание
curl -sX POST \
    -H "Authorization: Api-Key <ключ-api-сервисного-аккаунта>" \ 
    -d '@params.json' \
        https://transcribe.api.cloud.yandex.net/speech/stt/v2/longRunningRecognize > log.txt

#Запрос результата распознания
isready=$(grep 'done' log.txt | sed 's/^.*: //' | sed 's/,*$//')
if [[ $isready == "false" ]]; then
    while [[ $isready == "false" ]]; do
        curl -sH "Authorization: Api-Key <ключ-api-сервисного-аккаунта>" \
            https://operation.api.cloud.yandex.net/operations/{operationID} > log.txt 
        isready=$(grep 'done' log.txt | sed 's/^.*: //' | sed 's/,*$//')
        sleep 60 
        if [[ $isready == "true" ]]; then
            grep "text" log.txt | sed 's/^.*: "//' | sed 's/",*$//' | sed -e G > result.txt
            exit
        fi
    done
fi

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

Выложил на github более-менее законченную версию с минимальным учётом всех возможных сценариев работы, если кому-то надо.

Tags:
Hubs:
Total votes 4: ↑4 and ↓0+4
Comments15

Articles