kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

Voiceflow Dialog Management APIことはじめ

f:id:kun432:20210313005910p:plain

ずいぶんとご無沙汰してしまいましたが、久々のVoiceflowエントリ。

以下で紹介したVoiceflow SDK,実はすでにObsoleteになっています・・・・

Voiceflow SDKに変わって、現在新しく提供されているのが『Voiceflow Dialog Management API』です。

どのように使うのか、実際にやってみましょう。

目次

カスタムアシスタントとDialog Management APIについて

まず最初に、カスタムアシスタントについて説明しておきましょう。比較としてわかりやすいので、最初にAlexaやGoogle向けのプロジェクトを作成した場合の構成をまとめてみました。

f:id:kun432:20211228222135p:plain

VoiceflowでAlexa/Google向けプロジェクトを作る場合、VoiceflowのGUIインタフェース上で会話フローを作成するので、このあたりの構成をあまり意識することはありませんが、実際には、

  • スマートスピーカーが受け取ったユーザの発話を、それぞれのプラットフォームが提供しているクラウドに渡す。
  • プラットフォームのクラウド上で音声認識を行い、インテントやスロットなどをバックエンドの会話ロジックに渡す。
  • バックエンドが受け取ったインテントやスロットをもとに会話の流れを判断して応答を返す。

というような流れになります。Voiceflow上では「プロジェクト」として作成していますが、実際には「対話モデル」と「会話ロジック」は別々に処理されて、それぞれが連携する形です。そしてユーザと直接触れ合うインタフェース部分は「スマートスピーカー」が担います。

これに対して、カスタムアシスタントの場合はこんな感じになります(多少正確ではないです)

f:id:kun432:20211228223111p:plain

カスタムアシスタントは独自のアシスタントです。AlexaやGoogleの場合にプラットフォームが提供するクラウド部分も、バックエンドとまとめてVoiceflowが提供しますが、ユーザとのインタフェース部分は用意されていません。この部分については開発者が自分で用意する必要があります。

これだけ聞くとカスタムアシスタントのほうが面倒に思えますが、逆にいうとAlexa/Google向けプロジェクトでは、それぞれが提供している枠組み以外の使い方ができません。つまりフロントエンドのユーザインタフェース部分もそれぞれのプラットフォームが提供するスマートスピーカーしか使えないわけですね(Googleの場合はスマホのGoogleアシスタントアプリも使えますが)。

カスタムアシスタントではこの制限がないため、フロントエンド部分は自由に選択ができます。例えばこのあたり。

  • Webサイト内の埋め込みチャットボット
  • スマホアプリのチャットボット
  • いろいろなチャットツール(Slack/LINE/MS Teams/Facebook Messenger/Discordなどなど)

これらを、バックエンドとして作成したVoiceflowプロジェクトとつなぐごとで、さまざまなインタフェースに対応した音声/チャットボットを作成することができるというわけですね。

そして、この開発者が作成するフロントエンドとVoiceflowのプロジェクトをつなぐのが『Voiceflow Dialog Management API』というわけです。

ちなみに以前ご紹介した「Voiceflow SDK」は、このAPIとの接続処理などをラップしたクライアント向けライブラリとして提供されていましたが、APIが独立して提供されるようになり、仕様もおそらく変わったため、Obsoleteされたということだと思います。なお、今のDialog Management APIにあわせた新しいSDKが近々出るみたいです)

Dialog Management APIの種類

Dialog Management APIには2つの種類があります。

  • State API
  • Stateless API

"State"というのは、会話の「状態」です。Voiceflowの会話フローの中で、誰の会話フローなのか?会話フローのどこにいるか?会話フロー中のどんな情報を保持しているのか?を管理します。

State APIは、この「状態」をVoiceflow側が持ちます。開発者側は一意となるキーを用意してAPIにリクエストを送るだけで、面倒な会話の状態管理をVoiceflow側に任せることができ、単にVoiceflowとつなぎこむ処理だけに集中することができます。

Stateless APIは、Voiceflow側では状態を持たずに、開発者側のアプリ側など自前で持つことになります。したがって、会話の流れを追うためには毎回すべての「状態」に関する情報をAPIに投げる必要があり、セッションや状態の管理も自前で行う必要がありますが、その反面、細かくセッション管理を行いたい場合や、センシティブな情報をクラウド側に渡さずにきちんと自分で管理したい場合などに向いている、というわけですね。

今回は簡単に使えるState APIの方を使ってみましょう。

サンプルプロジェクト

サンプルとなるプロジェクトを用意しました。以下の.vfファイルをダウンロードしてください(右クリックでダウンロード)。

https://raw.githubusercontent.com/kun432/voiceflow-samples/main/dialog-managment-api/dialog-management-api-sample.vf

Voiceflowのプロジェクト一覧画面の右上にあるインポートメニューからインポートします。

f:id:kun432:20220101023503j:plain

