kun432's blog

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

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

Voiceflow SDKでTwilio IVRチャットボットを作ってみた

f:id:kun432:20210313005910p:plain

前回のLINE BOTに続いて、今回はTwilioを使ったIVRチャットボットをVoiceflow SDKで作ってみました。

目次

コードとアーキテクチャ

サンプルコードはこちら。

構成は前回とほぼ同じ。Twilioで電話番号からStudio、そこからWebhookでローカルのnode.jsアプリにつないでます。

f:id:kun432:20210320182846p:plain

必要なもの

  1. node.js実行環境
  2. ngrok
  3. Twilio(Phone Numbers、Studio)の設定
  4. Voiceflowの設定
  5. Voiceflowのカスタムアシスタント向けサンプルプロジェクト
  6. VoiceflowプロジェクトのバージョンID
  7. VoiceflowのAPIキー

1、2、あと4〜6は前回と同じですので、説明は短めに。今回はTwilioの設定を中心に説明します。

アプリ実行

レポジトリをcloneして、npm installします。

$ git clone https://github.com/kun432/voiceflow-twilio.git && cd voiceflow-twilio
$ npm install

次に、Voiceflow SDKで必要なバージョンIDとAPIキーを設定します。そう、この管理画面が正式にリリースされました。

ワークフロー画面から、右上の"Settings"アイコン(歯車のやつ)をクリックして、"Workspace Settings"をクリックします。

f:id:kun432:20210320192415p:plain

"Workspace Settings"に"Developer"というメニューが追加されていますね。これをクリックするとAPIキーの発行画面が表示されますので、APIキーを作成します。

f:id:kun432:20210320192440p:plain

バージョンIDは前回と同じです。coffeeshop.vfファイルをインポートして、プロジェクトのURLからバージョンIDをコピーしてください。

f:id:kun432:20210313224335p:plain

インポート後に、”Test”をクリックして、学習させておくこともお忘れなく。また、一度テストも実行しておいてください。

f:id:kun432:20210318223749p:plain

f:id:kun432:20210318223829p:plain

バージョンIDとAPIキーを環境変数にセットしておきます。

# VoiceflowのサンプルプロジェクトのバージョンID
$ export VF_VERSION_ID="XXXXX...XXXXX"

# Voiceflowのサンプルプロジェクトが存在するワークスペースのAPIキー
$ export VF_API_KEY="VF.XXXXX...XXXXX"

アプリを起動します。

$ node .
listening on 3000

ngrokで公開します。

$ ngrok http 3000

前回同様、ngrokのURLを控えておいてください。

f:id:kun432:20210318230446p:plain

Twilioの設定

Twilioの設定は以下の流れになります。

  • 電話番号の購入
  • Twilio Studioでフローを作成
  • 電話番号のWebhookにTwilio Studioのフローを指定

電話番号の購入については以下をご覧ください。

注意としては、

  • 電話番号の購入には本人認証が必要になりました。免許証など個人を証明するものの画像をアップロードして認証しててもらう必要があります。認証は3営業日以内ということなので、事前にやっておくことをおすすめします。
  • 電話番号は国内のもので良いと思います。海外の番号だとSMSやMMSも使えたりするのですが、このサンプルではSMS/MMSは不要ですし、テストで電話する場合は国際電話になってしまうので。
  • ということで、電話料金が発生しますので予めご了承ください。
  • 上記の手順の中にあるTwiML Binの設定は、Twilio Studioでフローを作成したあとで変更しますので、不要です。初めての方は実際に電話で応答することを確認するためにやってみてもいいかもしれません。

電話番号が用意できたら、Twilio Studioのフローを作成します。Twilio Studioは、Voiceflowと同じく、GUIで応答フローを作ることができるというものです。かんたんな自動応答であればTwilio Studioだけで作れたりします。Amazon Connectとかと似た感じですね。今回はマルチターンの会話を繰り返すために使ってて、会話のロジックはVoiceflow側に持たせています。このあたりのやり方は以下を参考にさせてもらいました。

