Tweet

2018年12月12日水曜日

【Alexaスキル開発】AlexaSDK V2 (Ver2/ask-sdk)にアップデートしよう!絶対挫折しない導入解説!移行のコツなども解説。【サンプルコード配布あり】

はてなブログ版記事を是非御覧ください!

大幅に見やすく同じ内容が掲載しております!
https://iga34engineer.hatenablog.jp/entry/2018/12/12/171404

こういう人向け

  • AlexaSDK ?って何って人
  • Alexa SDK V1を使用していて、
    そろそろV2と言われるものに移行しないと…と考えている人
  • Alexa SDK V2を導入しようとしてターミナルで挫折した
  • Alexa SDK V2で、SDK V1コードを書き直してみたい人
  • Alexa SDK V2で動くサンプルコードが見たい

おことわり


世の中の多くのAlexa SDK V2導入記事では、
ターミナルの使用や使いこなすのを前提として導入紹介する記事が多いですが、
ターミナルを使わずファイル配布する事で導入のハードルを大幅に下げてます。

ターミナルの使用に抵抗がある方でもご安心下さい。

自分の開発環境がAlexa SDK V1/V2か、確認する方法


//Alexa SDK V1 -> const Alexa = require('alexa-sdk');
//Alexa SDK V2 -> const Alexa = require('ask-sdk');

皆様のソースコードのはじめの一文を見れば判別可能です。
上記を参考に見分けてみて下さい。

Alexa SDK V2に移行するメリット

  • V1と比較して確実に長い間スポンサードされる。
  • 機能追加されている。
特に大きな理由が無ければ最新開発環境でチャレンジするべきではないかと、思います。
機能追加について具体的な内容を紹介します。
  • NPMパッケージとして提供される。
  • コア機能のみのパッケージも利用可能(v2)
  • 各種のリクエストをハンドラとして定義できる。
  • ハンドラは柔軟にグループ化や共通処理が可能(V2)
  • セッションごとやセッションを跨ぐデータの永続化が可能(V2)
  • DynamoDB等のDBが使用可能(V2)
  • すべての音声出力はSSMLでラップされる
  • 全てのLambdaイベントとコンテキストにアクセスが可能。
  • デバイスアドレスなどのAlexaサービスをラップし、簡単に利用可能(V2)
  • TypeScript定義ファイルと.d.tsファイルの読み取りが可能(V2)
  • anync/awaitが利用可能(V2)
V1でわざわざ拡張する必要があった機能などが既に拡張されて対応されている、
+αで出来る事が増えているという程度の認識でOKです。
後程勉強して分かるようになったら上記読めば理解が深まるのではないでしょうか。

Alexa SDK V2 導入について


基本的にはAlexa SDK V1時代にご紹介した方法と同じにしてます。
  1. URLを共有するのでzipファイルをChromeブラウザでダウンロード。
  2. 「zipファイルをアップロード」
  3. いつも通りインラインコード編集でコーディング
下記手順で問題ないと思いますが、
より丁寧に説明しているSDK V1時代と同じ手順になりますので、
過去記事をご活用ください。


Alexa SDK V2 zipファイル 配布について


こちらにzipファイルを置いております。

Chromeブラウザでダウンロードしてください。解凍は不要です。

Amazon lambda関数にzipファイルをアップロードする



lambda関数でいつものように新規作成して、
「コードエントリタイプ」から「.zipファイルをアップロード」で、
先程ダウンロードしたzipファイルをそのまま上げて、
ページ最上部の「保存」を押してください。

Alexa SDK V2、フォルダの整形(お手間かけてすみません)


File not found '/index.js'
こちらのメッセージが出てくると思いますが、スルーでOKです。
正しい位置に「/index.js」が存在していないのでシステムが見つけられませんでしたというメッセージですから。

アップロードしたばかりのフォルダ階層をチェックしてみましょう。


▶test_01(関数名と同一)
 ▶フォルダ「_MACOSX」
 ▶フォルダ「AWS lambda アップロード」
   ▶フォルダ「node_modules」
   ▶ index.js
   ▶package.json

