20
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-07-18

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. 対話モデル

対話モデル

custom-extension.png
  • カスタムインテントには 「KinokoIntent」を1個追加
  • サンプル発話にはとりあえず「きのこ」と「キノコ」を設定

テスト

custom-extension-tet.png
  • サーバーの設定はしてないので、応答はありません。

スキルの実装側を作成

基本的に 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 の サーバー設定

cek-server-config.png
  • https://${HEROKU_APP_NAME}.herokuapp.com/clova を設定
    • これは index.tsPOST /clova を作ったため

最後のテスト!

result.png

まとめ

もともと heroku の知識があったため、
サンプルの JS を heroku にデプロイして Clova の繋げるまでは 18分 でできました。

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

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

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

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

20
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?