GoogleのAIY Voice kitを日本語化したりボタンを使えるようにしたり

だいぶ前にGoogleのAIY Voice kitを購入したのですが、最近ちまちまと遊んでみたのでその内容を記載してみようかなと思います。
2017年12月にGoogle Assistant SDKがバージョンアップされて日本語でやりとりできるようになったとの事なのでその対応を中心に、デバイスアクションを使ったLED制御までやってみようと思います。

備忘録的なところが大きいので読みづらい点はご了承ください。

# 準備
## 動作確認
初期セットアップはGoogleのAIYプロジェクトページにある手順で済んでいるものとします。
ということで、まずは"Start Dev Terminal"からKit自体が動作することを確認しておきます。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python $ cd src
(env) pi@raspberrypi:~/AIY-voice-kit-python/src $ ./assistant_library_demo.py
[2018-02-21 00:03:43,380] INFO:root:OAuth credentials initialized: /home/pi/.cache/voice-recognizer/assistant_credentials.json
Say "OK, Google" then speak, or press Ctrl+C to quit...
```

# Google Assistant SDK 関連の整備
## Google Assistant SDK のインストール・アップデート
ここから、Google Assistant SDK関連のアップデートを行っていきます。
以下の通りpythonのパッケージをアップデートしていきます。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python $ pip list
...
google-assistant-grpc (0.0.2)
google-assistant-library (0.0.3)
google-auth (1.0.1)
google-auth-oauthlib (0.1.0)
googleapis-common-protos (1.5.2)
...
(env) pi@raspberrypi:~/AIY-voice-kit-python $ pip install --upgrade google-assistant-library
Collecting google-assistant-library
...
(env) pi@raspberrypi:~/AIY-voice-kit-python $ pip install --upgrade google-assistant-sdk
...
(env) pi@raspberrypi:~/AIY-voice-kit-python $ pip install --upgrade google-assistant-grpc
...
(env) pi@raspberrypi:~/AIY-voice-kit-python $ pip list
...
google-assistant-grpc (0.1.0)
google-assistant-library (0.1.0)
google-assistant-sdk (0.4.2)
google-auth (1.4.1)
google-auth-oauthlib (0.2.0)
googleapis-common-protos (1.5.3)
...
```

これでGoogle Assistant SDKがインストール・アップデートされました。

## OAuth2.0クレデンシャルの初期化

続いてOAuthクレデンシャルの初期化を行います。
ここで指定しているassistant.jsonはAIY Projectのページの手順でダウンロードしたjsonファイルです。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python $ google-oauthlib-tool --scope https://www.googleapis.com/auth/assistant-sdk-prototype --save --headless --client-secrets /home/pi/assistant.json
```

URLが表示されますので、そこにアクセスします。指示通り進めるとauthorization codeが表示されますので、Terminalの方へコピーします。

## 認証用ファイルの配置

さて、続いての作業に入る前に、先ほども出てきた認証用のjsonファイルを再度ダウンロードします。AIY Projectの手順ではリネームすることになっていますが、ここではリネームせずに~/AIY-voice-kit-python配下に配置しておきます。
これにより、続くコマンド類が動くようになります。

## デバイスの登録

このあたりから、[Google Assistant SDKのGUIDES](https://developers.google.com/assistant/sdk/overview)を参考にしながら進めます。
まずデバイスの登録を行います。以下のコマンドの`<model-name>`には適当な文字列を入れますが、サンプルに則って`ProjectID-DeviceID`等にしておくのが良いかと思います。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python $ googlesamples-assistant-devicetool register-model --manufacturer "Assistant SDK developer" --product-name "Assistant SDK light" --type LIGHT --model <model-name>
Creating new device model
Model <model-name> successfully registered
```

確認には以下のコマンドを使用します。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python $ googlesamples-assistant-devicetool list --model
(env) pi@raspberrypi:~/AIY-voice-kit-python $ googlesamples-assistant-devicetool list --device
```

# Google Assistant の実行
## サンプルの実行

ここまで完了すれば、新しいGoogle Assistant SDKでサンプルが動くようになります。

まずはhotwordのサンプルを確認します。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python $ googlesamples-assistant-hotword --project_id <Project ID> --device_model_id <model-name>
```

うまく動いたでしょうか。

続いてpushtotalkのサンプルを実行するために、pipでいくつかモジュールをインストールします。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python $ pip install tenacity
(env) pi@raspberrypi:~/AIY-voice-kit-python $ pip install sounddevice
```

その後、以下のコマンドでpushtotalkが起動できます。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python $ googlesamples-assistant-pushtotalk --project-id <Project ID> --device-model-id <model-name>
```

hotwordとpushtotalkでオプションが微妙に違う("-"と"_")ので注意が必要です。

ここで気になるのが、まだこの時点では英語バージョンだという事と、pushtotalkのトリガーがキーボードなので、せっかくだからVoice kitの上についているボタンで反応させたくなります。

# 日本語対応の有効化

## pushtotalkの日本語化

