Firebase
ラズパイ
linebot
GoogleHome
dialogflow

GoogleHomeとiftttとDialogflowとfirebaseとLINEBOTとラズパイを使って子供と音声によるLINE交換をしてみる(前編)

はじめに

AWS Summitで始めてみたalexaさんに心奪われAIスピーカに興味を持ち、気が付いたらGoogleHomeが家に置いてありました。

家族の無茶な命令で謝ってばかりのGoogleHomeの地位を向上させるべく、今回のプロジェクトを始めました。
まだスマホを持っていない子供との遠隔コミュニケーションが取れるようになれば、売れっ子間違いなしです。

※このプロジェクトを実現するにあたり、以下の記事が非常に参考になりました!ありがとうございました!
https://qiita.com/miso_develop/items/be562d8a823ad2639d94

絵が非常にわかりやすかったため、インスパイアされてパクって作ってみました。

実現イメージ

子供がGoogleHomeでLINEメッセージを送信

googlehome1.png

親がLINEメッセージをGoogleHomeへ送信

googlehome2.png

子供がGoogleHomeから未読のLINEメッセージを聞く

googlehome3.png

ポイントは子供が使うので、GoogleHomeとのやり取りはシンプルな言葉でできること。

  • LINEでただいま → "ただいま"メッセージをLINEへ送る
  • 新しいLINE → 未読のメッセージを読み上げて既読にする
  • さっきのLINE → 既読になってから数分前までのメッセージを読み上げる
    • 新しいLINEで聞き取れなかった時にもう一回読み上げてもらうイメージ

実現手段

本当なら自宅サーバーのラズパイとLINEBOTサービスだけで完結させたかったけど、一刻も早く地位を向上させる必要があるため、いろいろ情報を調べて以下のサービスを活用することでまずは実現させることを優先とします。

実現に必要なサービス

  • LINE Messaging API
  • IFTTT
  • Dialogflow
  • Cloud Functions
  • Firebase

LINE Messaging APIはなければ今回のLINEで云々プロジェクトが始まりません。
IFTTTはGoogleHomeとFirebase(webhook)との連携で必要となります。
その他は、自宅サーバーが外部公開できていればwebhookで発火できますが、めんどくさくてしていません・・・。ngrokを使うことも考えましたが、常にトンネリングするのと、ネットワークが切れたら再接続でURLが変わるため、試作段階で却下です。

準備

各サービスへ登録しよう

LINE Messaging API

LINE BOTはpushサービスを使うので、「Developer Trial」で登録します。
Channel基本設定で、以下のように設定します。

  • Webhook送信 → 利用する
  • Botのグループトーク参加 → 利用する
  • 自動応答メッセージ → 利用しない

WebhookのURLはFirebaseを登録してからなので後で設定。

Dialogflow

Googleアカウントでサクッと登録してみます。
自分のプロジェクトを作成するので、他のブログを参考にして作ってみてください。
とりあえず、LANGUAGEは「Japanese — ja」で。TIME ZONEも忘れずに。
では「Intents」を作っていきましょう。
その前に、「Integrations」でLINEにチェックを入れるのと、「Fulfillment」でInline EditorをENABLEDにしましょう。
Fulfillmentは最終的にはInline EditorではなくWebhookになりますが、最初をInline Editorにすることで自動的にCloud Functionsに関数が作られます。
その関数を使っていく過程で、Webhookに強制的に移行されます。

LINEの設定

以下の設定はLINE Messaging APIの管理画面から持ってきましょう。

  • Channel ID
  • Channel Secret
  • Channel Access Token

「Webhook URL」はURLをコピーして LINE Messaging APIの「Webhook URL」に設定してください。

Intentsの作成

ここでの役割は親のLINEメッセージをLINEBOTがそのまま横流しするのが役目となります。
要するに、メッセージに対して何もアクションを起こさず、全てFallbackとしてLINEのPayloadをFulfillmentにそのまま渡してあげるということです。
「CREATE INTENTS」の右にある3点をクリックして「Create Fallback Intents」を選択します。
intents_fallback.png

