AdventCalendar
GoogleHome
スマートスピーカー
adventcalendar2017

この記事はRetty Inc. Advent Calendar 2017 3日目です。
昨日は @tkngue さんのBigQuery の ベストプラクティス 〜 2017年度版 〜でした。

こんにちは!Rettyでエンジニアをしている諏訪です。

今スマートスピーカーとっても熱いですね!
2017年に入り、Google Homeをはじめとした日本語に対応したスマートスピーカーが数種類発売されました。
勢いに乗って私もGoogle Home Miniを買ってしまったので、今回はGoogle Homeと会話するアプリケーションを作ってみようと思います。

アプリを作る手段はいくつかあるみたいですが、私はActions SDKと自宅サーバーを使用しました。

プロジェクトを作る

Actions on Googleのコンソールへアクセスし、適当な名前でプロジェクトを作成します。

スクリーンショット 2017-11-17 19.59.51.png

今回はActions SDKを使用してアプリケーションを作っていくのでActions SDKのBUILDをクリックします。

スクリーンショット 2017-11-17 20.01.38.png

するとプロジェクトにアクションを追加するためのコマンドが出てくるので、メモっておきましょう。

スクリーンショット 2017-11-17 20.04.27.png

アプリを作る

Actions SDKを使用するためNodeとExpressを使ってエンドポイントを作っていきます。
会話部分は自作の会話AIを使用したかったのですが、5秒以内にレスポンスしないといけないという制限があるため、今回はリクルートのTalk APIを使用します。

私の環境は以下の通りです。

  • Node v8.7.0

npm initをして作っていきます。

index.js
var express = require("express"),
  log4js = require("log4js"),
  morgan = require('morgan'),
  bodyParser = require('body-parser'),
  ActionsSdkApp = require('actions-on-google').ActionsSdkApp;
  app = express(),
  talk = require('./talk.js');

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());

log4js.configure({
  "appenders": {"out": {"type": "stdout"}},
  "categories": {"default": {"appenders": [ "out" ], "level": "debug"}}
});
var logger = log4js.getLogger('out');
app.use(log4js.connectLogger(logger));

var server = app.listen(3000, function(){
  logger.info("Node.js is listening to PORT:" + server.address().port);
});

app.post('/', function(request, response, next){
  let sdk = new ActionsSdkApp({request, response});
  logger.info(JSON.stringify(request.body));

  function mainIntent (sdk) {
    logger.info('New Conversation: ', JSON.stringify({
      conversationId: sdk.getConversationId(),
      userId: sdk.body_.user.userId
    }));
    sdk.ask({speech: "こんにちは", displayText: "こんにちは"});
  }

  function rawInput (sdk) {
    let input = sdk.getRawInput();
    logger.info('Input: ', JSON.stringify({
      rawInput: input,
      userId: sdk.body_.user.userId
    }));
    if (input === 'バイバイ') {
      sdk.tell('ばいばい');
    } else {
      talk(input, function(text){
        sdk.ask({speech: text, displayText: text})
      });
    }
  }

  let actionMap = new Map();
  actionMap.set(sdk.StandardIntents.MAIN, mainIntent);
  actionMap.set(sdk.StandardIntents.TEXT, rawInput);

  sdk.handleRequest(actionMap);
});

mainIntentはアプリに接続した時に呼び出され、rawInputはユーザーから発話があった時に呼び出されます。
sdk.tell()ではレスポンス後アプリが終了しまうので、
sdk.ask()でユーザーの発話を待ち、会話のループに入ります。

この例ではバイバイを終了命令にしてますが、停止でも終了できます。

talk.js
var request = require('request');

module.exports = function(talk, callback){
  request({
    url: 'https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk',
    method: 'POST',
    form: { apikey: process.env.TALK_APIKEY, query: talk },
    json:  true
  }, (err, response, body) => {
    let text = err ? "エラーだよ" : body.results[0].reply;
    callback(text);
  });
}

アプリの作成が終わったら好きなところにデプロイしましょう。
私はDockerでコンテナ化して自宅サーバーにデプロイしました。

アクションの設定

アクションの設定にはgactions CLIが必要なので以下のコマンドでダウンロードしてきましょう。実行権限も必要なので付与します。

$ curl -O https://dl.google.com/gactions/updates/bin/darwin/amd64/gactions/gactions
$ chmod +x gactions

action.ja.jsonを作成してアクションの定義をします。複数の言語に対応するにはそれぞれのロケールに合わせたファイルを作成する必要があります。

action.ja.json
{
  "locale": "ja",
  "actions": [
    {
      "description": "Default Welcome Intent",
      "name": "MAIN",
      "fulfillment": {
        "conversationName": "conversation_1"
      },
      "intent": {
        "name": "actions.intent.MAIN"
      }
    }
  ],
  "conversations": {
    "conversation_1": {
      "name": "conversation_1",
      "url": "YOUR APP URL",
      "fulfillmentApiVersion": 2
    }
  }
}

作成し終わったらプロジェクトを作成した時にメモったコマンドを使用してアクションを設定できます。PACKAGE_NAMEは先ほど作成したaction.ja.jsonに変更します。初回は認証情報を取得する必要があるためコマンドラインの出力にしたがって取得します。

$ ./gactions update --action_package action.ja.json --project talkapp-hoge

Your app for the Assistant for project talkapp-hoge was successfully updated with your actions. Visit the Actions on Google console to finish registering your app and submit it for review at https://console.actions.google.com/project/talkapp-hoge/overviewみたいな出力が出れば成功です。出力されたURLにアクセスし、アプリの概要の設定をしていきます。

スクリーンショット 2017-11-17 20.41.31.png

2のApp informationから始めていきます。

スクリーンショット 2017-11-17 20.59.22.png

まず左上の言語をJapaneseに設定します。
Assistant app nameはgoogle homeからこのアプリを呼ぶために使用する名前なのでよく考えて設定しましょう。呼んだときにgoogle homeがどう認識するのか(ひらがな、カタカナ、漢字等)をしっかり確認しておかないと実機テストの時に呼んでも反応せずハマります(1時間無駄にしました)
マイアクティビティで自分の発話がどう認識されてるのか確認できるので設定前に確認しておいたほうがいいです。

DetailsセクションのAssistant app voiceで声を変更できるので使用したい声をあらかじめここで確認しておきます。

あとはよしなに設定します。

Account linkingの設定はなくてもいいようなので今回は設定しません。

スクリーンショット 2017-11-17 21.11.41.png

ここまでくればほとんど完成です。
TEST DRAFTからWEBシミュレーターに入れます。ブラウザで会話のテストができます。また、アプリを作成しているアカウントと同じアカウントに接続したGoogle Homeであれば実機でもテストできます。

スクリーンショット 2017-11-17 21.22.27.png

このままでも自分だけなら使用できますが、他の人にも公開したい場合SUBMIT DRAFT FOR REVIEWからGoogleのレビューをもらうことで他人にも公開できるようです。

まとめ

いかがでしたでしょうか?
今回はGoogle Homeで簡単に会話アプリをつくってみました。
Google Homeでは高性能な音声認識ができるため、ぜひ色々と試して見てください!