インポートされたらプロジェクトを開きます。(もし以下のメッセージが消えてしまって見えない場合は「Dialog Management APIサンプル」という名前のプロジェクトを開いてください。)

f:id:kun432:20220101023539j:plain

こんな感じのプロジェクトが開きます。

f:id:kun432:20220101024159p:plain

カスタムアシスタントプロジェクトでは、プロジェクトをインポートした場合や対話モデルを変更した場合、トレーニングが必要になります。右上の青いアイコンをクリックしてテスト画面に移ります。

f:id:kun432:20220101024000j:plain

右側に「トレーニングが必要」というようなメッセージが表示されるかと思いますので、"Train your assistant"をクリックします。

f:id:kun432:20220101024321j:plain

対話モデルのトレーニングが行われます。少し待ちます。

f:id:kun432:20220101025810p:plain

Trainedが100%になっていればトレーニングは完了です。下にある"Run test"をクリックしてテストしてみましょう。

f:id:kun432:20220101030157j:plain

f:id:kun432:20220101024647p:plain

ユーザの名前と年齢を聞くだけのとてもシンプルなものですね。名前と年齢は、恒久的な変数として保存するようにしてます。よって、2回目以降は何も聞かれずにこういうふうになる想定です。

f:id:kun432:20220101024820p:plain

ちなみに、Voiceflowのテストモードでは変数は恒久的に保存されませんが、変数の値を自分でいじることができます。これにより、擬似的に2回目以降を再現することができます。 f:id:kun432:20220101025610j:plain

これをDialog Management API経由で動かせるようにします。

APIキー・バージョンIDの取得

Dialog Manament APIにアクセスするには以下が必要になります。

  • APIキー
    • Dialog Management API経由でプロジェクトにアクセスするための認証キー。
    • 現状はプロジェクト単位ではなく、「すべて」のプロジェクトにアクセスできるようになってしまうため、取り扱い注意!
  • バージョンID
    • 個々のプロジェクトを区別するためのID。
    • こちらは漏れても多分大丈夫。

これらを取得していきましょう。

プロジェクト画面の左にある"Integration"をクリックします。

f:id:kun432:20220101030905j:plain

APIキーの発行画面が表示されます。

f:id:kun432:20220101031522p:plain

実行例が表示されていると思いますが、ここにバージョンIDがありますので控えておきます。

f:id:kun432:20220101031656j:plain

ちなみにプロジェクトのURLからも確認できます。

f:id:kun432:20220101034219j:plain

次にAPIキーです。こちらは実行例にも表示されていません(それだけ重要ということですね)。下の方に"Create API Key"というメニューがありますので、ここの"Create Key"をクリックします。

f:id:kun432:20220101034901j:plain

APIキーが表示されます。APIキーは一度表示されたあとは再度表示することはできません(削除して作り直すしかなくなります)。"Copy to Clipborad"をクリックすると、クリップボードに保存されるので、どこか安全な場所にペーストして保管しておきましょう

f:id:kun432:20220101035050j:plain

これでDialog Management APIを使うのに必要な情報が集まりました。

Node.jsでDialog Management APIにアクセスする

では実際にコードを書いてDialog Managemet APIにアクセスしてみましょう。Node.jsでやってみたいと思いますので実行環境を用意しておいてください。

公式のサンプルコードは以下のレポジトリのnodeJSディレクトリ以下にあります。

が、残念ながらこれ動きません!問い合わせてみたところ、現在APIの仕様変更を行っている途中らしく、サンプルコードはすでにそれに合わせたものになっていますが、仕様変更されたAPIがまだリリースされていないので、このサンプルコードでは動かないということみたいです。

ということで、仕様変更前のAPIに合わせたサンプルコードのレポジトリを用意しました。

ちなみに、仕様変更後のAPIでは、バージョンIDが不要になり、APIキーはプロジェクト単位になるだけらしいので、基本的なAPIリクエストやロジックは、公式のサンプルコードも私のサンプルコードも大きな違いはないです。

git cloneします。

$ git clone https://github.com/kun432/voiceflow-dialog-management-api-sample-ja
$ cd voiceflow-dialog-management-api-sample-ja/nodejs-cli

必要なライブラリをインストールします。

$ npm install

index.jsをエディタで開いて、以下のYOUR_API_KEY_HEREYOUR_VERSION_ID_HEREを先程取得したAPIキー・バージョンIDで書き換えてください。

const API_KEY = "YOUR_API_KEY_HERE";
const VERSION_ID = "YOUR_VERSION_ID_HERE";

では実行してみましょう。

$ npm start

ここからコマンドラインの対話がスタートします。

> voiceflow-api-nodejs-example@1.0.0 start
> node index.js

セッションを開始します。
> ユーザーIDを入力してください。: 

ユーザーIDと書いていますが、これが「状態」を管理するためのキーのことです。一般的にこのキーはユーザーごとに管理することが多いと思いますので、ユーザーIDという言い方にしています。適当な文字列を入力します。あとは質問に従って入力してください。

