Cloud9とGAEでClovaの公式チュートリアルを一瞬で突破してみた

2018年7月12日に[Clova Extensions Kit（CEK）](https://clova-developers.line.me/)がリリースされました。
（３連休前に公開していただいたことにありがたみを感じています！）

用意していただいている[チュートリアル](https://clova-developers.line.me/guide/#/CEK/Tutorials/Introduction.md)は短時間で試せる内容ですが、
個人的にさらに素早く楽に試せるような各種ツールを使いましたので
軽い気持ちで記録を残しておこうと思います。( ..)φメモメモ

ちなみに、既に最速組の方々がCEK関連の記事を投稿なさっているようですのでそちらもすごく参考になると思います。

* [[入門]Clovaスキル(CEK)は作りながら覚えて行く（前提知識編）](
https://qiita.com/imajoriri/items/8d511cdfde8cb731ff82)

* [3分でClovaスキル「サイコロトーク」を作ってみた](
https://qiita.com/h-takauma/items/9162aebe42e358538442)

* [Clovaに話しかけて家電を操作してみる](
https://qiita.com/miso_develop/items/f3eb644b8816b41f6792)

# 楽するために使うサービスたち
CEK以外のツールとしては下記を使いました。

* AWS Cloud9
* GoogleAppEngine

# さっそくチュートリアル
チュートリアルは下記にあります。さっそく実施していきましょう！

* https://clova-developers.line.me/guide/#/CEK/Tutorials/Introduction.md
* https://clova-developers.line.me/guide/#/CEK/Tutorials/Build_Simple_Extension.md

## ステップ1 Extensionサーバーを用意する
今回はまず[AWS Cloud9](https://aws.amazon.com/jp/cloud9/?sc_channel=PS&sc_campaign=acquisition_JP&sc_publisher=google&sc_medium=cloud9_english_b&sc_content=cloud9_p&sc_detail=cloud%209&sc_category=cloud9&sc_segment=276999033731&sc_matchtype=p&sc_country=JP&sc_brand=brand&ef_id=VuuwGAAABeIKTMIL:20180715145930:s)を使います。
こんな感じのWebブラウザ上で使えるIDEみたいなものです。
ある程度各種ランタイムの環境も整っているので、環境構築で挫折する確率が圧倒的に減るのではないかと思います。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/55c98feb-1e91-6a9e-cb03-f7cb1d0dca99.png)

Cloud9はTerminalが用意されていてコマンドが打てるようになっています。
このTerminal上でおもむろにチュートリアルのコマンドを叩いていきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/cdf66311-04fd-646c-c886-7d0ad828da11.png)

```shell
git clone https://github.com/line/clova-extension-sample-dice.git
cd clova-extension-sample-dice
git checkout tutorial1
npm install
```
```
ﾊﾞﾝﾊﾞﾝﾊﾞﾝﾊﾞﾝﾊﾞﾝﾊﾞﾝﾊﾞﾝ
ﾊﾞﾝ　　　　 ﾊﾞﾝﾊﾞﾝﾊﾞﾝ
ﾊﾞﾝ (∩`･ω･)　ﾊﾞﾝﾊﾞﾝ
　＿/_ﾐつ/￣￣￣/
　　　＼/＿＿＿/￣￣
```

ついでにgit cloneで落としてきたconfig.jsの「ExtensionId」をClova Developer Centerで設定する値に変更しておきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/5a1992a9-9d69-88af-6643-3d31a889362b.png)


```javascript:config.js
module.exports = {
  SERVER_PORT: process.env.SERVER_PORT || 3000,
  DOMAIN: 'https://clova-common.line-scdn.net/dice',
  ExtensionId: '<Your ExtensionId>'
}
```
「ExtensionId」はClova Developer Center上で設定する、下記赤枠に記載されているような値のことです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/9a1f8e20-cc6c-7889-117d-de427663cc31.png)

### Extensionサーバー(デプロイ先)の選択肢
自分が試した選択肢は今のところ下記です。順番に見ていきます。

1. ngrok でやってしまった
2. now,heroku でお手軽にデプロイ
3. GoogleAppEngine をやっぱり使いたいですよね！

#### 1. ngrok でやってしまった
これは一番最初に横着してしまっただけです、最近時間に追われているのでorz
cloud9上ですべて完結できますが、動作確認ぐらいの用途になります。
下記のコマンドをcloud9のTerminal上で打ち

```shell
cd clova-extension-sample-dice
node app.js
```

```shell
cd clova-extension-sample-dice
npm i -g ngrok
ngrok http 3000
```
下記画面のようにhttpsのURLが取得できますので、Clova Developer Centerの方で「https://hoge.io/clova」 と設定してやります。以上
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/5efd6bb9-20a2-fe8e-b744-0bcd77bbf52f.png)


#### 2. now,heroku でお手軽にデプロイ
正直Herokuは今回まだやってないんですが、たぶんnowとだいたい同じ感じでお手軽かなぁと思いますｗ

package.jsonの「scripts」に「"start": "node app.js",」を追加します。

```json:package.json
{
  "name": "clova-ext-sound",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.18.2",
    "cookie-parser": "^1.4.3",
    "crypto": "^1.0.1",
    "express": "^4.16.2",
    "lodash": "^4.17.10",
    "morgan": "^1.9.0",
    "uuid": "^3.1.0"
  }
}
```

```shell
cd clova-extension-sample-dice
npm i -g now
now
```

超絶簡単にデプロイされて、URLｹﾞﾄできます。「https://hoge.sh/clova」 のようにClova Developer Centerの方で設定してやります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/4e3c8e39-32c3-32cd-8d71-cf4e6ccf4a48.png)


#### 3. GoogleAppEngine をやっぱり使いたいですよね！
やっぱりGAE使いたいと思うんですよ、もちろんstandardの方です！

* まずCloud9にGoogle Cloud SDK を入れてたり、初期化したりします。公式のドキュメントは[コチラ](https://cloud.google.com/sdk/docs/downloads-interactive)

```shell
curl https://sdk.cloud.google.com | bash
exec -l $SHELL
gcloud init
```

* package.json を[公式のサンプル](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/appengine/hello-world/standard/package.json)を参考にしていじります。ひとまず下記のような感じにしました。

```json:package.json
{
  "name": "clova-ext-sound",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "deploy": "gcloud app deploy",
    "start": "node app.js",
    "lint": "repo-tools lint",
    "pretest": "npm run lint",
    "system-test": "repo-tools test app",
    "test": "npm run system-test",
    "e2e-test": "repo-tools test deploy"
  },
  "author": "",
  "license": "ISC",
  "engines": {
    "node": "8.x.x"
  },
  "dependencies": {
    "body-parser": "^1.18.2",
    "cookie-parser": "^1.4.3",
    "express": "^4.16.2",
    "lodash": "^4.17.10",
    "morgan": "^1.9.0",
    "uuid": "^3.1.0"
  },
  "devDependencies": {
    "@google-cloud/nodejs-repo-tools": "^2.3.0",
    "semistandard": "^12.0.1"
  },
  "cloud-repo-tools": {
    "test": {
      "app": {
        "msg": "Hello, world!"
      }
    },
    "requiresKeyFile": true,
    "requiresProjectId": true
  }
}
```

* config.js のポートを8080に変更します。

```javascript:config.js
module.exports = {
  SERVER_PORT: process.env.SERVER_PORT || 8080,
  DOMAIN: 'https://clova-common.line-scdn.net/dice',
  ExtensionId: 'com.xxx.xxx'
}
```

* clova-extension-sample-diceの配下にapp.yaml ファイルを追加します。公式ドキュメントは[コチラ](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/tree/master/appengine/hello-world/standard
app.yaml)

```yaml:app.yaml
# Copyright 2017, Google, Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START app_yaml]
runtime: nodejs8
# [END app_yaml]
```

* 最後にdeployを実行します！公式ドキュメントは[コチラ](https://cloud.google.com/appengine/docs/standard/nodejs/quickstart)。取得したURLを「https://hoge.appspot.com/clova」 のようにClova Developer Centerの方で設定してやりましょう！

```
gcloud app deploy
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/4544084e-de69-2be7-15cc-93a6dead31fa.png)