では、Twilio Studioの会話フローを作りましょう。予めTwilio Studioのフローをファイルで用意してありますので、これをインポートするだけでできるようにしてます。

左のメニューから"Studio"を開きます。

f:id:kun432:20210320195409p:plain

”Create a flow”で新規にフローを作成します。

f:id:kun432:20210320200102p:plain

フローの名前を適当につけて、"Next"をクリックします。

f:id:kun432:20210320200220p:plain

フローの新規作成は、空から作ることも、テンプレートから作ることもできます。今回はファイルからのインポートで作りますので、下の方にある"Import from JSON"を選択して、"Next"をクリックします。

f:id:kun432:20210320200411p:plain

JSONのインポート画面が開きました。ここに用意してあるフローのファイル、twilio-studio.jsonの内容をコピペで上書きして、"Next"をクリックします。

f:id:kun432:20210320200650p:plain

以下のようにフローが表示されればインポートは成功しています。

f:id:kun432:20210320200840p:plain

1箇所だけ変更をしましょう。上の方にある"defaults"というブロックの中で、ngrokのURLが表示されているのがわかるでしょうか?ここをngrokが生成したURLに書き換える必要があります。

f:id:kun432:20210320201110p:plain

"defaults"ブロックをクリックすると、右のメニューに設定が表示されます。"Config"タブの"Variables"タブでngrok_urlという変数が設定してあるので、"edit"をクリックして変更します。

f:id:kun432:20210320201332p:plain

URLを変更したら"Save"をクリックして、変数の設定変更を完了させます。

f:id:kun432:20210320201449p:plain

下にある"Save"もクリックして、ブロックの設定変更を完了させます。

f:id:kun432:20210320201750p:plain

ブロックのURLが正しく書き換わっていればOKです。

f:id:kun432:20210320201739p:plain

最後に一番上の”Publish”をクリックしてフローを公開します。

f:id:kun432:20210320213208p:plain

初回は以下のようなメッセージが表示され、"Publish"するだけではフローが使えず、電話から呼び出す必要があることを教えてくれます。このあとやりますので、一旦"Publish”をクリックします。

f:id:kun432:20210320213110p:plain

"Flow is up-to-date"と表示されればOKです。

f:id:kun432:20210320213434p:plain

では、電話をかけたらこのフローを呼び出すようにしましょう。

左のメニューから"Phone Numbers"を開きます。

f:id:kun432:20210320213625p:plain

購入した電話番号の設定画面を開きます。

f:id:kun432:20210320213740p:plain

下の方にある"Voice & Fax"のところに"A CALL COMES IN" というのがあるかと思います。これが購入した電話番号に電話がかかってきたときにどの処理を呼び出すか?という設定になります。

f:id:kun432:20210320213915p:plain

ここで先程作成したフローを実行するように設定すればOKです。まず、左のメニューでStudio Flowを選択します。

f:id:kun432:20210320214056p:plain

右のメニューで先ほど作成したTwilio Studioのフローを選択します。

f:id:kun432:20210320214154p:plain

最後に一番下の"Save"をクリックすれば完成です!

f:id:kun432:20210320214256p:plain

テスト

では実際に電話をかけてテストしてみましょう。

うまくいきましたね!

コード

ほぼVoiceflow SDKのexpressサンプルからほとんど変わってないです。

最初はLINEの場合と同じように、普通にWebhookでTwiMLの応答を返す形でやろうと思ったのですが、Twilioからのリクエストにはユーザを識別するためのIDのようなものが渡ってきません。発信者番号通知を使えばできるのかなぁ?と思いながらも、非通知な場合も多いことを考えると、それも現実的ではない。

