「AlexaスキルとSlackで買いものを便利に」をやってみた

## はじめに
はじめまして。oka-shiです。

Alexaに買いたいものを伝えるとSlackに通知される「スラックスキル」を作成してみました。元ネタは、下記のよーぐると様のブログとなります。
　[AlexaスキルとAWS Lambda, Slackを使って我が家の買いもの管理を便利にした話](https://yoghurt1131.hatenablog.com/entry/2018/12/26/072907)

Alexa初心者でも簡単に実装できたので、参考にしたサイト、Alexaスキル設定、Lambda→Slackへの連携 などをまとめてみました。

### 対象読者
* Alexaスキルを作ってみたい方
* Lambda(Node.js 10.x版)→Slackへの連携をやりたい方

### 説明すること
* スラックスキルの概要
* Alexaスキル作成の前にやること
* Alexaスキル作成のポイント
* Lambda(Node.js 10.x版)→Slackへの連携設定
* Alexa初心者がつまずいたトコ

### 説明しないこと
* スラックスキルの詳細
* Alexaの初期設定や基礎知識
* Node.jsの全般

### 目次
* 0. スラックスキルとは
* 1. Alexaスキル作成の前にやること
* 2. Alexaスキル作成のポイント  
・スロットタイプ設定  
・インテント - サンプル発話設定  
・インテント - インテントスロット設定  
* 3. Lambda(Node.js 10.x版)→Slackへの連携設定  
・Slack側：Webhook URLを取得する  
・Lambda側：Webhook URLを設定する  
・Lambda→Slackへの連携確認  
* 4. Alexa初心者がつまずいたトコ  
・Lambda(Node.js 10.x版)のHTTPS通信について  
・AlexaスキルのLambdaのデバッグログについて  
* 5. まとめ  
* 参考サイト

## 0. スラックスキルとは
Alexaに買いたいものを伝えるとSlackに通知される、買いものリスト通知スキルです。イメージを図にするとこんな感じです。
ポイントは、買いものリストをSlackで一元管理しているトコです。買いものリストは誰が片付けても良いので、家族で分担できるのがいいですね。

### ■買いものリスト通知のイメージ

![買いもの通知.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676914/27ba0a23-7e8d-cbd1-9449-ff9422624c27.jpeg)

スラックスキルの詳細を知りたい方は、[よーぐると様のブログ](https://yoghurt1131.hatenablog.com/entry/2018/12/26/072907)を参照頂ければと思います。
また、Alexaスキルのしくみに興味がある方は、[Alexa道場 S02 EP02 Alexaスキルのしくみ](https://www.youtube.com/watch?v=bzOeFN25sxU&feature=youtu.be) が丁寧で分かりやすいと思います。



## 1. Alexaスキル作成の前にやること
Alexaスキルを作成する前に、初期設定、Alexa開発者アカウント、基礎知識が必要となるため、参考にしたサイトを記載します。
基礎知識は、Alexa道場がとても理解しやすかったのでオススメです。本記事のレベルであれば、「Season 1 : はじめてのAlexaスキル開発」～「Season 3 : スロットを使いこなそう」を見ておけば十分でした。

* Alexaの初期設定
  * [Amazon Alexa（Amazon Echo）の設定方法](https://complesso.jp/2882/) 
* Alexa開発者アカウントの作り方
  * [失敗しないAlexa開発者アカウントの作り方](https://dev.classmethod.jp/articles/how-to-safety-create-alexa-developers-account/)
* Alexaスキルの基本
  * [Alexa公式 動画シリーズ「Alexa道場」](https://developer.amazon.com/ja-JP/alexa/alexa-skills-kit/get-deeper/webinars)

## 2. Alexaスキル作成のポイント  
Alexaスキル作成におけるポイントとして、インテントとスロットの設定が必要となります。
買いものリスト通知の「スラックスキル」の場合、Alexa道場のハンズオン「コーヒーショップスキル」をベースにすると簡単に作成することができます。
以降、「コーヒーショップスキル」からの差分を記載します。

### スロットタイプ設定
Alexaに「買いたいもの」を認識させるために、スロットタイプを設定します。
oka-shi家の買いたいものは食料品が多いので、AMAZON.Foodを指定しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676914/596055b2-7186-3826-ca8f-4640db057034.png)

### インテント - サンプル発話設定
Alexaに会話の中から「買いたいもの」を識別してもらうために、インテントのサンプル発話を設定します。
サンプル発話に買いたいもののキーワード`{things} `を埋め込むことで、「買いたいもの」を抽出できるようになり、Lambda側へ送信できるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676914/3f20d275-4e3e-5882-11b2-b31bf526d6cc.png)

```csv
{things} を買っておいて
{things} 買っておいて
{things} を買っといて
{things} 買っといて
{things} って書いて
{things} を書いて
{things} を登録して
{things} を入れて
{things} を追加して
{things} が欲しい
{things} が食べたい
```

### インテント - インテントスロット設定  
買いたいもののキーワード`{things} `とスロットタイプを関連付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676914/e7372da1-5f45-b500-7222-556c8adf7b3e.png)

## 3. Lambda(Node.js 10.x版)→Slackへの連携設定  
LambdaからSlackへの連携は、SlackのWebhook URLを使用して行います。

### Slack側：Webhook URLを取得する  
別記事の「Slack側：Webhook URLを取得する」を参照下さい。
　 [BizDevOpsサービス導入ガイド GitLab + Slack編](https://qiita.com/oka-shi/items/f4b0216b8e5f05bf2bdb) 

### Lambda側：Webhook URLを設定する  
SlackのWebhook URLに向けて、JSON形式のメッセージを指定して、HTTPSプロトコルでリクエストします。
コードは、下記サイトを参考にさせて頂きました。

  * [AlexaスキルとAWS Lambda, Slackを使って我が家の買いもの管理を便利にした話](https://yoghurt1131.hatenablog.com/entry/2018/12/26/072907)
  * [node.jsでIncoming-webhookでslackメッセージ送る](https://qiita.com/zaburo/items/d6446b9e52b102b8a7ae)

コード上のpathは、Slack側から取得したWebhook URLを指定すればOKです。

また、Slackに投稿するメッセージ設定ですが、usernameやicon_emojiを指定してもユーザ名やアイコンを変更できない仕様になったそうなので、指定を削除しました。

  * [slackのIncoming webhookが新しくなっていたのでまとめてみた](https://qiita.com/kshibata101/items/0e13c420080a993c5d16)

```index.js
const ToBuyIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'ToBuyIntent';
    },
    handle(handlerInput) {
        // thingsスロット(=買うもの)を取得
        const slots = handlerInput.requestEnvelope.request.intent.slots;
        let things = slots.things.value;

        // Alexaの発話
        const speakOutput = `${things}ですね。わかりました。`;

        // Slackに投稿するためのパラメータをCloudWatch Logsへ出力
        console.log(`Slackに${things}を投稿しました。`);

        // メッセージ設定
        var data = JSON.stringify({"text": `${things}を買っておいてね。`});

        // オプション情報設定
        var  options = {
            hostname: 'hooks.slack.com',
            port: 443,
            path: '/services/AAAAAAAA/BBBBBBBB/CCCCCCCCCCCCCCC',
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Content-Length': Buffer.byteLength(data)
            }
        };

        // リクエスト
        const https = require('https');
        var req = https.request(options, (res) =>{
            if(res.statusCode===200){
                console.log("OK:"+res.statusCode);
            }else{
                console.log("Status Error:"+res.statusCode);
            }
        });

        // そもそもなエラー時
        req.on('error',(e)=>{
            console.error(e);
        });

        // データ送信
        req.write(data);
        // 終わり
        req.end();

        return handlerInput.responseBuilder
            .speak(speakOutput)
            //.reprompt('add a reprompt if you want to keep the session open for the user to respond')
            .getResponse();
    }
};
```

### Lambda→Slackへの連携確認  
alexa developer consoleのAlexaシミュレータを使うことで、Slackへの連携を確認することができます。  
今回、スロットタイプにAMAZON.Foodを指定しただけですが、食料品以外のキーワードも自動で認識してくれるようです。Alexaは賢くて良い子ですね。

#### Alexaシミュレータのイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676914/9c7ad529-6ad6-6e36-c1b5-baf1e36e7681.png)


#### Slackの買いものリストのイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676914/5862129c-f22b-5645-311b-60eabf0e9b46.png)
 
### 4. Alexa初心者がつまずいたトコ
#### Lambda(Node.js 10.x版)のHTTPS通信について  
[AlexaスキルとAWS Lambda, Slackを使って我が家の買いもの管理を便利にした話](https://yoghurt1131.hatenablog.com/entry/2018/12/26/072907)を参考に、HTTPS通信を`require("request-promise")`を実行したところ、以下のエラーとなりました。

```text
Unknown application error occurred Runtime.ImportModuleError
Runtime.ImportModuleError: Error: Cannot find module 'request-promise'
```

今回は、動かすことを優先したかったので、HTTPS通信は`require('https')`で実装しました。[Node.js v10.23.0 Documentation](https://nodejs.org/docs/latest-v10.x/api/)は、きちんと読めていないのでリンクを残しておきます。

#### AlexaスキルのLambdaのデバッグログについて  
AlexaスキルのLambdaのデバッグログは、alexa developer consoleからCloudWatch Logsへ遷移しないと表示できないようです。
また、CloudWatch Logsへ遷移した場合でも、以下のエラーが表示されることがありました。

```
フェデレーションログイン: VoiceHubSSORole/VoiceHubSSORole

ログストリームの説明中にエラーが発生しました。
The specified log group does not exist.

ロググループが存在しません
特定のロググループ: /aws/lambda/xxxxx-xxxx-xxxx-xxxx-xxxxxxxx はこのアカウントまたはリージョンに存在しません。
```

原因は、alexa developer consoleのLogs選択で、CloudWatch Logsを出力していないリージョン（Defaultのバージニア北部）を指定していたためです。
私の場合は、alexa developer consoleのLogsでオレゴンを選択すれば、正しく表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676914/c59782c6-2da2-872f-f4ef-1d87e099bbde.png)

### 5. まとめ  
買いものリスト通知の「スラックスキル」を使ってみた感想ですが、声だけで買いたいものをSlackに通知できるのは便利でした。

   * 料理をしている際に食材や調味料が少なくなったことに気づいたら、料理を続けながら声だけで買いものを依頼できる。
   * 幼児がアイスやお菓子を食べたくなった際に、声だけでおやつを依頼できる。
   * 病気の際にも使えると思います。あと介護でも使えそうですね。

また、買いものリストをSlackで一元管理しているので、家族で買いものを分担できるのがいいですね。（大事なことなので）

Alexaスキルを作ってみた感想ですが、AWS公式のAlexa道場が分かりやすく、Alexa初心者でもサクサク作れて楽しかったです。AWSは公式のWebinarが充実していたり、情報を上げて頂ける方が多いので、キャッチアップをやりやすいのがいいですね。

### 参考サイト
* 元ネタ
  * [AlexaスキルとAWS Lambda, Slackを使って我が家の買いもの管理を便利にした話](https://yoghurt1131.hatenablog.com/entry/2018/12/26/072907)
* Alexa
  * [Alexa公式 動画シリーズ「Alexa道場」](https://developer.amazon.com/ja-JP/alexa/alexa-skills-kit/get-deeper/webinars)
  * [Alexa道場 S02 EP02 Alexaスキルのしくみ](https://www.youtube.com/watch?v=bzOeFN25sxU&feature=youtu.be) 
  * [失敗しないAlexa開発者アカウントの作り方](https://dev.classmethod.jp/articles/how-to-safety-create-alexa-developers-account/)
  * [Amazon Alexa（Amazon Echo）の設定方法](https://complesso.jp/2882/) 
* Lambda→Slackへの連携
  * [node.jsでIncoming-webhookでslackメッセージ送る](https://qiita.com/zaburo/items/d6446b9e52b102b8a7ae)
  * [slackのIncoming webhookが新しくなっていたのでまとめてみた](https://qiita.com/kshibata101/items/0e13c420080a993c5d16)
* Slack Webhook URL
  * [BizDevOpsサービス導入ガイド GitLab + Slack編]
(https://qiita.com/oka-shi/items/f4b0216b8e5f05bf2bdb) 
* Node.js 10.x版
  * [Node.js v10.23.0 Documentation](https://nodejs.org/docs/latest-v10.x/api/)