GoogleのSpeech APIを使ってみた

# GoogleのSpeech APIを使ってみた

GoogleのSpeech APIを使ってみたので、それを記述する。

## 事前準備
GoogleのGCPとの契約。クレジットがある方はクレジットを用意してアカウントを作って下さい。
ここでは既にあるものとして、進めます。   
まずはプロジェクトを作成し、
ログイン後、左のメニューからライブラリを選択し、  「Google Cloud Machine Learning」の「Speech API」を選びます。
もし、有効になっていなければ有効にしてください。
そして、APIを呼び出すためのAPIキーを作成します。「APIとサービス」から認証情報を選択し「認証情報を作成」をしてAPIキーを作ります。
本来であれば、サービオアカウント、ユーザアカウントなどがありあｍすが、まずは手っ取り早くＡＰＩキーでやります。(推奨はサービスカウント)
* プロジェクト名
GoogleSpeechTest

* APIキー
xxxxxxxxx


が表示されるので、メモっておきます。  

## テストデータの実行
Linuxのコンソールなどでcurlで接続してみます。
テストデータが既にあるようなので、それを使います。

```bash
ubuntu@test1:~$ more sync-request.json
{
  "config": {
      "encoding":"FLAC",
      "sampleRate": 16000
  },
  "audio": {
      "uri":"gs://cloud-samples-tests/speech/brooklyn.flac"
  }
}
ubuntu@test1:~$
```
```bash
ubuntu@test1:~$ curl -X POST   -H "Accept: application/json" -H "Content-type: application/json" --data @sync-request.json https://speech.googleapis.com/v1beta1/speech:syncrecognize?key={API_KEY}
{
  "results": [
    {
      "alternatives": [
        {
          "transcript": "how old is the Brooklyn Bridge",
          "confidence": 0.987629
        }
      ]
    }
  ]
}
ubuntu@test1:~$
```
OK。無事に接続できています。

## 実際のデータの投入


まずは以下のファイルを作る必要があるのでその準備をします。

```bash
{
    'config': {
      'encoding':'FLAC',
      'sampleRate':16000,
      'languageCode':'ja-JP'
    },
    'audio': {
      'content': 'ZkxhQwAAACIQABAAAAUJABtAA+gA8AB+W8FZndQvQAyjv...'
    }
  }
```
### 音声ファイルの準備
音声のファイルはFLACでやってみるので以前使ったデータをそのままmp3⇒flacに変換します。
ffmpegがない方はインストールしてください。

```bash
ubuntu@test1:~$ ffmpeg -i rd319.mp3  output.flac
```
次にこの音声ファイルをbase64エンコードしたものをjsonファイルに格納する。

```bash
ubuntu@test1:~$ echo -e  "{\n 'config':{\n 'encoding':'FLAC',\n 'sampleRate':16000,\n   'languageCode':'ja-JP' \n   }, \n   'audio': { \n    'content': '`base64 output.flac -w
0` \n } \n }\n" >json_data
```
で、実行すると

```bash
ubuntu@test1:~$ curl -X POST   -H "Accept: application/json" -H "Content-type: application/json" --data @json_data https://speech.googleapis.com/v1beta1/speech:syncrecognize?ke
y={API_KEY}
{
  "error": {
    "code": 400,
    "message": "sample_rate_hertz (16000) in RecognitionConfig must either be unspecified or match the value in the FLAC header (44100).",
    "status": "INVALID_ARGUMENT"
  }
}
```
と言われてしまいました。どうやらrateが違うようなので、再度jsonファイルを16000を44100に変更してみることに。

```bash
ubuntu@test1:~$ curl -X POST   -H "Accept: application/json" -H "Content-type: application/json" --data @json_data https://speech.googleapis.com/v1beta1/speech:syncrecognize?key={API_KEY}
{
  "error": {
    "code": 400,
    "message": "Sync input too long. For audio longer than 1 min use LongRunningRecognize with a 'uri' parameter.",
    "status": "INVALID_ARGUMENT"
  }
}
```
今度は・・・長すぎるようです。どうやら調べてみると1分以上のものはuriを使ってgcpのストレージに上げないといけない模様。
ということで・・・それをやると大変なので元の音声ファイルをカットします。元のデータは76秒ほどなので
まず、最初の20秒を切り取り、20秒から最後までのファイルと2つを作成し、それぞれのデータをbase64にしてjsonファイルを2つ作ります。

