こんにちは。
スキルの開発の手順にはもう慣れましたか?
前回は開発の流れと、基本的なカスタムスキルの作り方について学びました。ユーザーがスキルとどのように対話をするかを決める「対話モデル」の設計方法についても学びましたね。
前回行った対話モデルの設計では、Alexaスキルが備える機能を表す「インテント」と、インテントをどのような言葉で呼び出すかを決める「サンプル発話」を扱いました。今回はさらに「スロット」と呼ばれる機能を使って、既定の発話サンプルにない情報を受け取る方法について学んでいきましょう。
連載2回目は、以下のテーマについて学びます。
- スロットを加えた設計
- スロットタイプ(組み込みスロットタイプ)を割り当てる
- カスタムスロットタイプを定義する
- Alexaとの複数回に渡るやりとり(ダイアログ)
それではさっそく始めましょう。
スロットを加えた設計
スロットとは簡単に言うと、「プログラミング言語における関数の引数のようなもの」です。次の対話例を見てください。
ユーザー:アレクサ、明日の東京都の天気を教えて
Alexa:○月○日の東京都の天気は概ね晴れ……
Alexaに天気を尋ねる際に、日付や場所の情報を指定することができます。上記の例では「明日」や「東京都」の部分ですが、これを受け取る引数に相当するのがスロットの役割です。
皆さんが開発するカスタムスキルではどうでしょうか。前回作成したスキルの例を見てみましょう。
ユーザー:アレクサ、来場者カウントで来場者数を教えて
Alexa:今日の来場者数は156人です
この対話では何のイベントであるか、いつの情報が欲しいかということを伝えていません。これらを追加すると、例えば次のような対話になるでしょう。
ユーザー:アレクサ、来場者カウントでAIフェスタの昨日の来場者数を教えて
Alexa: AIフェスタの○月○日の来場者数は208人でした
AIフェスタという(架空の)イベントが複数の日程で行われていて、そのうち昨日の来場者数が何人だったかを尋ねています。この問い合わせのサンプル発話を表現すると、次のようになります。
{eventName}の{eventDate}の来場者数を教えて
プログラミング言語のように、引数に当たる部分を{ }で囲んだ文字列に置き換えました。{eventName}の部分にユーザーが発した任意のイベント名、{eventDate}の部分に日付の情報が入ることを表しています。インテントのサンプル発話を表現する際にはこの記法を使います。さらにサンプルを追加しましょう。
{eventName}の来場者数を教えて
{eventName}の{eventDate}の来場者数を教えて
{eventCity}で開催の{eventName}の来場者数を教えて
{eventCity}で開催の{eventName}の{eventDate}来場者数を教えて
2行目は先ほどの例と同じですが、様々な問い合わせパターンに対応できるようにしています。省略した情報については既定の値({eventDate}であれば今日の日付など)を用いることにし、イベント名{eventName}は必須としましょう。ここまでの例で、次の3つのスロットが必要なことがわかりました。
- eventCity
- eventName
- eventDate
次は、これらのスロットにスロットタイプを割り当てます。
スロットタイプ(組み込みスロットタイプ)を割り当てる
多くのプログラミング言語の変数に「型」があるように、Alexaのスロットにも型が存在します。それを「スロットタイプ」と呼びます。Alexa Skills Kitには予めいくつかのスロットタイプが用意されており(組み込みのスロットタイプ)、日付や数値など、ほとんどのスキルに共通して使われそうなものはここから選択できます。以下にスロットタイプの一例を示します。
スロットタイプの例
スロットタイプ | 説明 |
AMAZON.DATE | 日付を表します。「今日」「明日」のように言葉で表現された場合には、内部で自動的に「2018-04-03」のような日付形式に変換されます |
AMAZON.TIME | 時刻を表します。「午後三時」などの言葉で表現された場合には、内部で自動的に「15:00」のような時刻形式に変換されます |
AMAZON.NUMBER | 数値を表します。 |
AMAZON.City | 都市の名前を表します。「東京都中央区」「京都市」などの都市の名前を表します。開発者が拡張することもできます。 |
より詳しい説明は、スロットタイプリファレンスのページをご覧ください。
スロットタイプリファレンス
組み込みのスロットタイプは、上記のように「AMAZON.」で始まる文字列で識別できるようになっています。
では、Alexa Skills Kit開発者コンソール(以降、開発者コンソール)でスロットの設定をしてみましょう。
前回作成した「来場者カウント」スキルの「VisitorCountIntent」編集画面を開きます。「インテントスロット」セクションにある「新しいスロットを作成」と書かれた入力欄に「eventCity」と入力して、その横の「+」をクリックします。
インテントスロット
すると「スロットタイプを選択」と書かれた選択欄が有効になるので、「AMAZON.City」を選択します。色は自動的に割り当てられるようで、下記の画面とは異なるかもしれませんが、問題ありません。
スロットタイプの選択
同じようにして「eventDate」スロットを作成し、「AMAZON.DATE」を割り当てます。
スロットタイプの割り当て
さて、都市の名前でも日付でも数値でもない、{eventName}の場合はどのようにすればよいのでしょうか。イベント名としては任意の名称を受け付ける必要があります。このような場合には、組み込みのスロットタイプを使うのではなく、専用のスロットタイプタイプを新たに定義することができます。それが「カスタムスロットタイプ」です。
カスタムスロットタイプを定義する
それでは、イベント名を扱うためのカスタムスロットタイプを開発者コンソールで定義してみましょう。
まず左メニューから「スロット値(2)」と書かれた項目をクリックしてみてください。( )内の数値には現在使われているスロットタイプの数が入ります。「スロットのタイプ」ページが表示されたら「+スロットタイプ」をクリックして、新しいスロットタイプを作成します。
新しいスロットタイプの作成
「スロットタイプ」欄に、これから作成するスロットタイプの名称を入力します。使用できるのは、アルファベットとアンダースコア(_)のみです。組み込みのスロットタイプで使われているピリオド(.)はここでは使用できません。今回は「EVENT_NAME」と入力して「カスタムスロットタイプを作成」をクリックします。
カスタムスロットタイプの作成
「スロットのタイプ」ページが表示されたら、このスロットが取り得る値、つまりここでは想定されるイベント名を入力していきます。「このスロットタイプの新しい値を入力」欄に文字列を入力し、[Enter]を押すことで値を登録できます。ここでは次の3つを登録しています。英数文字列と日本語文字列の間には、スペースを入れておきましょう。
- AI フェスタ
- ASK ユーザー会
- ジャパンアレクサデイズ
スロットタイプの追加
スロットタイプができたので、左メニューからVisitorCountIntentの編集ページに戻り、「eventName」スロットを追加します。スロットタイプには今作成した「EVENT_NAME」を選びます。
スロットタイプの選択
スロットの準備が整ったたら、サンプル発話を追加しておきましょう。
元々あったサンプル発話に加え、設計の項で挙げた4つのサンプルを新たに登録しています。スロットの部分は自動的に色分け表示されます。下記の画面の例と色が異なっていても問題ありません。完了したら、「モデルを保存」「モデルをビルド」の両方を実行しておきます。
インテントの保存とビルド
ここまでの設定ができたら、スロットのデータを扱えるようにスキル・サービスにも変更を加えます。前回作成したAWS Lambdaの関数の中身を、以下のコード例1のように書き換えてください。APP_IDはスキルのエンドポイントのページで取得したスキルIDです。
リスト1:コード例1:code2-1/index.js
02 | const Alexa = require('alexa-sdk'); |
04 | //============================================================================= |
05 | //TODO: The items below this comment need your attention. |
06 | //============================================================================= |
08 | //Replace with your app ID (OPTIONAL). You can find this value at the top of |
10 | //Make sure to enclose your value in quotes, like this: const APP_ID = 'amzn1 |
11 | .ask.skill.bb4045e6-b3e8-4133-b650-72923c5980f1'; |
12 | const APP_ID = 'amzn1.ask.skill.b6030ab0-d878-4bd3-bff0-790750d638d2'; |
14 | const SKILL_NAME = '来場者カウント'; |
15 | const HELP_MESSAGE = '来場者数を教えて、で今日の来場者数をお知らせします'; |
16 | const HELP_REPROMPT = '何をお調べしますか'; |
17 | const STOP_MESSAGE = '終了します'; |
19 | const visitorCount = 156; |
21 | //============================================================================= |
22 | //Editing anything below this line might break your skill. |
23 | //============================================================================= |
26 | 'LaunchRequest': function () { |
27 | // このスキルを「開いて」とリクエストした場合に呼び出される |
30 | this.emit(':responseReady'); |
32 | 'VisitorCountIntent': function () { |
33 | // VisitorCountIntent に対応して呼び出される |
36 | let intent = this.event.request.intent; |
39 | var eventCity = intent.slots.eventCity.value; |
40 | var eventName = intent.slots.eventName.value; |
41 | var eventDate = intent.slots.eventDate.value; |
47 | eventDate + 'の来場者数は' + |
49 | // Alexa アプリで参照できる情報 (カード) を返す |
50 | this.response.cardRenderer(SKILL_NAME, speechOutput); |
52 | this.response.speak(speechOutput); |
54 | this.emit(':responseReady'); |
56 | 'AMAZON.HelpIntent': function () { |
57 | const speechOutput = HELP_MESSAGE; |
58 | const reprompt = HELP_REPROMPT; |
60 | this.response.speak(speechOutput).listen(reprompt); |
61 | this.emit(':responseReady'); |
63 | 'AMAZON.CancelIntent': function () { |
64 | this.response.speak(STOP_MESSAGE); |
65 | this.emit(':responseReady'); |
67 | 'AMAZON.StopIntent': function () { |
68 | this.response.speak(STOP_MESSAGE); |
69 | this.emit(':responseReady'); |
73 | exports.handler = function (event, context, callback) { |
74 | const alexa = Alexa.handler(event, context, callback); |
75 | alexa.APP_ID = APP_ID; |
76 | alexa.registerHandlers(handlers); |
VisitorContentIntentのハンドラーで、インテントのObjectからスロットの値を取得しています。
リスト2:インテントObjectからスロット値を取得
2 | let intent = this.event.request.intent; |
5 | var eventCity = intent.slots.eventCity.value; |
6 | var eventName = intent.slots.eventName.value; |
7 | var eventDate = intent.slots.eventDate.value; |
eventCity、eventName、eventDateの3つのスロット値を取得し、それをそのまま返答内容に含めています。まずはこの状態でテストしてみましょう。
スキルのテスト
期待した結果になりましたでしょうか。サンプル発話が長く、一息で間違えずに言うのはなかなか難しいかもしれません。
次に、日付を省略すると今日の情報を返すというように、より簡単な言葉でもリクエストできるようにしたいと思います。Alexa Skills Kitに用意されている「ダイアログ」という機能を使うと、これらを簡単に実現できます。