ASKとCEK
自分はよく、AlexaとClovaのスキルを作るのだが概念がほとんど同じことに気づく。
たとえば、インテントだったり、スロットだったり。
どっちがどっちに似せたかはわからないが(言わない)ここまで似ているのに別々のSDKを使って、全く異なったコードを書くのはとても面倒である。
流石に同じエンドポイント(lambdaの同じ関数を使ったり)はよくない
しかし、同じSDKを使って、Alexaで使ったコードを丸っとコピーしてCEKに持っていけたらとても便利だ。
以前、この記事にてask-sdk
とほぼ同じコードでかけるClova用のSDKを紹介したが、もういっそask-sdk
をつかってClovaスキルを作ってみることにした。
流れ
- CEKからイベントを取得
- 取得したイベントをASK仕様に変換
- ask-sdkでごにょごにょ書く
- ask-sdkで作成されたレスポンスをCEK仕様に変換
- CEKにレスポンスを返す。
(3)のask-sdkの中のコードは説明しません。ask-sdkを使ったことがある前提で説明します。
exports.handler
index.js
let skill;
exports.handler = async function (event, context) {
if (!skill) {
skill = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
SampleIntentHandler)
.create();
}
// CEKのイベントをASK仕様に変換
var ASKEvent = conversionToASKEvent(event);
// ask-sdkでのレスポンスのオブジェクト
const ASKResponse = await skill.invoke(ASKEvent);
// ask-sdkで作成されたオブジェクトをCEK仕様に変換
var CEKResponse = conversionToCEKResponse(ASKResponse);
return CEKResponse;
}
以下の部分でCEKからきたイベントJSONをASK風にします。(この関数は後述します。)
var ASKEvent = conversionToASKEvent(event);
よって、以下のようにskill.invoke
が使用できます。
const ASKResponse = await skill.invoke(ASKEvent);
このままではレスポンスがASK風になってしまうので、以下でCEK風のオブジェクトに変換します。
var CEKResponse = conversionToCEKResponse(ASKResponse);
conversionToASKEvent
CEKのイベントオブジェクトをASK風にしているだけです。
function conversionToASKEvent(CEKEvent){
var ASKEvent = {
version: CEKEvent.version,
session: {
new: CEKEvent.session.new,
attributes: CEKEvent.session.sessionAttributes,
user: {
userId: CEKEvent.session.user.userId
},
},
// requestはほぼ一緒なのでそのまま
request: CEKEvent.request,
}
return ASKEvent;
}
conversionToCEKResponse
レスポンスの仕様はちょろっと違います。
Clovaは現在ssmlが使用できないのですが、ask-sdkだとタグで囲まれてしまうので、いっそのことreplace(/<.*?>/g, "")
でを全て消去しちゃってます。
function conversionToCEKResponse(ASKResponse){
var reprompt = undefined;
if(ASKResponse.response.reprompt){
var repromptText = ASKResponse.response.reprompt.outputSpeech.ssml.replace(/<.*?>/g, "");
reprompt = {
outputSpeech: {
type: "SpeechList",
values: [
{
type: "PlainText",
lang: "ja",
value: repromptText,
}
]
}
}
}
var text = ASKResponse.response.outputSpeech.ssml.replace(/<.*?>/g, "")
var CEKResponse = {
version: "1.0",
sessionAttributes: ASKResponse.sessionAttributes,
response: {
outputSpeech: {
type: "SpeechList",
values: [
{
type: "PlainText",
lang: "ja",
value: text,
}
]
},
reprompt: reprompt,
shouldEndSession: ASKResponse.response.shouldEndSession,
}
}
return CEKResponse;
}
終わりに
こんな感じで試しに開発してみた動画です。
喋った。。。よかった。