Edited at

Clova SDK を使ってカスタムスキルを heroku にデプロイして動かす

More than 1 year has passed since last update.

2018年7月12日に Clova Extensions Kit(CEK) がリリースされました。

チュートリアルは既に皆さまやっているようなので置いといて、

公式の Clova SDK を使ってサンプルスキルを heroku にデプロイしてみました。

実装は TypeScript を用いています。

CEK の基礎や CEK の使い方などは @imajoriri さんの以下の記事が詳しいです。


開発環境

$ heroku -v

heroku/7.7.1 darwin-x64 node-v10.6.0

$ node -v
v8.11.2

$ npm -v
6.1.0

$ git --version
git version 2.15.2 (Apple Git-101.1)


事前準備


  • git

  • heroku CLI

  • node


CEK で Extension を作成

詳細は既に皆さまが書かれておりますので割愛します。



  1. プロバイダー を登録


  2. チャネル を作成


  3. 基本設定 を入力


    1. Extension ID は後ほど使いますのでメモメモ




  4. サーバー設定 はとりあえずスルー


    1. 後でやります




  5. 配布情報 は今回はリリースしないのでスルー


  6. 個人情報の保護および規約同意 も今回はリリースしないのでスルー


  7. 対話モデル


対話モデル


  • カスタムインテントには 「KinokoIntent」を1個追加

  • サンプル発話にはとりあえず「きのこ」と「キノコ」を設定


テスト


  • サーバーの設定はしてないので、応答はありません。


スキルの実装側を作成

基本的に README.md を参照しました。

ゴールは https://github.com/chibi929/hello-clova に置きました。


プロジェクト作成

$ mkdir hello-clova

$ cd hello-clova

# リモートリポジトリはあとで `heroku CLI` が設定してくれるので init だけで OK
$ git init

# `npm init` は適当にスキップなり入力なり
$ npm init

$ npm install --save @line/clova-cek-sdk-nodejs body-parser express
$ npm install --save--dev typescript

# `src/` には後でソースコードを置きます。
$ mkdir src


package.json


package.json

{

"name": "hello-clova",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"engines": {
"node": "8.x"
},
"dependencies": {
"@line/clova-cek-sdk-nodejs": "^1.0.1",
"body-parser": "^1.18.3",
"express": "^4.16.3"
},
"devDependencies": {
"typescript": "^2.9.2"
}
}


tsconfig.json

TypeScript 用に tsconfig.json を用意


tsconfig.json

{

"compileOnSave": false,
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "lib",
"noImplicitReturns": true,
"sourceMap": true,
"lib": ["es6"]
},
"include": [
"src/"
]
}

たしか firebase init から生まれた tsconfig.json を使い回していたような。。。


ソースコード

Clova SDK のリポジトリにあった example/echo を参考に TypeScript のコードを書く


src/index.ts

import { Client, SpeechBuilder, Middleware } from '@line/clova-cek-sdk-nodejs';

import * as express from 'express';
const app = express();

const launchHandler = async responseHelper => {
responseHelper.setSimpleSpeech(
SpeechBuilder.createSpeechText('おはよう')
);
};

const intentHandler = async responseHelper => {
const intent = responseHelper.getIntentName();
const sessionId = responseHelper.getSessionId();

switch (intent) {
+ case 'KinokoIntent':
+ responseHelper.setSimpleSpeech(
+ SpeechBuilder.createSpeechText('きのこのこのこ元気の子')
+ );
+ break;
case 'Clova.YesIntent':
responseHelper.setSimpleSpeech(
SpeechBuilder.createSpeechText('はいはい')
);
break;
case 'Clova.NoIntent':
responseHelper.setSimpleSpeech(
SpeechBuilder.createSpeechText('いえいえ')
);
break;
default:
responseHelper.setSimpleSpeech(
SpeechBuilder.createSpeechText('なんなん')
);
break;
}
};

const sessionEndedHandler = async responseHelper => { };

- const clovaHandler = Client
+ // TypeScript だと RequestHandler 型にしないと怒られるのでとりあえず any で逃げる
+ const clovaHandler: any = Client
.configureSkill()
.onLaunchRequest(launchHandler)
.onIntentRequest(intentHandler)
.onSessionEndedRequest(sessionEndedHandler)
.handle();