まずpushtotalkの日本語対応は簡単でした。オプション`--lang ja_JP`を付けるだけです。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python $ googlesamples-assistant-pushtotalk --project-id <Project ID> --device-model-id <model-name> --lang ja_JP
```

音声入力と同時に日本語で認識された文字列が画面に表示されると思います。

## hotwordの日本語化

hotwordの方が難題でした。
結論から言うと、Androidの"アシスタント"アプリ(Googleアシスタントのアプリ)を使います。開発に使用しているGoogleアカウントでログインしているAndroid端末上にて、アシスタントアプリを起動します。アシスタントアプリの[設定]の中に、[デバイス]という項目があり、そこにデバイス登録したものがリストアップされます。
googlesamples-assistant-devicetoolで設定した名前でデバイスがみえているはずですので、そこをタップし、[アシスタントの言語]を[日本語]にします。
これで再度googlesamples-assistant-hotwordを起動すると日本語で対応してくれると思います。
問題は、Androidの6.0以降はアシスタント機能がOSに組み込まれているためアシスタントアプリ自体がインストールできないようなのです。つまり、Androidで設定する場合は5.0以前のものを持ってくる必要がありそうです。
また、iOSにもアシスタントアプリがあるようですのでiOSの端末がある場合はそちらを使用することになりそうです。

# Voice kitのボタンを有効にする
Voice kitにはLED内蔵のプッシュボタンがついているわけですが、現時点までのサンプルでは使用することができません。そこで、サンプルを改造してボタンを有効にしてみます。

## pushtotalkの改造

`/home/pi/AIY-voice-kit-python/env/lib/python3.4/site-packages/googlesamples/assistant/grpc`にサンプルがありますのでこれを使用することにします。
コピー先は以下の例と同じにしてください。srcディレクトリ配下にあるaiyパッケージを使用するためです。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python $ cd src
(env) pi@raspberrypi:~/AIY-voice-kit-python/src $ cp ../env/lib/python3.4/site-packages/googlesamples/assistant/grpc/*.py .
```

コピーされたファイルの中にpushtotalk.pyというファイルがあるので、以下のように編集します。

```
--- ../env/lib/python3.4/site-packages/googlesamples/assistant/grpc/pushtotalk.py       2018-02-21 00:15:06.996475934 +0900
+++ pushtotalk.py       2018-02-21 02:16:48.748299709 +0900
@@ -28,6 +28,8 @@ import google.auth.transport.grpc
 import google.auth.transport.requests
 import google.oauth2.credentials

+import aiy.voicehat
+
 from google.assistant.embedded.v1alpha2 import (
     embedded_assistant_pb2,
     embedded_assistant_pb2_grpc
@@ -418,9 +420,14 @@ def main(api_endpoint, credentials, proj
         # and playing back assistant response using the speaker.
         # When the once flag is set, don't wait for a trigger. Otherwise, wait.
         wait_for_user_trigger = not once
+        status_ui = aiy.voicehat.get_status_ui()
+        button = aiy.voicehat.get_button()
         while True:
             if wait_for_user_trigger:
-                click.pause(info='Press Enter to send a new request...')
+                #click.pause(info='Press Enter to send a new request...')
+                status_ui.status('ready')
+                button.wait_for_press()
+            status_ui.status('listening')
             continue_conversation = assistant.assist()
             # wait for user trigger if there is no follow-up turn in
             # the conversation.
```

編集が終わったらそのままカレントディレクトリで実行します。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python/src $ python pushtotalk.py --project-id <Project ID> --device-model-id <model-name> --lang ja_JP
```

これでボタンのLEDが反応し、ボタンも使えるようになると思います。


## hotwordの改造

hotwordはボタンは使用しませんが、ステータスをLEDで表せるようにしておきたいです。

pushtotalkと同様、サンプルをコピーしてきます。コピー元の場所が若干異なるので注意してください。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python/src $ cp ../env/lib/python3.4/site-packages/googlesamples/assistant/library/hotword.py .
```

コピーしたhotword.pyを以下の通り編集します。

```
--- ../env/lib/python3.4/site-packages/googlesamples/assistant/library/hotword.py       2018-02-21 00:15:07.006470918 +0900
+++ hotword.py  2018-02-21 02:35:29.113723823 +0900
@@ -24,6 +24,9 @@ import json
 import google.auth.transport.requests
 import google.oauth2.credentials

+import aiy.assistant.auth_helpers
+import aiy.voicehat
+
 from google.assistant.library import Assistant
 from google.assistant.library.event import EventType
 from google.assistant.library.file_helpers import existing_file
@@ -56,14 +59,26 @@ def process_event(event, device_id):
     Args:
         event(event.Event): The current event to process.
     """
+    status_ui = aiy.voicehat.get_status_ui()
     if event.type == EventType.ON_CONVERSATION_TURN_STARTED:
         print()

     print(event)

+    if event.type == EventType.ON_START_FINISHED:
+        status_ui.status('ready')
+
+    if event.type == EventType.ON_CONVERSATION_TURN_STARTED:
+        status_ui.status('listening')
+
+    if event.type == EventType.ON_END_OF_UTTERANCE:
+        status_ui.status('thinking')
+
     if (event.type == EventType.ON_CONVERSATION_TURN_FINISHED and
             event.args and not event.args['with_follow_on_turn']):
         print()
+        status_ui.status('ready')
+
     if event.type == EventType.ON_DEVICE_ACTION:
         for command, params in process_device_actions(event, device_id):
             print('Do command', command, 'with params', str(params))
```

編集が終わったらそのままカレントディレクトリで実行します。

```
(env) pi@raspberrypi:~/AIY-voice-kit-python/src $ python hotword.py --project_id <Project ID> --device_model_id <model-name>
```

これでボタンのLEDが反応するようになるため、見た目がわかりやすくなります。

---
次の記事はデバイスアクションを使用して外部につないだLEDを制御してみます。