Twilio Studioの場合、Webhookのレスポンスを変数として保持することができます。これを使って、

  • 初回はユーザID(というか正しくはセッションIDですね)がない状態でリクエストが飛んでくるので、アプリ側でユーザIDを発行し、Voiceflowのstateと紐付け。Voiceflowからのメッセージと一緒にユーザIDを含めて、Twilio Studioに返す。
  • Twilio Studio側で、レスポンスからメッセージとユーザIDを取り出して、メッセージを発話しつつ、次のWebhookリクエストでユーザIDも付与してリクエスト。
  • 2回目以降はこのユーザIDをもとにセッションを管理する

というやり方を行っています。詳しくはTwilio Studioのフローの設定も見ていただければと思います。Voiceflow SDKは会話の状態管理は行ってくれますが、そのためのキーとなるセッションIDのようなものはアプリ側で実装する必要があります。LINEの場合はリクエストにユーザIDが含まれていたため、やりやすかったのですが、プラットフォームの違いはこういうところにもあるのかーという感じです。

ただ、これによって、Twilioの応答フォーマットを気にしなくて良くなった(Twilio Studio側でやってくれる)ので、純粋な中継アプリになり、コードがとてもシンプルになりました。Twilio Studio、久々に触ってみましたが、マルチターンの会話の場合はWebhookやTwilio Functionsよりもやりやすい気がしました。

まとめ

Voiceflow SDKを使うと、比較的容易にマルチプラットフォームに対応できる、ということがわかっていただけましたでしょうか?

Voiceflow SDK公式のレポジトリには、

  • Facebook Messenger
  • Slack
  • Microsoft Teams
  • Discord

などとのインテグレーションのサンプルコードがありますので、こちらもぜひ見てみてください!

Voiceflow SDKでLINE BOTを動かしてみる

f:id:kun432:20210313005910p:plain

先日のVFV2まとめの中でもご紹介した「Voiceflow SDK」、もう少しすると公式に提供されるはずですが、ややフライング気味にLINE BOTを実装してみました。

目次

Voiceflow SDKとは?

元々、Voiceflowは、Amazon AlexaスキルおよびGoogleアクションをノンコーディングで作成し、それぞれのプラットフォーム(AlexaであればAmazon Echo、GoogleであればGoogle HomeやGoogleアシスタント)で公開するためのツールでしたが、昨年、これらのプラットフォームに依存しないカスタムなアシスタントを作成することができるようになりました。

ただし、このカスタムアシスタントは公開用のプラットフォームを持ちません。これを可能にするのがVoiceflow SDKです。

Voiceflow SDKを使うと、Voiceflowで作った対話モデルとチャットボットプラットフォームを中継するアプリケーションを開発することができ、ひとつの会話フローをさまざまなチャットボットプラットフォームに対応させることができます。

ということで、今回はLINE BOTと連携させてみました。

サンプルコードとアーキテクチャ

まずはサンプルコードで実際に動いているものを見てもらうのが早いでしょう。サンプルコードは以下のgithubレポジトリで公開しています。

今回はサンプルなので、LINE Messaging API SDK/Voiceflow SDKを使ったNode.jsアプリをローカルに立ててngrokで公開、それをLINE Messaging APIのwebhookに指定しています。

f:id:kun432:20210317021857p:plain

事前準備

サンプルアプリの実行には以下が必要です。

  1. node.js実行環境
  2. ngrok
  3. LINE BOTの設定
  4. Voiceflowのカスタムアシスタント向けサンプルプロジェクト
  5. VoiceflowプロジェクトのバージョンID
  6. VoiceflowのAPIキー

上記のうち、1〜3については説明を割愛します。ググって準備してください。

少し補足します。

  • Voiceflow SDK(Voiceflow Runtime Client)は、将来的には複数言語に対応するようですが、現時点ではJavaScript用だけのようですので、node.js実行環境が必要になります(LINE BOT用のSDKもnode.jsに対応しています)
  • LINE BOTの設定では、「チャネルシークレット」と「チャネルアクセストークン」を取得して、BOTと友達になっておいてください。なお、Webhook URLは後で設定しますので、一旦ダミーのものを登録しておけば良いと思います。