const clovaMiddleware = Middleware({ applicationId: process.env.APPLICATION_ID });

app.post('/clova', clovaMiddleware, clovaHandler);

const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server running on ${port}`);
});



  • KinokoIntent のハンドリング

  • 型違いで怒られたので修正


ビルド

その前に package.json を修正


pacjage.json

{

"name": "hello-clova",
"version": "1.0.0",
"description": "",
- "main": "index.js",
+ "main": "lib/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "build": "tsc"
},
"author": "",
"license": "ISC",
"dependencies": {
"@line/clova-cek-sdk-nodejs": "^1.0.1",
"body-parser": "^1.18.3",
"express": "^4.16.3"
},
"devDependencies": {
"typescript": "^2.9.2"
}
}



  • tsconfig.json により lib/ 以下にビルドしたものが生成される


  • npm run build を使えるようにする

ビルド

$ npm run build

> hello-clova@1.0.0 build /private/tmp/hello-clova
> tsc

$ ls
lib node_modules package.json src tsconfig.json


  • こうなれば OK


トラブルシュート

$ npm run build

> /private/tmp/hello-clova
> tsc

node_modules/@line/clova-cek-sdk-nodejs/dist/types/types.d.ts:1:8 - error TS1192: Module '"/private/tmp/hello-clova/node_modules/@types/express/index"' has no default export.

1 import express from 'express';
~~~~~~~

node_modules/@line/clova-cek-sdk-nodejs/dist/types/verifierMiddleware.d.ts:1:8 - error TS1192: Module '"/private/tmp/hello-clova/node_modules/@types/express/index"' has no default export.

1 import express from 'express';
~~~~~~~

と、怒られたが、

Clova SDK の PR#2 を見て解決。

言われるがまま、以下のように tsconfig.json を修正

tsconfig.json を修正


tsconfig.json

{

"compileOnSave": false,
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "lib",
"noImplicitReturns": true,
"sourceMap": true,
+ "allowSyntheticDefaultImports": true,
"lib": ["es6"]
},
"include": [
"src/"
]
}


heroku の準備


ログイン

$ heroku login

# ID(メールアドレス) 入力
# パスワード入力


heroku app 作成

$ heroku create

# ここでリモートリポジトリが設定される


Procfile を準備


Procfile

web: node lib/index.js



環境変数を準備

# process.env.APPLICATION_ID で取得できるようになる

$ heroku config:set APPLICATION_ID="さっきメモメモしといた Extension ID"

# デプロイ後、devDependencies もインストールしたいので false にする
$ heroku config:set NPM_CONFIG_PRODUCTION=false


デプロイ後のビルドコマンド追加


package.json

{

"name": "hello-clova",
"version": "1.0.0",
"description": "",
"main": "lib/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc",
+ "heroku-postbuild": "npm run build"
},
"author": "",
"license": "ISC",
"dependencies": {
"@line/clova-cek-sdk-nodejs": "^1.0.1",
"body-parser": "^1.18.3",
"express": "^4.16.3"
},
"devDependencies": {
"typescript": "^2.9.2"
}
}



  • heroku-prebuild は heroku 上で npm install が完了したら実行される


heroku へデプロイ

$ git add Procfile package.json src tsconfig.json

$ git commit -m "Add project"
$ git push heroku master
~略~
remote: https://${HEROKU_APP_NAME}.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/${HEROKU_APP_NAME}.git
2433fb3..55d6dfc master -> master



  • remote: https://${HEROKU_APP_NAME}.herokuapp.com/ deployed to Heroku


    • こんなの出れば OK




アクセス

https://${HEROKU_APP_NAME}.herokuapp.com/ にブラウザでアクセスすると


Cannot GET /


こんな感じですかね?

できてない場合は heroku logs とかでログ見ないとだー。


CEK の サーバー設定



  • https://${HEROKU_APP_NAME}.herokuapp.com/clova を設定


    • これは index.tsPOST /clova を作ったため




最後のテスト!


まとめ

もともと heroku の知識があったため、

サンプルの JS を heroku にデプロイして Clova の繋げるまでは 18分 でできました。

その後、記事書きながら TypeScript に置き換えるのに、時間を取られました…

Clova SDK や CEK は、それなりに理解しやすかったです。

(単純に動かすだけなら簡単!!)


記事内に貼ったリンクのまとめ