Google Cloud Speech gRPC API を使ってストリーム音声認識をしたい！（簡易VAD付けた）

# 新しく説明を書きました（メモ的なもの・・・）
【Macでpython3でGoogle Cloud Speech gRPC API を使ってストリーム音声認識をする！】
http://qiita.com/sayonari/items/4656212b4d34714ab98f

# やりたいこと
2016年7月20日に公開された，Google Cloud Speech APIを使ってみたい！

使ってみた結果の動画です↓
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Qiitaに貼り付けるようの動画．googleの音声認識（ストリーミング版）のテスト●GoogleCloudSpeechAPI streaming demo (Japanese) <a href="https://t.co/K6yfWE6M5M">https://t.co/K6yfWE6M5M</a> </p>&mdash; さよなりω/西村良太博士（工学） (@sayonari) <a href="https://twitter.com/sayonari/status/779227119767334912">2016年9月23日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

実際に使ってみると，以下の点で優れていると感じました．

- 日本語の音声認識が良くできる
- 日本語語彙がとても多い（競合他社サービスより）
- マイクの違いや環境雑音なんかにも強い感じ

Google Cloud Speech APIには，以下の2つのモードがあります．

- non-streaming mode
- streaming mode

streamingの方は，音声入力が開始されると同時に，その音声を順番にgoogleに送信し，喋りながら音声が認識されていくというものです．

streamingでない場合（発話が終了したあと，音声を送信して音声認識するもの）は，音声認識終了までに以下の時間がかかります．

- 発話開始-終了 → googleに接続 → 音声送信 → 認識処理 → 認識結果受信

これでは，発話終了から認識結果が得られるまでに，時間がかかり，音声対話などでは使い物になりません．

streamingの場合（入力された音声を逐次googleに送信するもの）は，以下のような時間経過を辿ります．

- 発話開始 ----------------------------- 発話終了 
- ｇｏｏｇｌｅに接続 → 逐次音声送信＆認識処理 → 認識結果受信

ですから，うまく行けば，発話終了とほぼ同時に，認識結果を得られるわけです．

これは絶対に使いたい！！！
ということで，以下にそのためのプログラムを載せておきます．

# stream認識の問題点
Google Cloud Speech APIで音声認識する場合には，音声の始まりの検出も自動で行ってくれるので，基本的には，googleに繋いで，音声を逐次送信していればよいです．音声区間が始まると，そこから認識結果が逐次送信され，音声が終了すると，認識処理もそこで終了し，接続が切れます（接続を切らずに連続認識するモードもある）

**しかし！！！！！！**

Google Cloud Speech APIのstreamモードには連続接続時間に制限があり，1分間しか連続して接続できません．

これは，音声認識を開始して，58秒たった後で5秒間の発話をすると，最後の3秒間分の音声は認識できないということになります．
また，連続音声認識モードにしても，1分で切れてしまうため，再接続を行っている間の時間分は，音声認識ができない事になってしまいます．

これは大問題なので，以下のように対処することにしました．
- 簡易的な音声開始検出を実装し，音声が開始するまではPC側で監視
- 音声開始を検出してから，googleに接続開始
- 接続中の音声もバッファしておき，googleに繋がったらバッファから順に送信

こうすることで，接続制限1分問題＋接続時の音声ロスト問題を解決してあります．

# 参考文献
・ 本家本元
https://cloud.google.com/speech/
・ サンプルプログラム
https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/speech/grpc
・ Google Speech APIを使えるようになるまで（API利用登録などの詳細）
http://qiita.com/lethe2211/items/7c9b1b82c7eda40dafa9
・Google Speech API をストリームで利用してみた（情報少なすぎ！）
http://qiita.com/voluntas/items/fb9fc621947272928df4

# 実行結果を先に見せちゃう
```
Ryota-no-MacBook-Pro:forGithub nishimura$ python GoogleSpeechAPI_stream.py 
Start Rec!
2016-09-23 15:08:55.784 Python[1667:116715] 15:08:55.784 WARNING:  140: This application, or a library it uses, is using the deprecated Carbon Component Manager for hosting Audio Units. Support for this will be removed in a future release. Also, this makes the host incompatible with version 3 audio units. Please transition to the API's in AudioComponent.h.
rms 652 decibel 56.2849525
connecting ....
success to connect.
conf:0.0 stab:0.00999999977648
trans:足
conf:0.0 stab:0.00999999977648
trans:明日
conf:0.0 stab:0.00999999977648
trans:明日の
conf:0.0 stab:0.00999999977648
trans:明日のよ
conf:0.0 stab:0.00999999977648
trans:明日の横
conf:0.0 stab:0.00999999977648
trans:明日の
conf:0.0 stab:0.00999999977648
trans:明日の横浜
conf:0.0 stab:0.00999999977648
trans:明日の横浜の
conf:0.0 stab:0.00999999977648
trans:明日の横浜のて
conf:0.0 stab:0.00999999977648
trans:明日の横浜の
conf:0.0 stab:0.00999999977648
trans:明日の横浜の天気
conf:0.0 stab:0.00999999977648
trans:明日の横浜の天気を
conf:0.0 stab:0.00999999977648
trans:明日の横浜の天気を押し
conf:0.0 stab:0.00999999977648
trans:明日の横浜の天気を教え
conf:0.0 stab:0.00999999977648
trans:明日の横浜の天気を教えて
conf:0.0 stab:0.00999999977648
trans:明日の横浜の天気を教えてく
conf:0.0 stab:0.00999999977648
trans:明日の横浜の天気を教えてくだ
conf:0.0 stab:0.00999999977648
trans:明日の横浜の天気を教えて
conf:0.0 stab:0.00999999977648
trans:明日の横浜の天気を教えてください
is_final: True
conf:1.0 stab:0.0
trans:明日の横浜の天気を教えてください
```

