スキルにAlexaショッピングアクションを実装する

スキルにAlexaショッピングアクションを実装する

スキルは、Skill Connectionsインターフェースを使用してAlexaショッピングフローを開始します。ユーザーのAmazonカートに商品を追加するには、AddToShoppingCartタスクを呼び出します。商品を購入するには、BuyShoppingProductsタスクを呼び出します。どちらのタスクも、ショッピングエクスペリエンスを完了するには、Alexaとユーザーの間でマルチターンの対話を始めます。

スキルでAlexaショッピングアクションを使うには、ユーザーがAlexaアプリで音声による購入を有効にする必要があります。

カートへの追加フローを実装する

AddToShoppingCartアクションは、勧められた商品をユーザーのカートに追加します。ユーザーは、後からAmazonリテールウェブサイトを開いて、この商品を確認できます。ユーザーが、スキルセッション中に購入の意思決定を行うことはありません。

以下の手順に従って、スキルコードにAlexaショッピングのAddToShoppingCartアクションを実装します。

カートに商品を追加するディレクティブを送信する

ユーザーから商品を購入する許可を得たら、AddToShoppingCartペイロードを含むConnections.StartConnectionディレクティブをAlexaに送信します。

以下は、指定された商品をカートに追加するリクエストの例です。

クリップボードにコピーされました。

/**
 * RecommendAndShopForProductsを処理するハンドラー
 */
const RecommendAndShopForProductsHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'IntentRequest'
            && (request.intent.name === 'RecommendAndShopForProducts');
    },
    handle(handlerInput) {
        console.log("RecommendAndShopForProductsを受信しました。");

        const speechText = "<商品の紹介>" +
        " この商品をAmazonのカートに追加しますか?"

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

/**
 * YesAndNoIntentHandlerを処理するハンドラー
 */
const YesAndNoIntentHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'IntentRequest'
            && (request.intent.name === 'AMAZON.YesIntent'
                || request.intent.name === 'AMAZON.NoIntent');
    },
    handle(handlerInput) {
        const intentName = handlerInput.requestEnvelope.request.intent.name;
        console.log("ユーザー発話:" + intentName);

        if (intentName === 'AMAZON.YesIntent') {
            var actionText = "Amazonで商品を準備しています"
            let actionTask = {
              'type': 'Connections.StartConnection',
              'uri': 'connection://AMAZON.AddToShoppingCart/1',
              'input': {
                   'products' : [
                     {
                       'asin' : 'B01962MDHA'
                     }
                   ]
                },
              'token': 'AddToShoppingCartToken'
          };

            return handlerInput.responseBuilder
            .speak(actionText)
            .addDirective(actionTask)
            .getResponse();
        }

        const speechText = "わかりました。またご利用ください。"

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

セッション再開リクエストを処理する

スキルは、SessionResumedRequestとして購入結果を受け取ります。結果には、AddToShoppingCartリクエストで指定されたtokenが含まれます。SessionResumedRequest応答を受け取るハンドラーを実装します。ペイロードに含まれるresultに基づいてスキルを再開します。tokenを使用して保存済みのスキルセッションを読み込み、スキルエクスペリエンスを変更してエラーを処理します。

以下は、セッション再開リクエスト応答を処理する方法の例です。

クリップボードにコピーされました。

/**
 * SessionResumedRequestを処理するハンドラー。
 */
const SessionResumedRequestHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'SessionResumedRequest';
    },
    handle(handlerInput) {

        // セッションアトリビュートとIDは、前回のIntentRequestと同じです
        const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
        console.log("sessionAttributes : " + JSON.stringify(sessionAttributes));
        const token = handlerInput.requestEnvelope.request.cause.token;

        let request = handlerInput.requestEnvelope.request;
        let speechText = "すみません。リクエストに対応できませんできませんでした。もう一度試してみてください。";

        if (request.cause) {
             const token = request.cause.token;
             const status = request.cause.status;
             const code = status.code;
             const message = status.message;
             const payload = request.cause.result;

             console.info(`[Shopping Response] ${JSON.stringify(request)}`);
             console.info(`[INFO] ショッピングアクションの結果: コード - ${code}、メッセージ - ${message}、ペイロード - ${payload}`);

             switch(code) {
                 case '200':
                     if (typeof payload !== "undefined") {
                         if (payload.code === "AlexaShopping.RetryLaterError") {
                             speechText =  "問題が発生しました。スキルに戻ります。";
                         } else {
                             speechText = "すみません。ショッピングでリクエストの処理中に問題が発生しました。後でもう一度試してください。";
                             console.info(`[INFO] ショッピングアクションでリクエストの処理中に問題が発生しました。 ${payload.message}`);
                        }
                    } else if (token === "AddToShoppingCartToken") {
                        console.info(`[INFO] ショッピングアクション: カートへの追加アクションは成功しました。トークン:${token}。`);
                        speechText = "商品をカートに追加しました。";
                    }
            break;
            default :
                console.info(`[INFO] ショッピングアクション: ショッピングアクションの実行中に問題が発生しました。`);
                speechText = "商品をカートに追加できませんでした。";
            }
        }

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

購入フローを実装する

BuyShoppingProductsアクションを使うと、ユーザーは商品を購入できます。このアクションは、ユーザーに商品と最終価格を提示し、商品の購入を確認するマルチターンの対話を進めます。購入ワークフローに、ユーザーのアカウントに登録された有効な支払い方法、お届け先住所、音声によるPIN認証といった、さまざまなチェックを組み込みます。

スキルの内部でBuyShoppingProductsアクションを使用するには、ユーザーがAmazonアカウントでデフォルトの1-Click設定を有効にする必要があります。ユーザーがこのオプションを有効にしていない場合、Alexaショッピングはユーザーに必要な設定を有効にするよう伝え、InvalidCustomerSettingsのステータスコードを含む応答で適宜情報を返します。

以下の手順に従って、スキルコードにAlexaショッピングのBuyShoppingProductsアクションを実装します。

商品を購入するディレクティブを送信する

スキルがユーザーから商品購入の許可を得たら、BuyShoppingProductsペイロードを含むConnections.StartConnectionディレクティブをAlexaに送信します。

以下は、商品購入フローを開始するリクエストの例です。

クリップボードにコピーされました。

/**
 * RecommendAndShopForProductsを処理するハンドラー
 */
const RecommendAndShopForProductsHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'IntentRequest'
            && (request.intent.name === 'RecommendAndShopForProducts');
    },
    handle(handlerInput) {
        console.log("RecommendAndShopForProductsを受信しました。");

        const speechText = "<商品の紹介>" +
        " この商品をAmazonで購入する方法を知りたいですか?"

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

/**
 * YesAndNoIntentHandlerを処理するハンドラー
 */
const YesAndNoIntentHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'IntentRequest'
            && (request.intent.name === 'AMAZON.YesIntent'
                || request.intent.name === 'AMAZON.NoIntent');
    },
    handle(handlerInput) {
        const intentName = handlerInput.requestEnvelope.request.intent.name;
        console.log("ユーザー発話:" + intentName);

        if (intentName === 'AMAZON.YesIntent') {
            var actionText = "Amazonで商品を準備しています"
            let actionTask = {
              'type': 'Connections.StartConnection',
              'uri': 'connection://AMAZON.BuyShoppingProducts/1',
              'input': {
                   'products' : [
                     {
                       'asin' : 'B01962MDHA'
                     }
                   ]
                },
              'token': 'PurchaseProductToken'
          };

            return handlerInput.responseBuilder
            .speak(actionText)
            .addDirective(actionTask)
            .getResponse();
        }

        const speechText = "わかりました。" +
                              "またご利用ください。"

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

セッション再開リクエストを処理する

スキルは、SessionResumedRequestとして購入結果を受け取ります。結果には、BuyShoppingProductsリクエストで指定されたtokenが含まれます。SessionResumedRequest応答を受け取るハンドラーを実装します。ペイロードに含まれるresultに基づいてスキルを再開します。tokenを使用して保存済みのスキルセッションを読み込み、スキルエクスペリエンスを変更してエラーを処理します。

以下は、セッション再開リクエスト応答を処理する方法の例です。

クリップボードにコピーされました。

/**
 * SessionResumedRequestを処理するハンドラー。
 */
const SessionResumedRequestHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'SessionResumedRequest';
    },
    handle(handlerInput) {

        // セッションアトリビュートとIDは、前回のIntentRequestと同じです
        const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
        console.log("sessionAttributes : " + JSON.stringify(sessionAttributes));
        const token = handlerInput.requestEnvelope.request.cause.token;

        let request = handlerInput.requestEnvelope.request;
        let speechText = "すみません。リクエストに対応できませんできませんでした。もう一度試してみてください。";

         if (request.cause) {
             const token = request.cause.token;
             const status = request.cause.status;
             const code = status.code;
             const message = status.message;
             const payload = request.cause.result;

             console.info(`[Shopping Response] ${JSON.stringify(request)}`);

             console.info(`[INFO] ショッピングアクションの結果: コード - ${code}、メッセージ - ${message}、ペイロード - ${payload}`);

             switch(code) {
                 case '200':
                     if (typeof payload !== "undefined") {
                         if (payload.code === "AlexaShopping.RetryLaterError") {
                             speechText =  "問題が発生しました。スキルに戻ります。";
                         } else {
                             speechText = "すみません。ショッピングでリクエストの処理中に問題が発生しました。後でもう一度試してください。";
                             console.info(`[INFO] ショッピングアクションでリクエストの処理中に問題が発生しました。 ${payload.message}`);
                        }
                     } else if (token === "PurchaseProductToken") {
                             console.info(`[INFO] ショッピングアクション: 購入アクションは成功しました。トークン:${token}.`);
                             speechText = "商品を購入しました。ありがとうございます。";
                         }
                    break;
            default :
                console.info(`[INFO] ショッピングアクション: ショッピングアクションの実行中に問題が発生しました。`);
                speechText = "商品を購入できませんでした。";
            }
        }

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

返金リクエストを処理する

返金リクエストを処理するには、ユーザーにAmazonアカウントの注文を確認するよう案内します。返金を処理するAlexaショッピングアクションはありません。

クリップボードにコピーされました。

 const RefundHandler = {
     canHandle(handlerInput) {
         return util.parseIntent(handlerInput) === 'RefundIntent';
     },
     handle(handlerInput) {

         return handlerInput.responseBuilder
         .speak("Amazonアカウントの注文セクションで注文の確認またはキャンセルを行ってください。")
         .getResponse();
     },
 }