docs

Alexaスキル開発からリリースまでに経験したアレコレ

自己紹介

趣味など

経緯

リリース日 成果物 公開URL
11/11 EC-CUBEプラグイン Alexaカスタムスキル(4.0系)プラグイン
11/14 Alexaスキル ミラショーン オンラインストア

スキル審査は、合格まで3回が目安

審査結果 審査回数 合否
10/25 1 ×
10/31 2 ×
11/5 3

本日お伝えしたいこと

SDK は必要か?

<?php

// 応答の形式
// https://developer.amazon.com/ja/docs/custom-skills/request-and-response-json-reference.html#response-format

$response = [
    "version" => "1.0",
    "response" => [
        "outputSpeech" => [
            "type" => "PlainText",
            "text" => "PHPで実装したエンドポイントです"
        ],
        "shouldEndSession" => true,
    ],
];

header('Content-Type: application/json; charset=utf-8');
echo json_encode($response);

    /**
     * Alexa端末からのリクエストを捌くエンドポイント
     *
     * @Route("/alexa/endpoint", name="endpoint", methods={"POST","GET"})
     *
     * @param HttpRequest $httpRequest
     */
    public function endpoint(HttpRequest $httpRequest)
    {
        try {
            $alexaRequest = Request::fromAmazonRequest($httpRequest->getContent(), $_SERVER['HTTP_SIGNATURECERTCHAINURL'], $_SERVER['HTTP_SIGNATURE']);
            // Request validation
            $validator = new RequestValidator();
            $validator->validate($alexaRequest);
        } catch (\Throwable $e) {
            // BadRequest.
            return new Response(Response::$statusTexts[400], Response::HTTP_BAD_REQUEST, ['Content-Type' => 'text/plain']);
        }

        // add handlers to registry
        $requestHandlerRegistry = new RequestHandlerRegistry([
            $this->launchRequestHandler,
            $this->pointRequestHandler,
            // handlers...
            $this->sessionEndedRequestHandler,
            $this->missingRequestHandler,
        ]);

        // handle request
        $requestHandler = $requestHandlerRegistry->getSupportingHandler($alexaRequest);
        $alexaResponse  = $requestHandler->handleRequest($alexaRequest);

        // return JSON RESPONSE
        $jsonResponse = new JsonResponse($alexaResponse);
        return $jsonResponse->send();
    }

Alexaエンドポイントは json 入出力の Web API

{
	"version": "1.0",
	"response": {
		"outputSpeech": {
			"type": "PlainText",
			"text": "セットアップを実行します"
		},
		"shouldEndSession": true,
		"directives": [
			{
				"type": "Connections.SendRequest",
				"name": "Setup",
				"payload": {
					"@type": "SetupAmazonPayRequest",
					"@version": "2",
					"sellerId": "YOUR-SELLER-ID",
					"countryOfEstablishment": "JP",
					"ledgerCurrency": "JPY",
					"checkoutLanguage": "ja_JP",
					"billingAgreementAttributes": {
						"@type": "BillingAgreementAttributes",
						"@version": "2",
						"sellerNote": "PHPからのセットアップ疎通テスト",
						"sellerBillingAgreementAttributes": {
							"@type": "SellerBillingAgreementAttributes",
							"@version": "2",
							"storeName": "キューブショップ"
						}
					},
					"needAmazonShippingAddress": false,
					"sandboxMode": true,
					"sandboxCustomerEmailId": "takashi@iplogic.co.jp"
				},
				"token": "UNIQUE-TOKEN"
			}
		]
	}
}
{
  "version": "1.0",
  ...省略...
  "request": {
    "type": "Connections.Response",
    "name": "Setup",
    "requestId": "amzn1.echo-api.request.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "timestamp": "2019-11-14T19:02:06Z",
    "locale": "ja-JP",
    "status": {
      "code": "200",
      "message": "OK"
    },
    "payload": {
      "billingAgreementDetails": {
        "releaseEnvironment": "SANDBOX",
        "billingAgreementStatus": "OPEN",
        "creationTimestamp": "2019-08-09T06:05:54.745Z",
        "billingAgreementId": "C03-XXXXXXX-YYYYYYY",
        "checkoutLanguage": "ja_JP"
      }
    },
    "token": "UNIQUE-TOKEN"
  }
}
{
    "version": "1.0",
    "response": {
        "outputSpeech": {
            "type": "PlainText",
            "text": "サンドボックスでチャージを実行します"
        },
        "shouldEndSession": true,
        "directives": [
            {
                "type": "Connections.SendRequest",
                "name": "Charge",
                "payload": {
                    "@type": "ChargeAmazonPayRequest",
                    "@version": "2",
                    "sellerId": "YOUR-SELLER-ID",
                    "billingAgreementId": "C03-XXXXXXX-YYYYYYY",
                    "paymentAction": "AuthorizeAndCapture",
                    "authorizeAttributes": {
                        "@type": "AuthorizeAttributes",
                        "@version": "2",
                        "authorizationReferenceId": "test-5dcda4aecaf1d",
                        "authorizationAmount": {
                            "@type": "Price",
                            "@version": "2",
                            "amount": "300",
                            "currencyCode": "JPY"
                        },
                        "transactionTimeout": 0,
                        "sellerAuthorizationNote": ""
                    },
                    "sellerOrderAttributes": {
                        "@type": "SellerOrderAttributes",
                        "@version": "2",
                        "sellerOrderId": "1",
                        "storeName": "TestStoreName",
                        "customInformation": "テスト用カスタム情報",
                        "sellerNote": "テスト用の販売事業者のメモ"
                    }
                },
                "token": "UNIQUE-TOKEN"
            }
        ]
    }
}
{
  "version": "1.0",
  ...省略...
  "request": {
    "type": "Connections.Response",
    "name": "Charge",
    "requestId": "amzn1.echo-api.request.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "timestamp": "2019-11-14T19:02:09Z",
    "locale": "ja-JP",
    "status": {
      "code": "200",
      "message": "OK"
    },
    "payload": {
      "authorizationDetails": {
        "authorizationAmount": {
          "amount": "300.00",
          "currencyCode": "JPY"
        },
        "capturedAmount": {
          "amount": "300.00",
          "currencyCode": "JPY"
        },
        "softDescriptor": "AMZ*IPLOGIC デモサイト",
        "expirationTimestamp": "2019-12-14T19:02:08.347Z",
        "idList": [
         "S03-XXXXXXX-YYYYYYY-CZZZZZZ"
        ],
        "softDecline": false,
        "authorizationStatus": {
          "lastUpdateTimestamp": "2019-11-14T19:02:08.347Z",
          "reasonCode": "MaxCapturesProcessed",
          "state": "Closed"
        },
        "authorizationFee": {
          "amount": "0.00",
          "currencyCode": "JPY"
        },
        "captureNow": true,
        "sellerAuthorizationNote": "",
        "creationTimestamp": "2019-11-14T19:02:08.347Z",
        "amazonAuthorizationId": "S03-XXXXXXX-YYYYYYY-AZZZZZZ",
        "authorizationReferenceId": "test-5dcda4aecaf1d"
      },
      "amazonOrderReferenceId": "S03-XXXXXXX-YYYYYYY"
    },
    "token": "UNIQUE-TOKEN"
  }
}

ダイアログモデルを活用すべし

スキルを実装する前に理解しておきたいドキュメント

あるインテントでダイアログ機能を使うには?

インテントに、少なくとも下記のどれか一つが定義されていること

ダイアログインターフェイス

tips

VUI設計が一番大事

全てに感謝を