LoginSignup
7
4

More than 5 years have passed since last update.

ask-sdkでClovaスキルを開発してみる

Posted at

ASKとCEK

自分はよく、AlexaとClovaのスキルを作るのだが概念がほとんど同じことに気づく。
たとえば、インテントだったり、スロットだったり。
どっちがどっちに似せたかはわからないが(言わない)ここまで似ているのに別々のSDKを使って、全く異なったコードを書くのはとても面倒である。

流石に同じエンドポイント(lambdaの同じ関数を使ったり)はよくない
しかし、同じSDKを使って、Alexaで使ったコードを丸っとコピーしてCEKに持っていけたらとても便利だ。

以前、この記事にてask-sdkとほぼ同じコードでかけるClova用のSDKを紹介したが、もういっそask-sdkをつかってClovaスキルを作ってみることにした。

流れ

  1. CEKからイベントを取得
  2. 取得したイベントをASK仕様に変換
  3. ask-sdkでごにょごにょ書く
  4. ask-sdkで作成されたレスポンスをCEK仕様に変換
  5. 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;
}

終わりに

こんな感じで試しに開発してみた動画です。

喋った。。。よかった。

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4