下記、Clova Developer Centerの「ExtensionサーバーのURL」を設定！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/dc9049f9-c3fb-ef56-9e61-73beebabb56e.png)


ちなみに、サーバーにデプロイする前にpostmanとかで動作を確認しておいた方が良いでしょう。

## ステップ2 Extensionの基本情報を登録する(Clova Developer Centerで作業)
下記のClova Developer Centerの画面から各種必要な情報を設定していく必要があります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/255e0a4d-02a0-36e4-bc31-e8bc3e5c1faf.png)

設定の方法は下記の超最速組の方々の良記事が既にありますので、ここでの説明は省略します！

* [本日リリース！LINE Clovaのスキル開発の始め方〜申請編〜](
https://bit.ly/2LkzPRc)
* [[入門]Clovaスキル(CEK)は作りながら覚えて行く（インテント、スロットなど登録編）](
https://qiita.com/imajoriri/items/604ff74c4e81859771e2)

## ステップ3 対話モデルを登録する
Clova Developer Centerの「個人情報の保護および規約同意」タブの画面下に「対話モデル」のボタンがあるので押してみます。すると
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/e552040a-38a4-c0a4-238d-c0f48e23907f.png)

IntentとかSlotとか設定できる専用の画面が立ち上がります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/1efe1e9a-b2b1-c6a4-a3cd-4b8ffb943d06.png)