Actionに「input.linetext」を入力するのと、FulfillmentのUse Webhookをチェック入れるだけです。
intents_fallback_edit.png

Actionの「input.linetext」はこの文字列でなくても大丈夫です。Fulfillmentの実装時にルーティングで使用するので、そこと整合が取れればOKです。
では次はFulfillmentを実装していきます。

Fulfillmentの実装

ここまで、駆け足で書いてきましたが、どうも何か忘れているような気がする・・・。
・・・あ、Firebaseの登録ですね。うん。忘れました。
どこかの流れで、登録した気がするのですが・・・。
とりあえず、登録してある前提で話を進めます。

今回は、Inline Editorで作成されたCloud Founctionsを改修する形で実装します。
まずは、右側にあるダウンロードをクリックしてローカル環境に落としましょう。
inlineeditor.png

ローカルでの開発&デプロイは以下を参照してください。
https://firebase.google.com/docs/functions/get-started?hl=ja
https://firebase.google.com/docs/hosting/deploying?hl=ja

改修内容

index.jsの先頭付近に以下2行を追加します。

const firebase = require('firebase-admin');
firebase.initializeApp(functions.config().firebase);

こんな感じになるはずです。

'use strict';

const functions = require('firebase-functions'); // Cloud Functions for Firebase library
const DialogflowApp = require('actions-on-google').DialogflowApp; // Google Assistant helper library
const firebase = require('firebase-admin');
firebase.initializeApp(functions.config().firebase);

'input.unknow'と'default'の間に'input.linetext'を追加します。
はい。これだけです。

// The default fallback intent has been matched, try to recover (https://dialogflow.com/docs/intents#fallback_intents)
'input.unknown': () => {
  // Use the Actions on Google lib to respond to Google requests; for other requests use JSON
  if (requestSource === googleAssistantRequest) {
    sendGoogleResponse('I\'m having trouble, can you try that again?'); // Send simple response to user
  } else {
    sendResponse('I\'m having trouble, can you try that again?'); // Send simple response to user
  }
},
'input.linetext': () => {
  if (requestSource !== "line") {
    sendResponse('LINEからじゃないよ');
    return;
  }
  if( !(requestData.type === "message" && requestData.message.type === "text") ){
    sendResponse('テキストメッセージしか送れないよ');
    return;
  }

  let update = {
    '/linebot/receive':requestData
  };

  Promise.resolve().then( () =>{
    return firebase.database().ref().update(update);
  }).catch((err)=>{
    sendResponse("送信に失敗したよ:"+ err );
    return
  }).then(()=>{
    let msg = requestData.message.text + " を送ったよ";
    sendResponse(msg);
  });

},
// Default handler for unknown or undefined actions
'default': () => {

どこかで、$ firebase initみたいなことをしたりしましたが、何とかなるので乗り切ってください。
最後に、$ firebase deployをすれば終了です。

もう一度、Fulfillmentの画面に戻ると、Inline Editorではエラーとなるはずです。
Webhookに切り替えましょう。

FirebaseのDatabase

Firebaseは非常にシンプルですね。jsonの階層がそのままURLの階層で扱えます。
始めて使いましたが、このようなスキーマとなります。
基本的な使い方としては、googlehomeは通知用のみ。linebotはreceiveにlineのpayload、sendにbotに話させる言葉を格納します。

firebase.png

ラズパイにNodejsとサービスを入れましょう。

ラズパイとNodeのセッティング

これは、そこらじゅうに転がっているので、そちらを見てください。
ちなみに、自分はラズパイ3とケースをAmazonで買いました。

サービスのインストール

ソースをGitHubに上げたのでそちらを参照してください。
今回、QiitaもGitHubも初です。
https://github.com/nk-tamago/googlehome-linebot

これで、LINEに投稿した内容がサービス内のDBの蓄えられて、未読メッセージとして聞けるようになります。

次はIFTTTと連携して、未読メッセージを聞いてみましょう。
今日は遅くなったので、これまで。明日更新します。


2017年11月10日更新
GoogleHomeとiftttとDialogflowとfirebaseとLINEBOTとラズパイを使って子供と音声によるLINE交換をしてみる(後編)