Google Speech APIを使えるようになるまで


近頃,音声認識を使ったプログラムを作りたいということで調査をしていて,いろんな人から「精度良いよ」という噂を聞いたGoogle Speech APIを使おうという所まで思い至ったのですが,実際に動かそうとすると,ハマる所がいくつかあったのでメモしておきます.

何ができるの?

Google Speech APIは,Googleの音声認識の技術を利用するためのAPI.

このAPIは,音声ファイルを入力に取り,その音声に対応するもっともらしい自然文を確信度付きで出力する.
現在はver.2が稼働しているらしい.

APIのユーザ登録

Google Speech APIの利用にはGoogle Developer Consoleでの登録が必要.

Google Developer Console

Google Developer Console
https://console.developers.google.com/project

この辺,以前にGoogle APIを使ったことがあるかどうかで,インタフェースが大きく異なると思われる.
自分の手順はあくまで参考程度として捉えてもらえると.

「Google APIを利用する」をクリック.

適当なプロジェクト名とプロジェクトIDを入力してプロジェクトを作成.
作成されたプロジェクト名をクリックしてダッシュボードへ移動.

ここで,「Google API」タブの中にSpeech APIが含まれていると思って探してみたが,見当たらなかった(ここでめちゃくちゃハマった).

Chrome-devグループへの加入

こちらの記事によると,日本からSpeech APIを有効化するには,Chrome-devグループに加入する必要があるらしい.

「投稿するにはグループに参加してください」をクリックして加入(メアドにメーリスの通知が来るので注意?).

APIの有効化とキーの入手

グループへの加入ができれば,Google Speech APIが検索できるようになっているので,「APIを有効にする」をクリックして有効化(画像2枚目はすでに有効化した後なので,ボタンが「APIを無効にする」になっている).

「認証情報」タブから,

「新しい認証情報」 -> 「APIキー」 -> 「サーバーキー」を選択.

適当なサーバーキーの名前を入力して,「作成」をクリックすると,API用のキー(文字列)が得られるので,この値のメモを取っておく.

これでAPIを利用するための準備はできた.

APIを利用してみる

環境は
OS: Mac OS X 10.11
マイク: Macbook Air Mid 2013の内蔵マイク

とりあえず利用例に追従

ここで,あるGithubリポジトリ("Reverse Engineering"とか書いてあってちょっとこわい)にあった利用例にしたがって,一度APIを利用してみる.
https://github.com/gillesdemey/google-speech-v2
このページには,APIの仕様らしきものも載っているので,参考にするとよい.

$ cd
$ mkdir src/
$ cd src/
$ git clone https://github.com/gillesdemey/google-speech-v2.git
$ cd google-speech-v2/

$ curl -X POST \
--data-binary @'audio/hello (16bit PCM).wav' \
--header 'Content-Type: audio/l16; rate=16000;' \
'https://www.google.com/speech-api/v2/recognize?output=json&lang=en-us&key=<your api key>'
# {"result":[]}
# {"result":[{"alternative":[{"transcript":"hello Google","confidence":0.98762906},{"transcript":"hello Google Now"},{"transcript":"hello Google I"}],"final":true}],"result_index":0}

自分で録音した音源を読み込ませてみる

WAVファイルについては,上記ページにあるように,

# homebrewが使える環境で
$ brew install sox
$ rec --encoding signed-integer --bits 16 --channels 1 --rate 16000 test.wav
rec WARN formats: can't set sample rate 16000; using 44100
rec WARN formats: can't set 1 channels; using 2
# ↑こんな記述があるが,実際にできたファイルは,サンプリング周波数16,000Hz,1チャンネルになっている…

Input File     : 'default' (coreaudio)
Channels       : 2
Sample Rate    : 44100
Precision      : 32-bit
Sample Encoding: 32-bit Signed Integer PCM

In:0.00% 00:00:11.15 [00:00:00.00] Out:177k  [      |      ]        Clip:0
# 内蔵マイクにて録音中.Ctrl+Cで終了

とすることで,

SoX
http://sox.sourceforge.net/
を用いた録音ができるようだ.
(もちろん,これを使わなくても,16bitPCMの音源を用意できればOK.)

ここで,試しに「こんにちは」という声を録音してみた.

種別
ファイル名 test.wav
フォーマット WAVE
ビット数 16
変調方式 PCM
チャンネル数 2

このtest.wavに対し,