上記のようなフォルダ構造になっております。

上記の中で必要なのは色の付いたファイルだけになりますので、
フォルダ「test_01」の直下に置いてあげましょう。

一番上をファイルを押して一番下のファイルをshiftキー押せば複数選択が出来ます。
青くした状態で「test_01」へドラック&ドロップしてください。
ここらへんはパソコンのフォルダ整理と一緒だから大丈夫だよね・・・?

フォルダ整理後


上記3ファイルが階層が上がり、左側に移動したのが分かりますか。
これでOKです。
不要な「_MACOSX」「AWS lambdaアップロード」フォルダは右クリックで削除しましょう。
deleteという選択肢でOKです。

これで保存すればインラインコード編集が可能となります。

Alexa SDK V2 コーディングについて


SDK V1と変わらず、index.jsを編集すればOKです。
試しにサンプルコード置いてみました。

こちらに「index.js」と「JSONエディター」あげてます。

Alexa SDK V2 で大きく変わった点、意識する所について

  • モジュール採用は SDK V2用にしてある必要がある
    • const Alexa = require ('ask-sdk');
  • ErrorHandler(エラーハンドラ)が優秀に。
    • 特定インテント内で処理がおかしくなった時でも、
      エラーハンドラに飛ばされるように。
    • V1時代の「スキルが応答しませんでした」が激減しました。
  • intentへのアクセスの仕方が変わったので注意。
  • 各インテントを実行する条件(canHandler)が設定された。
  • 各インテントを新規追加する時は注意。
  • tell、ask完全廃止。Responseオブジェクトで記載する。

ErrorHandler(エラーハンドラ)が優秀に。


■Alexa SDK V1時代の「予期せぬ発話」
    //予期せぬ発話
    'Unhandled': function () {
        const speechOutput="すみません、まだわからないことが多くて。勉強しておきます。";
        this.emit(":ask",speechOutput,HELP_REPROMPT);
    },

SDK V1時代にも上記のような「予期せぬ発話」はありましたが、
実際ここのインテントが動く事はかなり少なかったです。
ですので各自分の実装していたインテント内で、
不適切な言葉が来たら弾くなどの処理を
皆さん書かれていたかと思います。

Amazon Alexa SDK V2 、ErrorHandler(エラーハンドラ)

■Alexa SDK V2.0時代のいわゆる「予期せぬ発話」

const ErrorHandler = {
    canHandle() {
        return true;
    },
    handle(handlerInput, error) {
        return handlerInput.responseBuilder
            .speak('ただしく認識出来ませんでした。もう一度おっしゃっていただけますか。')
            .getResponse();
    },
};

こんな感じの記述になります。

何が大きく変わったかというと、
各自作したインテント内でエラー処理が行われると、
エラーハンドラが呼び出されて処理
してくれます。

上記サンプルコード内で例を挙げるのであれば、
唯一のインテント:orderSeasoningインテント内でconst massageに代入したら
エラーになりますが、その場合はエラーハンドラが動作します

SKD V1時代では「スキルが応答しませんでした」と完全に落ちていた処理が、
ユーザーが聞いている分には違和感が起きないように処理が変更されました。

これは一長一短ですが、基本的には良いことではないのでしょうか。
デメリットは少しだけ感じたので後述します。

intentなどの出力JSONへのアクセスの仕方が変わってます。


SDK V1時代では下記のように記述されていたかと思います。
  • const intent =this.event.request.intent;
しかし、SDK V2では下記のように記述してください。
  • const intent = handlerInput.requestEnvelope.request.intent;
単純に書き換えて、頂くだけで結構です。
SDK V2で 「this.event.request.intent」にアクセスすると落ちて、
エラーハンドラに飛ばされるので注意して下さい。


各インテントが実行してOKかどうかの条件が設定できる(canHandler)


const LaunchRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
  },
  handle(handlerInput) {
    const speechText = 'さじグラムプラスへようこそ。「醤油」のようにお調べしたい調味料をおっしゃってください。どの調味料をお調べしますか?';

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

冒頭の赤字部分がそれに該当します。
出力JSONで「LaunchRequest」が来た時だけ、このインテントを処理します、という
内容です。

たとえば自作したインテント「orderSearsoning」であれば、
const orderSeasoning = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && handlerInput.requestEnvelope.request.intent.name === 'orderSeasoning';
    },

と記述いたします。

intentを新しく作る場合はexports.handlerにしっかり追記する。


仮に「addIntent」インテントを追加する場合は下記を追加します。

const addIntent = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && handlerInput.requestEnvelope.request.intent.name === 'addIntent';
    },
    handle(handlerInput) {
            //addIntent内で実行したい処理
            return handlerInput.responseBuilder
                .speak('テスト')
                .reprompt('テスト')
                .getResponse();
            }

 };

その後、最下部に記載してあるexports.handlerにインテント名を追記してください。


exports.handler = Alexa.SkillBuilders.standard()
  .addRequestHandlers(LaunchRequestHandler, orderSeasoning, addIntent)
  .addErrorHandlers(ErrorHandler) // これを追加
  .lambda();

お手数かもしれませんが、必要な記載なので宜しくお願いします。

tell、ask廃止 → Responseオブジェクトでの書き方に統一。


【AmazonAlexaスキル開発】Responseオブジェクトについて考えてみる(ask,tellなど) http://iga34engineer.blogspot.com/2018/12/amazonalexaresponseasktell_10.html

詳細につきましては上記記事を一度ご一読ください。

            return handlerInput.responseBuilder
                .speak('こんにちは'))
                .reprompt('次にお調べする調味料があればおっしゃってください。')
                .getResponse();

Alexa SDK V1時代と同じように、
Responseオブジェクトは上記のようにご記載ください。
次の見出しで書き方についてご紹介いたします。

SDK V2で「会話(セッション)を終了させる場合」(以前のtell)


            return handlerInput.responseBuilder
                .speak('こんにちは')
                .getResponse();

レスポンスには「shouldEndSessionキー」が含まれていない為、
trueとなり、アレクサの発話後、直ちにセッションは終了します。
以前tellで書かれていた内容になります。


SDK V2で「会話(セッション)を継続する場合」(以前のask)


            return handlerInput.responseBuilder
                .speak('こんにちは')
                .reprompt('次にお調べする調味料があればおっしゃってください。')
                .getResponse();

レスポンスには「shouldEndSessionキー」がfalseとなり、
アレクサの発話後、会話は継続します。
そしてアレクサの発話の後、ユーザーからの返答を待つようになります。
もし返答が無ければreprompt()内を発話します。
それでもユーザーの返事がなければセッションが終了します。

余談(SDK V1 互換モジュールについて)




一応こういうモジュールも無くはないですが、
最終的にはSDK V2に統合されると思うので、
まずはV2での書き方を取り扱ってみました。

配布ファイルには「ask-sdk-vladaptor」も入っているので
モジュール読み込みして実行は出来る筈ですので、
興味のある方は試してみて下さい。

余談(npmインストール手順について)


読み飛ばしてOKですし、理解する必要はありません。
ただ、ターミナルを利用したインストール手順など知りたい方もいらっしゃると思うので
一応簡単に手順だけはご紹介だけはしておきます。
  1. npmのバージョンチェック
  2. 「npm install --save ask-sdk」でインストール
  3. 生成された「node_modules」内のフォルダ内ファイルの中から
    下記ファイルをコピー
    • ask-sdk
    • ask-sdk-core
    • ask-sdk-dynmodb-persistence-adapter
    • ask-sdk-model
    • ask-sdk-runtime
  4. 以前使っていたSDK V1時代の「node_modules」内を全削除して、
    上記ファイルをコピペ
  5. zip化してアップロード(以降は当記事で、みなさんにご紹介している方法)

まとめ

  • Alexa SDK V2、導入実際頑張ったら難しくなかった。
  • 当記事読んだら更に楽だと思う!
  • みんなでAlexa SDK V2にアップデートしましょう!

0 件のコメント:

コメントを投稿