Google Assistant アプリで他の端末に処理を移す


何かしらの写真であったり地図であったり、
スキルの内容によっては視覚的に情報を提示したくなると思います。
しかし、Google Home などの端末ではディスプレイがないため
これらの情報を提示できません。

この問題を解決できるように
Google Assistant では適切な端末で情報が提示できるように
処理の続きを他の端末に移すことが可能です。

やり方

NewSurface() というレスポンス用のクラスを使います
説明ページ: https://developers.google.com/actions/assistant/surface-capabilities#multi-surface_conversations

実装として最低限やることは主に2つです。

  1. NewSurface() を呼んで他の端末に移動するか尋ねる
  2. 専用のイベントをインテントで設定して、fulfillment で捌く

1. NewSurface() を呼んで他の端末に移動するか尋ねる

NewSurface クラスをレスポンスとして返すだけで
Actions on Google は以下のことをまとめてやってくれます。

  • 他の端末に移動するかをユーザーに尋ねる
  • 次のインテントに移るためのイベントの発火
  • 連携している端末へのプッシュ通知

実際のコードを見てみましょう

import { NewSurface } from 'actions-on-google'

app.intent('TestIntent', conv => {
  const context = '「こちらをスマートフォンに送ってもよろしいですか?」の前に喋ってほしい内容'
  const notification = '通知のタイトル'

  conv.ask(new NewSurface({
    capabilities: ['actions.capability.SCREEN_OUTPUT'],
    context,
    notification,
  }))
})

このように開発者側は、処理を移したい先の端末の条件と
テキストをいくつか用意するだけでOKです。

実行すると以下のような流れが実現できます。

2. 専用のイベントをインテントで設定して、fulfillment で捌く

「こちらをスマートフォンに送ってもよろしいですか?」の問いに対して「いいえ」と答えるか、
「はい」と答えて通知を開くと actions_intent_NEW_SURFACE というイベントが発火します。
このイベントをキャッチする必要があるので dialogflow でインテントの設定を行いましょう。

画像の中には入っていませんが、インテントの下部にある fulfillment の設定を Enable にするのを忘れずに。

ちゃんとインテントに入り fulfillment に処理が飛んでいれば以下のコードで会話を続けることができます。

app.intent('TestNewSurface', (conv, parameters, newSurface) => {
  if (newSurface.status !== 'OK') {
    // 最初と同じ端末で会話が続いてる
    conv.close('「いいえ」って言われた時の応答')

    return
  }

  // 通知がきた端末で会話が続いている
  conv.close('「はい」って言われた時の応答')
})

newSurface.status の中身を確認することで、ユーザーの応答がわかるので
よしなに処理の内容を変えてあげてください

「はい」の場合、端末は変わっていますが
会話は続いているので Context やらは引き継がれています。

捕捉

ここまでは説明のために、非常にシンプルにしてあります
ここからはよりよいアプリにするための補足です

ユーザーの画面の状況の把握

もしかしたら、ユーザーが画面付きの端末で聞いてるかもしれませんし、
画面付きの端末と連携していないかもしれません。
そこで下記のような分岐を追加しましょう。

...
app.intent('TestIntent', conv => {
  const hasScreen = conv.surface.capabilities.has('actions.capability.SCREEN_OUTPUT')
  const hasDeviceWithScreen =
    conv.available.surfaces.capabilities.has('actions.capability.SCREEN_OUTPUT')

  if (hasScreen) { // 画面付きの端末の場合はそのまま返事
    conv.close('画面のある素敵な端末ですね')

    return
  }

  if (!hasDeviceWithScreen) { // 画面付きの端末と連携できていない場合はどうしようもない
    conv.close('この機能は画面付きの端末で利用することができます')

    return
  }

  const context = '「こちらをスマートフォンに送ってもよろしいですか?」の前に喋ってほしい内容'
  ...

複数の状況で newSurface を使いたい時

インテントの設定でイベントを設定しましたが、
actions_intent_NEW_SURFACE というイベントが常に発火することになります。

ですので複数の状況で使いたい場合は、
conv.contexts.set などを用いてコンテキストに情報を持たせると良いと思います。

端末の連携について

端末が連携しているかは同じGoogle Accountでログインしているかだけではなく、
Voice Matchを有効にしているかなど他の条件も必要なようです。

情報を共有するかどうかのチェックなどいろいろあるみたいで
完全に把握しきれてません。
もし知っている人がいたらコメントなどで教えてくれると嬉しいです。

まとめ

ディスプレイ付きの端末がどんどん発売されて、アシスタントを使う端末も多様化してきます。
端末ごとに適した表示方法は異なるので良い体験を追求していきましょう