$ curl -X POST \
--data-binary @'test.wav' \
--header 'Content-Type: audio/l16; rate=16000;' \
'https://www.google.com/speech-api/v2/recognize?output=json&lang=ja-JP&key=<your api key>'
{"result":[]}
{"result":[{"alternative":[{"transcript":"こんにちは","confidence":0.95324326},{"transcript":"こんにちわ"},{"transcript":"コンニチワ"},{"transcript":"こんにちゎ"}],"final":true}],"result_index":0}

とすることで,ちゃんと録音した声に対応する文字列が得られた.

リクエストヘッダに音源のMIME typeとサンプリング周波数を記述する必要がある.
また,微妙にパラメータlangを'en-js'から'ja-JP'に変更して,日本語対応させていることにも注意.

スクリプトを書いてみる

ここからは完全におまけ.
一応HTTPに対応しているのであれば,スクリプトからもリクエスト送れるよね,という話.

Pepperハンズオン ~基本編B 音声認識~ Google Speech APIを使ってPepperにあなたの名前を知ってもらう [Tech-Circle#7]
↑こちらを参考にさせていただいた.

認識させたい音声データは,先程と同様にしてWAV形式で用意(test.wav).
このファイルが以下のスクリプトと同一のディレクトリに置いてあるとする.

以下はPython3のコード.例えば,test.pyとする.

test.py
import sys
import json
import urllib.parse
import urllib.request

apikey = 'your api key'
endpoint = 'http://www.google.com/speech-api/v2/recognize'
query_string = {'output': 'json', 'lang': 'ja-JP', 'key': apikey}

url = '{0}?{1}'.format(endpoint, urllib.parse.urlencode(query_string))

headers = {'Content-Type': 'audio/l16; rate=16000'}
voice_data = open(sys.argv[1], 'rb').read()

request = urllib.request.Request(url, data=voice_data, headers=headers)
response = urllib.request.urlopen(request).read()

# 出力が複数行のJSONなので,不要そうなものを削除
for line in response.decode('utf-8').split():
    if not line:
        continue
    else:
        res = json.loads(line)
        if res['result'] == []:
            continue
        else:
            print(res)
$ python test.py test.wav
{'result_index': 0, 'result': [{'final': True, 'alternative': [{'confidence': 0.95324326, 'transcript': 'こんにちは'}, {'transcript': 'こんにちわ'}, {'transcript': 'コンニチワ'}, {'transcript': 'こ んにちゎ'}]}]}

その他注意点

  • 無料版では1日50回程度の実行に限られる(実際にはもう少し動かせるらしいが).
  • 思いの外実行時間がかかる(10秒弱の音声ファイルに対して,実行時間が約10秒程度).
  • 上記Githubページにも記載があるが,このAPIは主として10-15秒程度の音声ファイルに対応しているらしく,長すぎる/短すぎる音声には正確な答えを返せない可能性が高い.録音時のコツとして,喋っている時間が長くない場合でも音声ファイル全体の長さは10秒程度に揃えるようにすると,うまく拾ってくれる気がした.
  • 自分が確認した限りでは,16bitPCM,44,100Hzと16,000Hzの音声ファイルについて,うまく認識できた(1チャンネルのもののみ).flac形式にも対応しているらしいが,よくわからない.
  • なぜかレスポンスのJSONが複数行になって返ってくることがある.仕様がわからないので,その他のパラメータについてもなんとなく意味を推測するほかない.

やってみた感想

やはり精度は高いと思います.
長文とか,少し聞き取りづらい感じで声を出してもわりと拾ってくれます.
欠点を言うと,実行時間がかかる,かつ,ファイルにより精度がまちまちといった所から,リアルタイム性,ある程度の正確性を必要とするアプリで使うのは少し厳しいかな,という感じです.スマホで動いている奴はもっと速くて精度高いような気もしますが
その辺差し引いても,これが無料で使えるのは純粋にすごいと思いました.

欲を言えば,1年前ぐらいに試した参考記事とAPI登録のインタフェース全然違うし,そもそもメーリス入らないと使えないし,公式の仕様書見当たらないし,その辺いろいろひどいと思うので改善していただきたいですね…

その他の参考資料

On the use of Google’s Speech Recognition API Version 2 | Similar Sounds
Google Speech API ver.2の使い方
Google Speech APIをRubyから使う - Qiita
Google音声認識(Speech API)のAPIキー取得方法 | Eyepod touch