4〜6はVoiceflow SDKを使うために必要ですので、後で説明します。

サンプルアプリの実行

レポジトリのclone

上記のサンプルレポジトリをcloneしておいてください。

$ git clone https://github.com/kun432/voiceflow-line.git && cd voiceflow-line

Voiceflowのカスタムアシスタント向けサンプルプロジェクト

前提として、Voiceflow SDKは現在、カスタムアシスタント向け専用で、Alexa/Google向けには使えないようです。この点に注意してください。

今回用意したサンプルは、以下のAlexa向けVoiceflow日本語チュートリアルでも使っている「コーヒーショップ」スキルを元に、カスタムアシスタント向けに修正したものです。

f:id:kun432:20210318205126p:plain

このプロジェクトをエクスポートしたcoffeeshop.vfファイルがcloneしたレポジトリフォルダの中にありますので、これをVoiceflowにインポートしてください。インポートはプロジェクト一覧画面の右上のアイコンです。

f:id:kun432:20210318205848p:plain

.vfファイルを指定すると、現在開いているワークスペース上にプロジェクトがインポートされます。

インポートされたらプロジェクトを開いて、一度テストを開いてください。右上の"Test"をクリックします。

f:id:kun432:20210318223749p:plain

対話モデルを学習させます。"Train Assitant"をクリックします。

f:id:kun432:20210318223829p:plain

以下のように"Trained"が100%になっていればOKです。

f:id:kun432:20210318223931p:plain

終わったら左上の"Back"をクリックして、プロジェクトの編集画面に戻ります。

f:id:kun432:20210318224115p:plain

バージョンID

次にバージョンIDです。バージョンIDはプロジェクトのURLから取得できます。

現在プロジェクトの編集画面が開いていると思いますので、ブラウザのURL欄を見てください。

f:id:kun432:20210313224335p:plain

"https://creator.voiceflow.com/project/XXX...XXX/canvas/XXX...XXX"というようなURLになっていると思います。この"project/"と"/canvas"の間のランダムな文字列がバージョンIDになります。これをどこかに控えておきましょう。

APIキー

次にAPIキーです。APIキーは、近々専用の管理画面ができるようですが、現状はありませんので、少しひねったやり方になります。

プロジェクトの編集画面の左上の"<"をクリックして、インポートしたサンプルプロジェクトが存在するワークスペース画面に戻ります。

f:id:kun432:20210318224531p:plain

ワークスペース画面が表示されました。

f:id:kun432:20210313222108p:plain

このとき、ブラウザのURL欄を見てください。"https://creator.voiceflow.com/workspace/" のあとにランダムな文字列が並んでると思います。

f:id:kun432:20210313222414p:plain

URLの最後に"/api-keys" を追加してアクセスします。

f:id:kun432:20210313222620p:plain

APIキーの管理画面が表示されました。ここで"Create New API Key"をクリックします。

f:id:kun432:20210313222811p:plain

APIキーの名前を入力します。今回はテストなので適当に入れました。"Confirm"をクリックします。

f:id:kun432:20210313222910p:plain

"Successfully Created"と表示されればOKです。"VF." で始まる文字列がAPIキーになります。セキュリティの観点から、この画面を閉じるとAPIキーは二度と表示されません。"Copy to Clipboard"をクリックするとコピーされますので、安全なところに保管しておきしょう。

f:id:kun432:20210313223122p:plain

APIキー管理画面に戻ると、APIキーが表示されていますが、全部は表示されていませんね。もしコピーするのを忘れた場合は、このキーを削除して、新しいキーを生成してください。Backボタンで戻ります。

f:id:kun432:20210313223452p:plain

これで必要な情報が揃いました。

