Edited at

Alexa Skills Kit (ASK) Software Development Kit (ask-sdk-core) v2使ってみた

More than 1 year has passed since last update.


概要


相違点の検証実施


開発環境


  • node: v8.10.0

  • npm: 5.6.0

  • ask-sdk-core: 2.0.1

  • ask-sdk-model: 1.0.1


主たる相違点


ハンドラーの定義方法



  • バージョン1


    • セッションの状態を起点にハンドラーを定義

    • ハンドラー内ではインテントごとに処理を定義


    バージョン1

    exports.handler = (event, context) => {
    
    alexa.registerHandlers(handlers);
    };

    let handlers = {
    'LaunchRequest': function () {
    this.response.speak('ようこそ');
    this.emit(':responseReady');
    },
    'SessionEndedRequest': function() {
    },
    ・・・
    }





  • バージョン2


    • インテントを起点にハンドラーを定義

    • ハンドラー内ではセッションの状態ごとに処理を定義


    バージョン2

    const LaunchRequestHandler = {
    
    canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
    },
    handle(handlerInput) {
    const speechText = 'ようこそ';

    return handlerInput.responseBuilder
    .speak(speechText)
    .reprompt(speechText)
    .getResponse();
    },
    };





エラーハンドリングを専用のハンドラーに集約



  • バージョン1


    • ハンドラーごとに定義(正常処理が含まれているハンドラー)

    • ハンドラー内ではUnhandledとして処理を定義


    バージョン1

    exports.handler = (event, context) => {
    
    alexa.registerHandlers(handlers);
    };

    let handlers = {
    'LaunchRequest': function () {
    this.response.speak('ようこそ');
    this.emit(':responseReady');
    },
    'Unhandled': function() {
    this.response.speak('もう一度おねがいします');
    this.emit(':responseReady');
    }
    }





  • バージョン2


    • エラー専用のハンドラーとして登録

    • ハンドラー内ではセッションの状態ごとに処理を定義


    バージョン2

    exports.handler = skillBuilder
    
    .addErrorHandlers(ErrorHandler)
    .lambda()

    const ErrorHandler = {
    canHandle() {
    return true;
    },
    handle(handlerInput, error) {
    return handlerInput.responseBuilder
    .speak('もう一度おねがいします')
    .getResponse();
    },
    };





リクエストとレスポンスにインタセプターを設定可能

インターセプターとはある処理の実行前後になにか別の処理を挿入(インターセプト)させるためのコンポーネントです。



  • バージョン1


    • リクエストインタセプター


      • 各インテントの先頭に挿入したい処理を定義



    • レスポンスインタセプター


      • 各インテントの末尾に挿入したい処理を定義

      • セッション終了インテントの処理であればSessionEndedRequestに実装してもよい




    バージョン1

    let handlers = {
    
    'LaunchRequest': function () {
    console.log('リクエストインタセプターの処理はここ');
    this.response.speak('ようこそ');
    this.emit(':responseReady');
    console.log('レスポンスインタセプターの処理はここ');
    },
    'Unhandled': function() {
    console.log('リクエストインタセプターの処理はここ');
    this.response.speak('もう一度おねがいします');
    this.emit(':responseReady');
    console.log('レスポンスインタセプターの処理はここ');
    }
    }




  • バージョン2


    • リクエストインタセプター


      • addRequestInterceptorsをCustomSkillBuilderに定義



    • レスポンスインタセプター


      • addResponseInterceptorsをCustomSkillBuilderに定義




    バージョン2

    exports.handler = skillBuilder
    
    .addRequestInterceptors(requestInterceptor)
    .addResponseInterceptors(responseInterceptor)
    .lambda()

    const requestInterceptor = {
    process(handlerInput) {
    console.log('リクエストインタセプターの処理はここ');
    },
    };

    const responseInterceptor = {
    process(handlerInput) {
    console.log('レスポンスインタセプターの処理はここ');
    },
    };





リクエストのJSONオブジェクトの取得

AlexaからLambdaに渡ってくるJSONオブジェクトの取得方法が変わってます。


  • バージョン1


バージョン1

let handlers = {

'LaunchRequest': function () {
const request = this.event.request;
・・・
}


  • バージョン2


バージョン2

const LaunchRequestHandler = {

canHandle(handlerInput) {
・・・
},
handle(handlerInput) {
const request = handlerInput.requestEnvelope;
・・・
}


セッション情報、永続情報の取得・保存


  • バージョン1


    • セッション情報


      • 取得


        • this.event.session.attributesオブジェクトから値を取得



      • 保存


        • this.sessionオブジェクトに値を代入





    • 永続情報


      • alexa.dynamoDBTableName = 'MySkillSampleTable'を定義。

      • 取得


        • this.attributes['キー名']から値を取得



      • 保存


        • this.attributes['キー名']に値を代入








  • バージョン2


    • AttributesManagerを用いる 


    セッション情報

    const attributesManager = handlerInput.attributesManager;
    
    // 取得
    const sessionAttributes = attributesManager.getSessionAttributes();
    // 保存
    sessionAttributes.保存したい名称 = '保存したい値';


    永続情報

    return new Promise((resolve, reject) => {
    
    handlerInput.attributesManager.getPersistentAttributes()
    .then((attributes) => {
    // 取得
    const value = attributes['キー名'];

    // 保存
    attributes['キー名'] = '保存したい値';
    handlerInput.attributesManager
    .setPersistentAttributes(attributes);
    return handlerInput.attributesManager.savePersistentAttributes();
    })
    .then(() => {
    resolve(handlerInput.responseBuilder.getResponse());
    })
    .catch((error) => {
    reject(error);
    });
    });





注意点

githubにあがっているサンプル上ではSkillIDによる制御が入っていないためいれておくとよいです。


バージョン1

exports.handler = (event, context) => {

alexa.appId = process.env.APP_ID; //スキルID
};


バージョン2

exports.handler = skillBuilder

.withSkillId(process.env.APP_ID) //スキルID

(2018/05/04追記)

スキルIDの検証がLambda側でできるようになっていました。

Lambda中のロジックで検証ではなく、フロントで検証できるので、こちらでスキルIDを設定する方が便利のようです。

Screen Shot 2018-05-04 at 12.14.34.png


まとめ


  • ハンドラーの扱いが変わったのが最も大きな違いですがVUI設計の原則である、インテントごとにやりたい処理・機能を分離するという原則にのっとった実装になっている気がします


    • そのかわりに状態管理が複雑化しているようにも見えます。



  • 4月中公開するスキルはこれで実装してみます。


    • 公開したら追記しますので是非つかってみてくださいw