in my 雑記

プログラミング bump 日々のことなど

python3で音声ファイルをテキストにする

f:id:inmyzakki:20170902164248p:plain

はじめに

今回は前回の続きで、google speech apiで音声認識を行います。
google speech apiを使用する準備ができていない方は前回の記事を参考に、
登録やインストールを行ってください。

動かしてみる

公式のサンプルを動かしてみます。

GOOGLE_APPLICATION_CREDENTIALSの環境変数を設定します。

export GOOGLE_APPLICATION_CREDENTIALS='前回記事でDLした認証用jsonファイルのパス'

次にプロジェクト名の環境変数の設定をします。

export GCLOUD_PROJECT='プロジェクト名(jsonファイル内にも記載されているのでそれを参照に)'

以下のサンプル音源を落とします。
https://cloud.google.com/speech/docs/samples/audio.raw

以下のソースを「test.py」で保存します。
前回記事ではpythonのバージョンは2.7指定でしたが、
今回のソースはpython3.Xです。

"""Google Cloud Speech API sample application using the REST API for batch
processing."""

import argparse
import base64
import json

from googleapiclient import discovery
import httplib2
from oauth2client.client import GoogleCredentials

DISCOVERY_URL = ('https://{api}.googleapis.com/$discovery/rest?'
                 'version={apiVersion}')

def get_speech_service():
    credentials = GoogleCredentials.get_application_default().create_scoped(
        ['https://www.googleapis.com/auth/cloud-platform'])
    http = httplib2.Http()
    credentials.authorize(http)

    return discovery.build(
        'speech', 'v1beta1', http=http, discoveryServiceUrl=DISCOVERY_URL)

def main(speech_file):
    """Transcribe the given audio file.

    Args:
        speech_file: the name of the audio file.
    """
    with open(speech_file, 'rb') as speech:
        speech_content = base64.b64encode(speech.read())

    service = get_speech_service()
    service_request = service.speech().syncrecognize(
        body={
            'config': {
                'encoding': 'LINEAR16',  # raw 16-bit signed LE samples
                'sampleRate': 16000,  # 16 khz
                'languageCode': 'en-US',  # a BCP-47 language tag
            },
            'audio': {
                'content': speech_content.decode('UTF-8')
                }
            })
    response = service_request.execute()
    print(json.dumps(response))

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'speech_file', help='Full path of audio file to be recognized')
    args = parser.parse_args()
    main(args.speech_file)

あとは、以下のコマンドを実行するだけ。

python test.py audio.raw

だが、以下のエラーが発生した。

googleapiclient.errors.HttpError: <HttpError 400 when requesting https://speech.googleapis.com/v1beta1/speech:syncrecognize?alt=json returned "Unable to recognize speech, possible error in encoding or channel config. Please correct the config and retry the request.">

公式から落としたサンプルと音源なのに、エンコードやチャンネルの設定が悪いって怒られているみたいです。
私の環境周りが悪いのか?

ひとまず、原因切り分けのため他の公式音源でも試してみる。
http://storage.googleapis.com/speech-demo/shwazil_hoful.flac
これで、test.pyをflacの読み取りに変更する。

{
  "config": {
    "encoding":"FLAC",
    "sample_rate": 16000,
    "language_code":"en-US"
  },
  "audio":{
    "uri":"gs://speech-demo/shwazil_hoful.flac"
  }
}

再び実行。

python test.py shwazil_hoful.flac

今度はちゃんと結果が返ってきた。

python google_speech.py shwazil_hoful.flac
{"results": [{"alternatives": [{"transcript": "it's a swazzle hoffel day", "confidence": 0.70172733}]}]}

一応、flacで動いているようなので、 今度は自分で用意したmp3ファイルを音声認識します。

ffmpegでmp3を読み取れる形式にします。
ffmpegは以前の記事を参考に導入してください。
導入したら、以下のコマンドでtest.mp3をoutput.flacにします。

ffmpeg -I "test.mp3" -vn -ar 16000 -ac 1 -acodec flac -f flac "output.flac"

上記の変換形式に対応した音声ファイルは以下のコードで日本語のテキストに変換できます。
ついでに、テキストでも出力するようにしました。

# -*- coding: utf-8 -*-
"""Google Cloud Speech API sample application using the REST API for batch
processing."""

import argparse
import base64
import json
import codecs

import sys
import io

from googleapiclient import discovery
import httplib2
from oauth2client.client import GoogleCredentials

GOOGLE_APPLICATION_CREDENTIALS = 'hoge'

# デフォルト文字コードをutf8に変更
sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

DISCOVERY_URL = ('https://{api}.googleapis.com/$discovery/rest?'
                 'version={apiVersion}')

def get_speech_service():
    credentials = GoogleCredentials.get_application_default().create_scoped(
        ['https://www.googleapis.com/auth/cloud-platform'])
    http = httplib2.Http()
    credentials.authorize(http)

    return discovery.build(
        'speech', 'v1beta1', http=http, discoveryServiceUrl=DISCOVERY_URL)

def main(speech_file):
    """Transcribe the given audio file.

    Args:
        speech_file: the name of the audio file.
    """
    with open(speech_file, 'rb') as speech:
        speech_content = base64.b64encode(speech.read())

    service = get_speech_service()
    service_request = service.speech().syncrecognize(
        body={
            'config': {
                'encoding': 'FLAC',  # raw 16-bit signed LE samples
                'sampleRate': 16000,  # 16 khz
                'languageCode': 'ja-JP',  # a BCP-47 language tag
            },
            'audio': {
                'content': speech_content.decode('UTF-8')
                }
            })
    response = service_request.execute()
    f = codecs.open('test.txt', 'w', 'utf-8') # 書き込みモードで開く
    f.write(json.dumps(response, ensure_ascii=False)) # 引数の文字列をファイルに書き込む
    f.close() # ファイルを閉じる
    print(json.dumps(response, ensure_ascii=False))

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'speech_file', help='Full path of audio file to be recognized')
    args = parser.parse_args()
    main(args.speech_file)

以下のコマンドで変換できます。

python test.py output.flac

これで、自分の用意した音声ファイルをテキストに変換できます。
以上です。