```bash
ffmpeg -i output.flac  -t 20 cut1.flac
ubuntu@test1:~$ echo -e  "{\n \"config\":{\n \"encoding\":\"FLAC\",\n \"sampleRate\":44100,\n   \"languageCode\":\"ja-JP\" \n   }, \n   \"audio\": { \n    \"content\": \"`base64 cut1.flac -w 0`\" \n } \n }\n" >json_data
ubuntu@test1:~$
ubuntu@test1:~$ echo -e  "{\n \"config\":{\n \"encoding\":\"FLAC\",\n \"sampleRate\":44100,\n   \"languageCode\":\"ja-JP\" \n   }, \n   \"audio\": { \n    \"content\": \"`base64 cut2.flac -w 0`\" \n } \n }\n" >json_data2
```
まあ、先ほどのoutput.flacを変更しているだけです。
で、実行。

```bash
ubuntu@test1:~$ curl -X POST   -H "Accept: application/json" -H "Content-type: application/json" --data @json_data https://speech.googleapis.com/v1beta1/speech:syncrecognize?ke
y={API_KEY}  | jq  -r '.results[].alternatives[].transcript'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  696k    0   237  100  695k     36   106k  0:00:06  0:00:06 --:--:--     0
小川未明作海と太陽くんには昼寝る夜も寝るいびきをかいて寝る
ubuntu@test1:~$
ubuntu@test1:~$ curl -X POST   -H "Accept: application/json" -H "Content-type: application/json" --data @json_data2 https://speech.googleapis.com/v1beta1/speech:syncrecognize?key={API_KEY}  | jq  -r '.results[].alternatives[].transcript'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 1968k    0  1049  100 1967k     69   131k  0:00:14  0:00:14 --:--:--     0
昔昔大昔海が初めて口開けて笑った時に
太陽はねうお回して驚いた
可愛い花屋人たちを海が飲んでしまう優しく光る太陽は
魔術でウニを眠らした
恵庭昼寝る夜も寝る
ゴーゴーいびきをかいて寝る
ubuntu@test1:~$
```

どうでしょう？まあ、なかなかよさげな感じがします。
本来認識して欲しいもの

```bash
小川 未明 作

海と太陽
海は昼眠る、夜も眠る、
ごうごう、いびきをかいて眠る。
昔、昔、おお昔
海がはじめて、口開けて、
笑ったときに、太陽は、
目をまわして驚いた。
かわいい花や、人たちを、
海がのんでしまおうと、
やさしく光る太陽は、
魔術で、海を眠らした。
海は昼眠る、夜も眠る。
ごうごう、いびきをかいて眠る。
```

## プログラムからの実行
GoogleのSpeech APIにはSDKがあるため、今度はpythonでやってみる。
### SDKのインストールと認証の設定

```bash
ubuntu@test1:~$ wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-158.0.0-linux-x86_64.tar.gz?hl=ja
ubuntu@test1:~$ tar zxvf google-cloud-sdk-158.0.0-linux-x86_64.tar.gz?hl=ja
ubuntu@test1:~$ ./google-cloud-sdk/install.sh
ubuntu@test1:~$ ./google-cloud-sdk/bin/gcloud init
```

上記コマンドを打つと、URLが表示されるのでそのURLをブラウザで開き、コードをコンソールに打ち込んで使用するプロジェクトを指定する。
次にpythonのモジュールをインストールする。
プログラムで認証を行うため、サービスキーをjson形式でダウンロードし、保存して環境変数を指定してプログラムを実行する。