サンプルアプリの起動

ではサンプルアプリを起動します。

まず必要なパッケージをnpm installでインストールします。これでVoiceflowとLINE BotのSDK、およびnode.jsのwebサーバであるexpressがインストールされます。

$ npm install

次にこれまでに取得した各種情報を環境変数に設定していきます。"XXXXX...XXXXX"はそれぞれ用意したものに置き換えてください。

# LINE BOTのチャネルアクセストークン
$ export CHANNEL_ACCESS_TOKEN="XXXXX...XXXXX"

# LINE BOTのチャネルシークレット
$ export CHANNEL_SECRET="XXXXX...XXXXX"

# VoiceflowのサンプルプロジェクトのバージョンID
$ export VF_VERSION_ID="XXXXX...XXXXX"

# Voiceflowのサンプルプロジェクトが存在するワークスペースのAPIキー
$ export VF_API_KEY="VF.XXXXX...XXXXX"

ではアプリを起動します。

$ node .
listening on 3000

上記のように"listening on 3000"と表示されればOKです。3000番ポートでアプリが起動していることになります。

ngrokの起動

次に、ngrokを使って、さきほど起動したアプリをインターネット側からアクセスできるようにします。別のターミナルを立ち上げて以下を実行します。

$ ngrok http 3000

これにより、ngrokが3000番ポートで起動しているアプリにトンネルを用意して、インターネット側からアクセスできるURLを発行してくれます。以下の真ん中に表示されている"https"で始まる https://XXXXXXXXXX.ngrok.io というのがそのURLです。これをメモしておいてください。

f:id:kun432:20210318230446p:plain

LINE BOTのWebhookの設定

最後に、ngrokで発行されたURLをLINE BOTのWebhook URLとして設定します。LINE Developersコンソールの該当のBOTの「Messaging API設定」の中にある「Webhook URL」の「編集」をクリックします。

f:id:kun432:20210318231124p:plain

ここに、先程取得したngrokのURLを入力し、末尾に/callbackを追加します。設定したら「更新」をクリックします。

f:id:kun432:20210318231715p:plain

なお、ngrokは終了してしまうとそのURLは無効になり、再度起動すると違うURLが発行されます。したがって、このWebhook URLも変更する必要が出てきますので、ご注意ください。

テスト

ではLINEアプリを立ち上げて、「注文する」とか「開始」と入力してみてください。以下のように応答が返ってくれば成功です。

f:id:kun432:20210318232907p:plain

「コーヒー」「ジュース」「紅茶」で分岐するようにしていますので、色々入力してみてください。シノニムやサンプル発話も少しですがバリエーションを登録してありますので、言い方を変えてみてください。

画像を表示したり、

f:id:kun432:20210318233015p:plain

オーディオを再生することも可能です(ただし自動再生はされません)

f:id:kun432:20210318233201p:plain

プロジェクトを変更する

LINE BOTが動くようになったところで、少しプロジェクトを変更してみましょう。最初のSpeak Blockのメッセージを修正します。修正後に、Voiceflow上で一度テストして変更されていることを確認しておいてください。

f:id:kun432:20210318234105p:plain

再度BOTに注文してみましょう。

f:id:kun432:20210318234400p:plain

変更されているのがわかるでしょうか?つまり、VoiceflowのGUI上での変更が即座に反映されるということですね!

サンプルコード

少しだけサンプルコードについて。ちゃんと理解できてるか怪しいですが、説明してみます。

LINE公式のオウム返しBOTのサンプルコードをベースにしています。ユーザから送信されたメッセージの文字列をそのままレスポンスとして返すというものです。

これをVoiceflow SDKと組み合わせて、以下のようなやり取りになるように修正しています。

  • ユーザがLINEアプリで送ってきたメッセージを取得
  • このメッセージをVoiceflow SDK経由でVoiceflowプロジェクトに送信
  • Voiceflowプロジェクトが会話フローに従って応答したものを取得
  • Voiceflowプロジェクトからの応答をLINEの応答フォーマットに合わせて整形して、ユーザに返答