...
> ユーザーIDを入力してください。: 000001
...
あなたのお名前を言ってください。
> 入力: 太郎
...
太郎 さん、こんにちは。
あなたの年齢を言ってください。
> 入力: 20歳
...
太郎 さんの年齢は、20 歳です。
セッションを終了します。

一通り入力が終わるとセッションは終了です。Voiceflow上でのテストと同じように、NodeJSのコードからもプロジェクトの会話フローにアクセスできているのがわかりますね。

もう一度実行してみましょう。ユーザーIDに先ほどと同じ文字列を入力してみてください。

$ npm start

> voiceflow-api-nodejs-example@1.0.0 start
> node index.js

セッションを開始します。
> ユーザーIDを入力してください。: 000001
...
太郎 さん、こんにちは。
太郎 さんの年齢は、20 歳です。
セッションを終了します。

はい、入力を求められることなく実行が完了し、かつ、1回目に入力した情報がきちんと表示されています。つまりユーザーIDに会話の「状態」が永続的に紐付いているということになります。State APIを使うとこのように会話の状態をVoiceflow側で保存してくれます。

サンプルコードはこんな感じです。

cURLでDialog Management APIにアクセスする

では次にcURLを使って詳細にやってみましょう。

最初にAPIキー、バージョンID、ユーザーIDをセットしておきます。

$ API_KEY='VF.XXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
$ VERSION_ID='XXXXXXXXXXXXXXXXXXXX'
$ USER_ID='000002'

State APIで会話のやり取りを行うためのエンドポイントは以下になります。

https://general-runtime.voiceflow.com/state/$VERSION_ID/user/$USER_ID/interact

AuthorizationヘッダーにAPIキーをセットして、JSONでリクエストを投げればよいです。やってみましょう。

まずは会話フローの開始です。会話フローを開始するには以下のようなJSONを投げます。

{
    "request": { 
        "type": "launch"
    }
}

type: launchで会話フローの一番最初から実行されます。

$ curl -s -X POST "https://general-runtime.voiceflow.com/state/$VERSION_ID/user/$USER_ID/interact" -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"request": {"type": "launch"}}' | jq .
[
  {
    "type": "speak",
    "payload": {
      "message": "あなたのお名前を言ってください。",
      "type": "message"
    }
  }
]

最初のspeak blockの内容が返ってきていますね。

こちらからの応答を送信するには以下のようなJSONを投げます。

{
    "request": { 
        "type": "text",
        "payload": "送信する文字列"
    }
}
$ curl -s -X POST "https://general-runtime.voiceflow.com/state/$VERSION_ID/user/$USER_ID/interact" -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"request": {"type": "text", "payload": "花子"}}' | jq .
[
  {
    "type": "path",
    "payload": {
      "path": "choice:1"
    }
  },
  {
    "type": "speak",
    "payload": {
      "message": "花子 さん、こんにちは。",
      "type": "message"
    }
  },
  {
    "type": "speak",
    "payload": {
      "message": "あなたの年齢を言ってください。",
      "type": "message"
    }
  }
]

ちなみにAPIからのレスポンスは配列で返ってきます。複数のSpeak blockに分かれている場合などは順番に返ってきてますし、発話の応答以外にもChoice blockの分岐っぽい情報が含まれていたりします。

さらに返してみます。

$ curl -s -X POST "https://general-runtime.voiceflow.com/state/$VERSION_ID/user/$USER_ID/interact" -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"request": {"type": "text", "payload": "25歳"}}' | jq .
[
  {
    "type": "path",
    "payload": {
      "path": "choice:1"
    }
  },
  {
    "type": "speak",
    "payload": {
      "message": "花子 さんの年齢は、25 歳です。",
      "type": "message"
    }
  },
  {
    "type": "end"
  }
]

会話フローが終了すると、type: endが返ってきます。

同じユーザーIDを使って再度type: launchでリクエストを送ると、ちゃんと会話の状態が保存されていることがわかります。

$ curl -s -X POST "https://general-runtime.voiceflow.com/state/$VERSION_ID/user/$USER_ID/interact" -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"request": {"type": "launch"}}' | jq .
[
  {
    "type": "speak",
    "payload": {
      "message": "花子 さん、こんにちは。",
      "type": "message"
    }
  },
  {
    "type": "speak",
    "payload": {
      "message": "花子 さんの年齢は、25 歳です。",
      "type": "message"
    }
  },
  {
    "type": "end"
  }
]

まとめ

ということで、Dialog Management APIに触ってみました。SDKも便利でしたが、APIもシンプルに使えて便利ですね。

State APIには他にも、状態の取得や削除といったこともできますし、Stateless APIであれば、手元で状態の管理が行なえますので、ユースケースに合わせて選択すればよいかと思います。詳細はドキュメントをご覧ください。

www.voiceflow.com

次回はLINEやSlackなどと実際に連携してみたいと思います。