この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
1 はじめに
外部のAPIをコールしているようなスキルでは、Alexaからのレスポンスが遅くなってしまうことがあります。青と緑のリングがグルグル回ってAlexaが頑張ってる(考えてる)感じのやつです。
少しの「待ち」であれば、これはこれで可愛いのですが・・・ちょっと長くなると、やはりUXは良くないかも知れません。
通常のスキルの実装は、下記のような順で処理されます。
① リクエストを受ける ② 内部処理(外部APIコールなど) ③ レスポンスを返す
このため、ユーザーの発話に対してAlexaが返事を始めるのは、③のレスポンスを受けてからですので、②が長くなると返事が遅くなるのは避けようがありません。
今回は、②の前に一旦Alexaから何らかの返事(発話や音楽など)を返しておき、②が終わった時点で、改めてレスポンスを返すという実装を試してみたいと思います。
① リクエストを受ける レスポンスを返す (Progressive Response) 「現在、検索中です。少しお待ちください ♪♪♫♪♬」 ② 内部処理(外部APIコールなど) ③ レスポンスを返す
2 プログレッシブレスポンス(Progressive Response)
Progressive Responseは、スキルの応答を待っている間にAlexaが再生するコンテンツであり、SSMLが使用可能なため、テキストや短いオーディオを利用することが可能です。スキルがリクエストを受け取り、現在、処理中であることを返すことができるため、ユーザーは「待ち」に入っていることが認識でき、安心感を得ることが出来ます。
Progressive Responseは、LaunchRequestまたは、IntentRequestから使用できます。
Progressive Responseは、リクエストに含まれるapiAccessToken及び、requestIdを使用してVoicePlayer.SpeakなどをPOSTすることで送ることできます。通常のレスポンスオブジェクトを受信する前に、これが到着した場合、デバイスで再生されます。
Directive Request
POST https://api.amazonalexa.com/v1/directives HTTP/1.1
Authorization: Bearer AxThk...
Content-Type: application/json
{
"header":{
"requestId":"amzn1.echo-api.request.xxxxxxx"
},
"directive":{
"type":"VoicePlayer.Speak",
"speech":"This text is spoken while your skill processes the full response."
}
}
なお、Progressive Responseを使用しても、レスポンスの制限時間(8秒以内)を超えることは出来ませんので注意して下さい。
3 SDKによる実装
Progressive Responseは、現在、Alexa SDK for Nodejsで記述が可能です。
最初に、比較のため時間のかかる処理を書いてみました。単純に7秒のウエイトを入れただけのコードです。
'SearchIntent': function () { // 通常の処理
let that = this;
let query = this.event.request.intent.slots.query.value;
setTimeout(function(){
that.emit(':ask', query + 'を検索しました。他にも何か検索しますか');
},7000);
},
続いて、上記の処理にProgressive Responseを追加したものです。通常の処理とProgressive Response用の処理をPromiseオブジェクトとして用意し、Promise.all()で実行しています。
Promise.all()では、複数の処理が全部終わってからthenに進むので、Progressive Response用の処理は、実処理側の所要時間を考慮して作成するべきでしょう。
今回は、発話と音楽でだいたい7秒程度の処理を用意しました。
'MusicSearchIntent': function () { // プログレッシブレスポンスを返す処理
let that = this;
let query = this.event.request.intent.slots.query.value;
const requestId = this.event.request.requestId;
const token = this.event.context.System.apiAccessToken;
const endpoint = this.event.context.System.apiEndpoint;
const ds = new Alexa.services.DirectiveService();
const audio = 'https://s3-ap-northeast-1.amazonaws.com/devio-blog-data/output.mp3';
const ssml = '<speak>検索を開始します<audio src="' + audio + '" /></speak>';
const directive = new Alexa.directives.VoicePlayerSpeakDirective(requestId, ssml);
const progressiveResponse = ds.enqueue(directive, endpoint, token)
.catch((err) => {
console.log(err);
});
const serviceCall = new Promise((resolve, reject) => {
setTimeout( () => {
resolve(query);
},7000);
})
Promise.all([progressiveResponse, serviceCall])
.then( query => {
that.emit(':ask', '音楽付きで検索しました。他にも何か検索しますか');
});
}
それでは、動作している様子です。一回目の呼出は、通常の処理で、二回目は、プログレッシブレスポンスの入った処理です。
4 最後に
今回は、プログレッシブレスポンスを使用して、応答待ち時間に音楽やメッセージを再生してみました。ユーザーの体験を向上させる手法としては、非常に有効な手法だと思います。うまく組み合わせて積極的に使用して行きたいと思います。