単にやりとりを中継しているだけのとてもシンプルなものです。

順に見ていきます。LINE BOT SDKの説明はちょっと割愛します。

Voiceflow SDKを呼び出します。

const { default: RuntimeClientFactory, TraceType } = require("@voiceflow/runtime-client-js");

環境変数からVoiceflowプロジェクトのバージョンIDおよびワークスペースのAPIキーを取得します。

const vfconfig = {
  versionID: process.env.VF_VERSION_ID,
  apiKey: process.env.VF_API_KEY,
};

Voiceflow SDKとは直接関係ありませんが、オンメモリなデータベースへのアクセスを用意して、ユーザのセッション状態(現在会話セッションが継続しているか?)を管理できるようにしてあります。

// mock database
const mockDatabase = {};
const db = {
    read: async (userID) => mockDatabase[userID],
    insert: async (userID, state) => mockDatabase[userID] = state,
    delete: async (userID) => delete mockDatabase[userID]
};

VoiceflowプロジェクトのバージョンIDおよびワークスペースのAPIキーを使って、Voiceflowクライアントを作成するためのfactoryインスタンスを作成します。

// create VF SDK client
const runtimeClientFactory = new RuntimeClientFactory(vfconfig);

ここからはLINEアプリ経由でユーザが送ってきたメッセージの処理です。

  • ユーザのメッセージ送信などで送信されていたイベントから、「ユーザID(event.source.userId)」「メッセージの文字列(event.message.text)」を取得します。ユーザIDはセッション状態を管理するためのキーになります。
  • セッションデータベースからユーザのセッション状態を確認します。通常初回はセッションがないはずなのでstateは空になりますが、セッション中の場合はVoiceflowから返されたセッション状態をここに保存し、リクエストのたびに呼び出すことでセッション状態を管理します。
  • VFのfactoryインスタンスのcreateClient()メソッドを使って、VFクライアントインスタンスを作成します。これが実際にVoiceflowとやり取りするためのインタフェースになります。createClient()メソッドにstateを渡すことでVoiceflow側とのセッション状態を維持します。
  • VFのクライアントインスタンスのsendText()メソッドで、LINEから送信されたメッセージをVFに送信します。Voiceflowからのレスポンスはcontextオブジェクトに入ります。
  const userId = event.source.userId;
  const userInput = event.message.text;

  const state = await db.read(userId);

  const vfclient = runtimeClientFactory.createClient(state); 
  const context = await vfclient.sendText(userInput)

Voiceflowからのレスポンスをチェックして、会話セッションが終了しているかを確認します。終了している場合はセッションデータベースからユーザセッションを削除します。会話が継続中の場合はレスポンス中に含まれるセッション状態をデータベースに保存し、以降のやり取りで使います。

  if (context.isEnding()) {
      db.delete(userId);
  } else {
      await db.insert(userId, context.toJSON().state);
  }

ちなみにVFからのレスポンスは以下のような配列に各オブジェクトが入っている形になっています。よく見るとVoiceflow上で実行される会話フローの各ブロックや処理などが順番に並んで返されるようです。したがって、この中から必要なものだけを抽出して応答に使うような感じになります。

