Alexaでリマインダー連携するときの注意点
はじめに
先日、Googleカレンダーの予定をAlexaのリマインダーに登録するアレクサスキル「リマインドカレンダー」を作りました。
リマインドカレンダー
Amazon.co.jp: リマインドカレンダー: Alexaスキル
リマインドカレンダーではAlexa Reminders APIを使ってリマインド登録ができます。 このAPIを使うときの注意点、審査での指摘事項が幾つかあったので書いてみたいと思います。
Alexa Reminders APIの完成形コード
まずは審査が通った完成形のコードを抜粋します。 一部わかりやすくするために直書きしています。
| const ScheduleIntentHandler = { | |
| ... | |
| async handle(handlerInput) { | |
| ... | |
| const speechText = '予定が2件あります。1番目は、10:00からヨガです。2番目は、12:00からランチです。何番をリマインドしますか?'; | |
| return handlerInput.responseBuilder | |
| .speak(speechText) | |
| .reprompt(speechText) | |
| .getResponse(); | |
| }, | |
| }; | |
| const RemindersIntentHandler = { | |
| ... | |
| async handle(handlerInput) { | |
| ... | |
| const number = Alexa.getSlotValue(handlerInput.requestEnvelope, 'Number'); | |
| const speechText = `${number}番、今日の10:00にヨガをリマインドしますか?`; | |
| return handlerInput.responseBuilder | |
| .speak(speechText) | |
| .reprompt(speechText) | |
| .getResponse(); | |
| }, | |
| }; | |
| const YesIntentHandler = { | |
| ... | |
| async handle(handlerInput) { | |
| ... | |
| const number = handlerInput.attributesManager.getSessionAttributes().number; | |
| try { | |
| const client = handlerInput.serviceClientFactory.getReminderManagementServiceClient(); | |
| const reminderRequest = { | |
| trigger: { | |
| type: 'SCHEDULED_ABSOLUTE', | |
| scheduledTime: '2019-09-07 10:00', | |
| timeZoneId: 'Asia/Tokyo', | |
| }, | |
| alertInfo: { | |
| spokenInfo: { | |
| content: [{ | |
| locale: 'ja-JP', | |
| text: 'ヨガ, | |
| }], | |
| }, | |
| }, | |
| pushNotification: { | |
| status: 'ENABLED', | |
| }, | |
| }; | |
| const reminderResponse = await client.createReminder(reminderRequest); | |
| } catch (error) { | |
| return handlerInput.responseBuilder | |
| .speak('リマインダーの登録ができませんでした。リマインドカレンダーでは予定をリマインドに登録するために、リマインダーの権限が必要です。Alexaアプリに送付したカードを使用してリマインダー権限を有効にしてください。') | |
| .withAskForPermissionsConsentCard(['alexa::alerts:reminders:skill:readwrite']) | |
| .getResponse(); | |
| } | |
| const speechText = `わかりました。${number}番、今日の10:00にヨガをリマインドします。`; | |
| return handlerInput.responseBuilder | |
| .speak(speechText) | |
| .getResponse(); | |
| }, | |
| }; |
簡単にコードの説明をします。
まずは、ScheduleIntentHandlerでGoogleカレンダーの予定を発話します。
予定には1番〜x番までの連番を付与して発話しています。
次に、RemindersIntentHandlerでリマインドしたい予定の番号をスロットで受け取ります。
受け取った番号と、リマインドに登録する時間・内容をユーザーに確認します。
最後にYesIntentHandlerで予定をリマインドに登録しています。
リマインドに登録する時は正確な内容をユーザーに伝える
はじめに作った時は次の様な発話フローにしていました。
Alexa:予定が2件あります。1番目は、10:00からヨガです。2番目は、12:00からランチです。何番をリマインドしますか?
ユーザー:1番をリマインドして。
Alexa:1番をリマインドに登録しますか?
ユーザー:はい
Alexa:わかりました。1番、今日の10:00にヨガをリマインドします。
この発話フローで審査に提出すると次のように指摘されました。
「1番をリマインドに登録しますか?」というセッションの際に、日付と時刻を確認できる応答内容に修正してください。
当初は、コードをシンプルにする為にダイアログモデルを利用して登録する番号の確認を行っていました。 しかし、ダイアログモデルでは確認の発話に含めることができるのはスロットです。 その為、この指摘を実装するにはダイアログモデルを諦めしかありませんでした。
最終的の発話フローは次の通りです。
Alexa:予定が2件あります。1番目は、10:00からヨガです。2番目は、12:00からランチです。何番をリマインドしますか?
ユーザー:1番をリマインドして。
Alexa:1番、今日の10:00にヨガをリマインドしますか?
ユーザー:はい
Alexa:わかりました。1番、今日の10:00にヨガをリマインドします。
リマインダーの使用ガイドラインにもリマインダーの発話例が掲載されているので確認しておきましょう。
リマインダーの許可が必要な理由を詳細に説明する
YesIntentHandlerの31行目〜57行目でAlexa Reminders APIを使ってリマインダーに登録しています。
しかし、リマインダーへのアクセス権限はユーザーによってOFFにすることができます。
もしも、アクセス権限がない場合には52行目〜57行目でcatchされます。
この時の発話をシンプルなエラーメッセージで返していました。
Alexa:1番、今日の10:00にヨガをリマインドしますか?
ユーザー:はい
Alexa:リマインダーの登録ができませんでした。
ここも審査で次の用に指摘されました。
権限が与えられていない時、なぜスキルがリマインダーの許可が必要かの理由を応答内に提示してください。
アクセス権限がない場合の発話も何故アクセス権限が必要なのかを説明する必要があります。 変更後の発話は次のとおりです。
Alexa:1番、今日の10:00にヨガをリマインドしますか?
ユーザー:はい
Alexa:リマインダーの登録ができませんでした。リマインドカレンダーでは予定をリマインドに登録するために、リマインダーの権限が必要です。Alexaアプリに送付したカードを使用してリマインダー権限を有効にしてください。
また権限がない場合には.withAskForPermissionsConsentCard(['alexa::alerts:reminders:skill:readwrite'])で権限付与のカードをAlexaアプリに表示する必要があります。
権限カードを送付するとAlexaアプリでは次のように表示されます。ユーザーはカードの「許可をアップデート」から簡単に権限の付与ができます。

まとめ
今回はどれもユーザーにわかりやすく伝えるための当然の指摘です。 Alexa審査チームは本当に細部までよく確認していますね。 Alexa Reminders APIを使う際には参考にしてください。
Let’s enjoy Alexa development.