Alexaを使ってSlackにメモを保存する

## 動機
　寝転がりながら布団にくるまって、本を読むのが趣味なのですが、本を読んでいると突然よいアイデアが浮かぶことがあります。

　しかし、起き上がるのも、スマホを立ち上げるのも、紙に書くのも面倒なので、何とかできないかと考えました。

　最近はやりのスマートスピーカーを使えば、全く動かずにメモを取れるのではと考えました。何も考えずに買ったAmazon Echoが家にあったのでそれを使いました。

## 要件
- 音声だけでメモが取れる
- 内容に制約がない
- どこででも確認できる
    - Webサービスに保存したい

## 準備

### 手段の検討
　調べたところ、「買い物リスト」と「やることリスト」でもできそうな気はしましたが、削除するのが面倒そうなのとWeb経由でみたいという要望にかなわず却下しました。

　仕方ないので、自分用のスキルを使って実現することにしました。

### 転送先の検討
　検討候補は以下の通りです。

- Line
- Scrapbox
- Google Keep
- Slack

　LineはWebサービスじゃないですが、どこでも確認できるという点では及第点なので候補に挙げました。

　APIの有無や手軽さを考えると、SlackがよさそうなのでSlackにしました。

　しかし、LineのMessaging APIを使って、Push通知がベストだったのではないかという気は少ししています。

### Slackのトークンの取得
　下記の記事を参考にSlackのトークンを取得しました。さすがSlackだけあって簡単でした。

[Slack APIでメッセージ送信](https://qiita.com/mizuki_takahashi/items/3f77c2e5b6142563ce66)

## スキルの実装

### 基本設定
　Amazon 開発者コンソールから Alexa スキルに進んで、設定します。

　基本的な設定は下記を参考にやりました。

[ユーザーの自由発話に対応する Alexa Skill を作る](https://qiita.com/halhorn/items/48998d6b7a166cc905c6)

- 日本語
- カスタム対話モデル
- メモ書き（スキル名・呼び出し名）

### スキーマの作成

　設定は大体上記の記事に沿っているので特に説明することもないです。

```json
{
    "languageModel": {
        "invocationName": "メモ書き",
        "intents": [
            {
                "name": "AMAZON.HelpIntent",
                "slots": [],
                "samples": []
            },
            {
                "name": "MemoIntent",
                "slots": [
                    {
                        "name": "Memo",
                        "type": "any"
                    }
                ],
                "samples": [
                    "{Memo}"
                ]
            }
        ],
        "types": [
            {
                "name": "any",
                "values": [
                    {
                        "id": "",
                        "name": {
                            "value": "ほげほげ",
                            "synonyms": []
                        }
                    }
                ]
            }
        ]
    }
}
```

　ポイントとしては以下のようです。

+ サンプル発話をスロットそのものにすること
    + 好きな内容が保存できる
+ スロットのtypeをanyとして適当にかぶらない値を突っ込むこと

　自由発話は基本ダメという、穴を付いた方法らしいのでいつまで大丈夫かは微妙ですね。それ用のスロットは英語ならあるらしいです。

### エンドポイントの実装

　エンドポイントはAWS Lambdaで作りました。言語はNode.jsです。詳しいことは下記のサイトに従いました。

[Alexa Skills Kit for Node.js はじめの一歩](https://dev.classmethod.jp/cloud/alexa-skills-kit-for-node-js-first/)

#### 環境変数の設定

　環境変数を保存します。Gitで管理したかったので、こういう情報が隠せるのはありがたいです。

- APP_ID
    - 先ほど作ったスキルのID
- BOT_TOKEN
    - Slackのトークン
- CHANNEL
    - 送信先のチャンネル

#### ライブラリのダウンロード

 AlexaのSDKとHTTP通信用のaxiosをダウンロードします。

```
npm init
npm install --save alexa-sdk axios
```

#### ハンドラーの実装

```javascript
"use strict";
var Alexa = require('alexa-sdk');
var axios = require('axios');
var HELP_MESSAGE = 'つぶやきたい言葉をささやいてください';
var SUCCESS_MESSAGE = 'メモを保存しました';
var FAILED_MESSAGE = '保存に失敗しました';

var handlers = {
    'LaunchRequest': function () {
        this.emit('AMAZON.HelpIntent');
    },
    'AMAZON.HelpIntent': function () {
        this.emit(':ask', HELP_MESSAGE);
    },
    'MemoIntent': function () {
        var memo = this.event.request.intent.slots.Memo.value;
        if(!memo) {
            this.emit(':tell', FAILED_MESSAGE);
            return;
        }
        axios.get(
            'https://slack.com/api/chat.postMessage',
            { 
                params:{
                    token: process.env.BOT_TOKEN,
                    channel: process.env.CHANNEL,
                    text: memo
                }
            })
            .then(res => {
                this.emit(':tell', SUCCESS_MESSAGE);
            })
            .catch(err => {
                this.emit(':tell', FAILED_MESSAGE);
            });
    }
};

exports.handler = function (event, context, callback) {
    var alexa = Alexa.handler(event, context);
    alexa.appId = process.env.APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};
```

　起動した際にaskを起動して、その回答をSlackに投げているだけです。比較的シンプルな実装かなと思います。

#### ソースコードのアップロード

　自分はローカルで開発して、zipに圧縮してソースコードをアップロードしました。

　7-Zipではうまくいかず、Windowsの基本機能だとうまくいきました。結構はまりましたが、理由はよくわかっていません。

### 仕上げ

　[ユーザーの自由発話に対応する Alexa Skill を作る](https://qiita.com/halhorn/items/48998d6b7a166cc905c6)の記事にしたがって、AWS LambdaとAlexaを繋げます。

　そのあとは適当にテストした後、公開情報などを埋めます。

　公開するつもりはないので、ここまでで自分的にはOKでした。

## 結果

　保存できました。

　![screenshot.1.jpg](https://qiita-image-store.s3.amazonaws.com/0/229574/9121d377-bc0f-2923-db41-9f4f18f6609a.jpeg)

　漢字変換の質が微妙だったり、一気に言わないといけないのが地味につらいですが、最低限の目標は達成できました。

　でも読書が止まるので、頭の中身を読み取って吐いておいてほしいという気持ちはあります。

## 感想

　IFTTTを使えばもう少し楽に行けたかもしれないという気持ちと、Lineのほうがよかったんじゃないかという気持ちはあります。

　しかし、役に立つものはできたので、まぁまぁ満足です。