[
  {
    "type": "debug",
    "payload": {
      "message": "matched intent **start_intent** - confidence interval _92.48%_"
    }
  },
  {
    "type": "block",
    "payload": {
      "blockID": "start00000000000000000000"
    }
  },
  {
    "type": "debug",
    "payload": {
      "message": "matched command **jump** - jumping to node"
    }
  },
  {
    "type": "block",
    "payload": {
      "blockID": "60439a9214ce235bc900f839"
    }
  },
  {
    "type": "speak",
    "payload": {
      "message": "カスタムコーヒーショップにようこそ。"
    }
  },
  {
    "type": "block",
    "payload": {
      "blockID": "605365085fd8e1ef16862953"
    }
  },
  {
    "type": "debug",
    "payload": {
      "message": "evaluating path 1: `({sessions} == 1)` to `false`"
    }
  },
  {
    "type": "debug",
    "payload": {
      "message": "no conditions matched - taking else path"
    }
  },
  {
    "type": "block",
    "payload": {
      "blockID": "605365485fd8e1ef1686296e"
    }
  },
  {
    "type": "speak",
    "payload": {
      "message": "またご来店いただきありがとうございます。"
    }
  },
  {
    "type": "block",
    "payload": {
      "blockID": "6051f1d16578cc1a9619c328"
    }
  },
  {
    "type": "speak",
    "payload": {
      "message": "ご注文は何にしますか?"
    }
  },
  {
    "type": "block",
    "payload": {
      "blockID": "604b9982bbafd948885abec5"
    }
  },
  {
    "type": "choice",
    "payload": {
      "choices": [
        {
          "name": "紅茶"
        },
        {
          "name": "ジュース"
        },
        {
          "name": "コーヒー"
        }
      ]
    }
  }
]

セッションが終了する場合のレスポンスは以下のようにtype: endが入っているものになります(わかりやすいように不要なものは除いてます)。isEnding()はこれが含まれているかをチェックしているわけです。

 {
    "type": "speak",
    "payload": {
      "message": "またのご来店をお待ちしております。"
    }
  },
  {
    "type": "end"
  },
]

先ほど説明したとおり、VFからのレスポンスはいろんなブロックの処理や応答が配列で渡ってきますので、これを順次取り出すことになります。ユーザに実際に返されるレスポンスで使うのは以下の3種類のオブジェクトになるかと思います。

  • TraceType.SPEAK
  • TraceType.VISUAL
  • TraceType.AUDIO

これ以外にもTraceType.DEBUGというデバッグ用のものや、TraceType.CHOICEというサジェスチョンチップのためのオブジェクトもありますが、一旦割愛します。

これらのオブジェクトのタイプに合わせてペイロードからデータを取り出し、LINEのレスポンスフォーマットにあわせて整形しているのが以下です。

  let replyMessages = [];
  for (const trace of context.getTrace()){
    if (trace.type === TraceType.SPEAK) {
      replyMessages.push({
        type: 'text',
        text: trace.payload.message
      });
    }
    if (trace.type === TraceType.VISUAL && trace.payload.visualType === 'image') {
      replyMessages.push({
        type: 'image',
        originalContentUrl: trace.payload.image,
        previewImageUrl: trace.payload.image
      });
    }
    if (trace.type === TraceType.AUDIO) {
      replyMessages.push({
        type: 'audio',
        originalContentUrl: trace.payload.src,
        duration: 12000 // need to know the duration of audio in advanced...
      });
    }
  }

上で少し紹介しましたが、3種類のオブジェクトの実際の応答を見てみましょう。まずはTraceType.SPEAK。

  {
    "type": "speak",
    "payload": {
      "message": "カスタムコーヒーショップにようこそ。"
    }
  },