Start Rec!の直後に，WARNINGが出てますが，これはElCapitanでportaudioを使うと出るWARNINGなようです．portaudioのバージョンアップで解決されるのを待つしかないようです．そのままでも動くので，そのままにしてあります．

さて，音声認識の動作ですが，1フレーム（ここでは100ms）ごとにデータを送信していますが，そのデータ送信ごとに，googleから認識の途中結果が返ってきます．実際に動かすと，感動する挙動です．

# 環境
- MacBook Pro (Retina, 13-inch, Late 2013)
- OS X El Capitan バージョン 10.11.6

# 準備
Google Cloud APIを使うためには，GoogleにAPI利用の登録したり，クレジットカードを登録したり，API利用キーをダウンロードしたり，色々しないといけません．

API利用登録などの詳細は，以下のページを見ましょう．
[Google Speech APIを使えるようになるまで](http://qiita.com/lethe2211/items/7c9b1b82c7eda40dafa9)

基本的には，以下のREADME.md通りに進めればOKです．
https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/speech/grpc

## 必要なものは，pipでインストールしてみよう
``` 
pip install grpc-google-cloud-speech-v1beta1
```
その他，portaudioなどもインストールしてください．

## Mac OS X El Capitan モジュールインポートエラーが出たら
ライブラリのパスを見直してみて！
.bash_profile に，以下を追記したら治るかも．

```
export PYTHONPATH="/Library/Python/2.7/site-packages:$PYTHONPATH"
```

# プログラム

## プログラムの特徴
上にも書きましたが，以下の特徴があります．

- 簡易的な音声開始検出を実装し，音声が開始するまではPC側で監視
- 音声開始を検出してから，googleに接続開始
- 接続中の音声もバッファしておき，googleに繋がったらバッファから順に送信

## ソース
以下にあります．
https://github.com/sayonari/GoogleSpeechAPI_stream

## 設定解説
``` GoogleCloudSpeechAPI_stream.py
# 各種設定　#########################
flag_recogRepeat = True  # 音声認識を繰り返し行う場合　Trueにする
EXIT_WORD = u"(音声認識を終了します|ちちんぷいぷい|さようなら)"  # 音声認識を終了させる合言葉
LANG_CODE = 'ja-JP'  # a BCP-47 language tag

RATE = 16000  # サンプリングレート
CHANNELS = 1  # 録音チャンネル数

RECORD_SEC = 5  # 録音時間(sec)
DEV_INDEX = 0  # デバイスを指定

FRAME_SEC = 0.1  # 1フレームの時間（秒）　（0.1sec = 100ms）
CHUNK = int(RATE * FRAME_SEC)  # 1フレーム内のサンプルデータ数

SLEEP_SEC = FRAME_SEC / 4  # メインループ内でのスリープタイム（秒）
BUF_SIZE = CHUNK * 2  # 音声のバッファ・サイズ（byte）

DECIBEL_THRESHOLD = 50  # 録音開始のための閾値（dB)
START_FRAME_LEN = 4  # 録音開始のために，何フレーム連続で閾値を超えたらいいか
START_BUF_LEN = 5  # 録音データに加える，閾値を超える前のフレーム数
```

`RECORD_SEC = 5  # 録音時間(sec)`を消すのを忘れてました．これは効力がありません．

設定をいじるとすれば，最初の2つと，最後の3つです．

``` py
flag_recogRepeat = True  # 音声認識を繰り返し行う場合　Trueにする
EXIT_WORD = u"(音声認識を終了します|ちちんぷいぷい|さようなら)"  # 音声認識を終了させる合言葉

DECIBEL_THRESHOLD = 50  # 録音開始のための閾値（dB)
START_FRAME_LEN = 4  # 録音開始のために，何フレーム連続で閾値を超えたらいいか
START_BUF_LEN = 5  # 録音データに加える，閾値を超える前のフレーム数
```

googleに送信された音声は，wavファイルに吐き出されます．
ただ，連続して音声認識した場合には，その全てがつながって1つのwaveファイルとして
出力されます．

分けたい人は，ソースをいじってください．