### Intentを追加する
チュートリアルの手順に従い、Intentを追加しましょう。「+」ボタンから
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/015f8e79-02f3-a433-92ba-22a7ba80a3c3.png)

「ThrowDiceIntent」を作成し
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/7844d59f-a026-c91b-e998-35f024d6369c.png)

サンプル発話に「サイコロを振って」と入力し、「＋」ボタンを押します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/cc9ca1c9-2563-ee0f-a525-64207115bca8.png)

設定は以上です。「保存」と「ビルド」をお忘れなく！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/8e097212-3b5a-611e-32ba-ee19a8db4926.png)

### シュミレーターでテストする
テスト画面で「サイコロを振って」と入力してテストを実施します。動きましたかね？
![image.png](https://qiita-image-store.s3.amazonaws.com/0/121860/13c528f4-8139-cf6f-a4d1-ce9294461c5e.png)

## ステップ4 Extensionの実際の動作をテストする
ここから先は、下記の公式ドキュメント通りに進めれば問題ありません。
https://clova-developers.line.me/guide/#/CEK/Tutorials/Build_Simple_Extension.md#Step4

# まとめ
Cloud9を使えば早く簡単にClovaの開発をすることができそうですね。
（自分のように絶対にローカル環境を汚したくないマンにとってもうってつけです！）
デプロイ先はどこが良いのかという議論もこれからおこってくる気配を感じます^^

また、ClovaはLINE Bot との連携が鍵を握りそうな気がしています。
開発の方は、公式のチュートリアルのソースコードやサンプルコードを元に
自分用にカスタマイズしていくのが楽かなぁと思いますので、そちらの充実も今後期待したいですね。

あとはやはり機能アップを。。とくに下記の機能追加について皆さん是非投票してください！
https://www.line-community.me/question/5b49fc8d851f743c271a1a2e

# おまけ（Custom ExtensionとLINEを連携する）※更新中
※更新中
すごく雑に「Custom ExtensionとLINEを連携する」を試しました。
https://clova-developers.line.me/guide/#/CEK/Guides/Link_Messaging_API.md

公式チュートリアルで使われている[コチラ](https://github.com/line/clova-extension-sample-dice)のソースをベースにして

* package.json に「@line/bot-sdk」を追加

```json:package.json
{
  "name": "clova-ext-sound",
  "version": "1.0.0",
  "engines": {
    "node": "8.11.3"
  },
  "now": {
    "engines": {
      "node": "8.11.3"
    }
  },
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.18.2",
    "cookie-parser": "^1.4.3",
    "crypto": "^1.0.1",
    "@line/bot-sdk": "^6.1.0",
    "express": "^4.16.2",
    "lodash": "^4.17.10",
    "morgan": "^1.9.0",
    "uuid": "^3.1.0"
  }
}

```

* index.js に下記を追加、pushMessageを使ってみる

```javascript:index.js
const uuid = require('uuid').v4
const _ = require('lodash')
const { DOMAIN, ExtensionId } = require('../config')
const line = require('@line/bot-sdk'); //追加した行

～省略～

 //追加したブロック
const client = new line.Client({
    channelAccessToken: '<Your accesstoken>',
    channelSecret: '<Your secret>'
});

～省略～

      cekResponse.appendSpeechText(`サイコロを ${diceCount}個 投げるぜ。`)
      //pushMessageを追加
      client.pushMessage(this.session.user.userId, {
            type: 'text',
            text: `サイコロを ${diceCount}個 投げるぜ。`
      }).then(() => {
        console.log('LINE Suucess')
      }).catch((err) => {
        console.log('LINE Error')
      })
      cekResponse.appendSpeechText({
        lang: 'ja',
        type: 'URL',
        value: `${DOMAIN}/rolling_dice_sound.mp3`,
      })

～省略～
```