TraceType.VISUALやTraceType.AUDIOの場合はそれらのURLが返ってくるわけですね。

  {
    "type": "visual",
    "payload": {
      "visualType": "image",
      "image": "https://s3.amazonaws.com/xxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxxx.jpg",
      "device": null,
      "dimensions": null,
      "canvasVisibility": "full"
    }
  {
    "type": "audio",
    "payload": {
      "message": "",
      "src": "https://s3.amazonaws.com/xxxxxxxxxxxxx/xxxxxxxxxxxxxxxxxx.mp3"
    }
  },

こういったものをよしなに整形した後、最後にまとめてLINE BOTの応答として返して終わりです。

  return client.replyMessage(event.replyToken, replyMessages);

まとめ

ということで、Voiceflow SDKを使って、LINE BOTを動かしてみました。ちょっと手探り感もあったのですが、いざやってみるととてもシンプルで少ない労力で書けますし、いろいろな可能性が広がると感じています。

  • いろんなプラットフォームにあわせて書き換えることでマルチに展開できる。
  • 会話のロジックやフローはVoiceflowのプロジェクトに集約されるので、これだけを管理すれば良い。
  • デザイナーは直接的かつ親しみやすいGUIで会話デザインに集中、プログラマーはインフラスタックの選択や運用、各プラットフォームごとの対応などに集中、デザインとプログラミングの分業ができる。

ぜひサンプル動かしてみていただいて体感していただければと思いますし、今後も楽しみです!

公式のレポジトリにはいろんなサンプルやドキュメントなどもありますので、そちらも見てみてください。

GitHub - voiceflow/runtime-client-js

2021年2月ふりかえり

f:id:kun432:20210307172230p:plain

もう1Qも最終月なのか、早い・・・ということで、2021年2月の振り返りです。

音声関連

  • 自作スキル・アクションの開発に力を入れる
  • Googleアシスタント向けアクションを作って公開する
  • スマホアプリを作って公開する

あー、ここは全く何もできていない・・・まあいろいろアウトプットはしたから許して(言い訳・・・)

仕事

  • AWSやK8S関連のアウトプットを増やしていく
  • 管理職としてもっとスキルを高めていく

先月からやっていたkube-prometheus周りと、あとTerraformを使ったTransit Gatewayを使ったアカウント跨ぎのVPC間通信、あとはDynamic Kubelet Configurationについてアウトプットできたので良しとします。EKSでDynamic Kubelet Configurationをやる場合、eksctlでちゃんとサポートができていないみたいで少しひねりが必要なのでどこかでまとめる予定。

管理職、これな、何もやってないw。

アウトプット

  • Voiceflowの日本語チュートリアルを充実させる
  • Voiceflowの動画チュートリアルを作る
  • AWSやK8Sのチュートリアルを作る
  • ブログを年間100記事以上書く
  • Advent Calendarに参加する
  • 技術同人誌を出す

ブログは上で書いた3件と合わせて合計13件。

インフラネタも書けたし、AlexaやVoiceflowについては引き続きコンスタントに書けてるので良かった。

VFV2イベントについては一旦まとめ(というか翻訳)なったので、細かいところは別でまとめる予定。Togetterで当日のツイートまとめてます。あとはre:capイベントやりたいけど人集まるかなぁ・・・

togetter.com

勉強会やイベントはこのあたりに参加させてもらいました。ありがとうございました。

Twilio Quest、結構頑張ったんだけど、最後にまくられて4位。なんとか3位に入ってHomePod miniがほしかったw。

事前に申し込んでおくと、TwilioQuest用のお供に、駄菓子詰め合わせもいただけました。

4位だったけど、楽しかったです!特製レゴとかももらえて嬉しい!

敗因はIoTのクエストやるにはSIMカードが必要で、ここでポイント稼げなかったことだなぁ。次回にむけてSIMカード&USB ドングル買いました!w

3G USBドングル AK-020 SORACOMスターターキット

3G USBドングル AK-020 SORACOMスターターキット

  • メディア: エレクトロニクス

あと、VFV2のほうは参加賞もらいました。

その他

  • ボカロPに俺はなる!
  • 住みやすい・仕事しやすいリモートワーク環境づくりをすすめる
  • 月に1冊本を読む

リモートワーク環境づくり、改め、リビング大幅改造計画になっていて、まだまだ進行中。落ち着いたらどっかでまとめたいなぁ。

読書はしてない・・・・

まとめ

いろいろあって、ちょっと鬱屈した感じが続いてる中、別人格がアウトプットしてる感じ。なんだかね。