```bash
ubuntu@test1:~$ pip install --upgrade google-cloud-speech
ubuntu@test1:~$ export GOOGLE_APPLICATION_CREDENTIALS=/home/ubuntu/google/stt/app_key.json
ubuntu@test1:~/google/stt$ python stt1.py
Traceback (most recent call last):
  File "/home/ubuntu/.pyenv/versions/3.4.3/lib/python3.4/site-packages/google/gax/retry.py", line 121, in inner
    return to_call(*args)
  File "/home/ubuntu/.pyenv/versions/3.4.3/lib/python3.4/site-packages/google/gax/retry.py", line 68, in inner
    return a_func(*updated_args, **kwargs)
  File "/home/ubuntu/.pyenv/versions/3.4.3/lib/python3.4/site-packages/grpc/_channel.py", line 492, in __call__
    return _end_unary_response_blocking(state, call, False, deadline)
  File "/home/ubuntu/.pyenv/versions/3.4.3/lib/python3.4/site-packages/grpc/_channel.py", line 440, in _end_unary_response_blocking
    raise _Rendezvous(state, None, None, deadline)
grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with (StatusCode.INVALID_ARGUMENT, Sync input too long. For audio longer than 1 min use LongRunningRecognize with a 'uri' parameter.)>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "stt1.py", line 29, in <module>
    response = client.recognize(config, audio)
  File "/home/ubuntu/.pyenv/versions/3.4.3/lib/python3.4/site-packages/google/cloud/gapic/speech/v1/speech_client.py", line 201, in recognize
    return self._recognize(request, options)
  File "/home/ubuntu/.pyenv/versions/3.4.3/lib/python3.4/site-packages/google/gax/api_callable.py", line 452, in inner
    return api_caller(api_call, this_settings, request)
  File "/home/ubuntu/.pyenv/versions/3.4.3/lib/python3.4/site-packages/google/gax/api_callable.py", line 438, in base_caller
    return api_call(*args)
  File "/home/ubuntu/.pyenv/versions/3.4.3/lib/python3.4/site-packages/google/gax/api_callable.py", line 376, in inner
    return a_func(*args, **kwargs)
  File "/home/ubuntu/.pyenv/versions/3.4.3/lib/python3.4/site-packages/google/gax/retry.py", line 127, in inner
    ' classified as transient', exception)
google.gax.errors.RetryError: RetryError(Exception occurred in retry method that was not classified as transient, caused by <_Rendezvous of RPC that terminated with (StatusCode.INVALID_ARGUMENT, Sync input too long. For audio longer than 1 min use LongRunningRecognize with a 'uri' parameter.)>)
ubuntu@test1:~/google/stt$
```
ということでやはり長いのでエラーになっている。ということで先ほどの2つのファイルで実行する。コードは以下の通り。

```python:stt1.py
import io
import os

# Imports the Google Cloud client library
from google.cloud import speech
from google.cloud.speech import enums
from google.cloud.speech import types

# Instantiates a client
client = speech.SpeechClient()

# The name of the audio file to transcribe
file_name = os.path.join(
    os.path.dirname(__file__),
    'cut1.flac')

# Loads the audio into memory
with io.open(file_name, 'rb') as audio_file:
    content = audio_file.read()
    audio = types.RecognitionAudio(content=content)

config = types.RecognitionConfig(
    encoding=enums.RecognitionConfig.AudioEncoding.FLAC,
    sample_rate_hertz=44100,
    language_code='ja-JP')

# Detects speech in the audio file
response = client.recognize(config, audio)

for result in response.results:
    print(format(result.alternatives[0].transcript))
```

``` bash
ubuntu@test1:~/google/stt$ python stt1.py
小川未明咲く海と太陽には昼寝る夜も寝るゴーゴーいびきをかいて寝る
ubuntu@test1:~/google/stt$ python stt2.py
昔昔大昔海が初めて口開けて笑った時に
体温はねうおまわして驚いた
可愛い花屋人たちを上にが飲んでしまう優しく光る太陽は
魔術でウニを眠らした
恵庭昼寝る夜も寝る
ゴーゴーいびきをかいて寝る
ubuntu@test1:~/google/stt$
```
こんな感じでとれました。
一部、認識が弱いのがありますね・・・。