Clova CEKでのスキル開発の始め方〜Node.jsで開発スタート編〜
こんにちは、n0bisukeです。
#linebootawards
関連でハンズオンをやる機会が増えそうなので学習メモがてら、前回に引き続きClovaの開発チュートリアルを書いていきます。
Node.jsとClovaの連携をとりあえずやりたいって人向けです。
Clovaってなんぞやって人はこちらの記事を先に読んでみてください。
いわゆるClovaのAPIのことをCEKと呼ぶんですよ〜
作るもの
のびすけ「秋葉原のカレー屋さん教えて」
Clova「秋葉原のオススメのカレー屋は ぺらぺらぺら」
これを作ってみます。完成はこんなイメージです。
環境
- Clova Friends Mini (サリー)
- Node.js v10.6.0
- Google Chrome / macOS Sierra v10.12
使い始めの申請
こちらの記事を参照して、利用開始できる状態にしましょう。
対話モデルの作成
Clova Developer Centerにアクセスします。
作成中スキルの一覧が表示されます。
作成対象となるスキル名の対話モデル
の修正
を選択します。
すると別ウィンドウが開き、対話モデルの編集画面になります。
インテントとスロット
インテントとスロットを設定していきます。
個人的にはインテントとスロットの概念を理解すればあとはBOT開発などとそこまで変わらないような印象があります。
説明はあってるのか不安なので、スマートスピーカー開発に慣れてる人が見て変だったら教えてください笑
公式ドキュメントのこの辺を見ると詳しく載っています。
スロット
スロットはスキル内で扱う名詞情報です。
今回の「秋葉原のカレー屋さん教えて」という発話を認識させる為に
秋葉原という名詞(スロット)を登録しましょう。
また、その名詞(スロット)はどういう属性かという上位概念をスロットタイプとして設定します。
では実際に
左側のメニューにカスタムスロットタイプ
という項目があるので、そこの+ボタン
を押します。
ここでスロットタイプのタイトルを決めますが、秋葉原は駅名や地名なので場所にちなんだタイトルが良さそうです。ここではarea
(エリア)としました。
作成を押すと、areaというスロットタイプが作成されます。
僕みたいに覚えにくい人はスロットタイプ=単語群
だと思えば良いと思います。
次にスロット登録です。
スロットの新たな代表語を入力
の箇所に秋葉原
と入力し、同義語の箇所に読み方や別名を入力します。こうすることであきば
などの名称でも認識してくれるようになります。
秋葉原もカレー屋は多いですがカレーと言えば神保町や神田周辺もかなり多いのでareaに神保町と神田も追加しておきました。重要情報(謎)
最後に保存
を押してスロットはOKです。個人的には難所50%クリアです。
インテント
インテントは会話や命令の種類です。
今回の「秋葉原のカレー屋さん教えて」はカレー情報の検索だと思うので
CurreySearchIntent(カレーサーチ)を作ってみます。
メニュー左のカスタムインテント
箇所の+ボタン
を選択し、インテント名を入力して進みます。
フォーム下部のスロットリスト
からこのインテントで利用するスロットの登録をします。
先ほど作成したarea
を登録しましょう。
次にサンプル発話リスト
箇所に例文を入れていきます。
先ほどから何回も出ている「秋葉原のカレー屋さん教えて」をここに入力します。
さらに秋葉原
の部分が先ほど登録したスロット部分になるので、この文章のここがスロットだよということを登録してあげます。
秋葉原
をドラッグするとスロット登録が出来るフォームが出てくるのでそこでarea
を選択しましょう。
ここは操作が難しい印象なので↓のキャプチャGIF参照で!
完成したら保存しましょう。
対話モデルのビルド
ここまで来たら左上のビルド
ボタンを押してひとまず完了です。
ここ、けっこう時間かかります。
体感5~10分程度。
ただ待つのもしんどいので次の準備にかかりましょう。
Node.jsの環境準備
お待たせしました。コード書いていきましょう。
Node.jsのSDKがあるのでこちらを使っていきます。
Node.js以外にも現時点でSwift/Kotlin/ElixirのSDKが出ています。
Node.jsのインストールがまだな方はこちらの記事をみてインストールしてみましょう。
ちなみにNode.jsは公式サイトからではなくnodebrew経由でインストールする形にした方が後々便利です。僕のオススメは以下の記事にあるnodebrew経由でのインストールになります。
ターミナル操作が不安な方はこちらの記事を先に見ておきましょう。
準備
以下のコマンドで進めていきます。 フォルダ作成と準備です。
$ mkdir clova_curry
$ cd clova_curry
$ npm init -y
SDKをnpm経由でインストールします。expressとbody-parserも利用します。
$ npm i @line/clova-cek-sdk-nodejs express body-parser
現時点ではnode_modules
,package-lock.json
,package.json
のファイルがある状態ですね。
$ ls
node_modules package-lock.json package.json
コードを書いていく
app.js
というファイルを作成して以下のコードを記述します。
また、スキルの基本情報を登録した際のExtention ID
を利用するので確認しておきましょう。
公式のサンプルよりもシンプルにしています。
const clova = require('@line/clova-cek-sdk-nodejs');
const express = require('express');
const clovaSkillHandler = clova.Client
.configureSkill()
//起動時に喋る
.onLaunchRequest(responseHelper => {
responseHelper.setSimpleSpeech({
lang: 'ja',
type: 'PlainText',
value: 'カレー屋さんを探します。',
});
})
//ユーザーからの発話が来たら反応する箇所
.onIntentRequest(async responseHelper => {
const intent = responseHelper.getIntentName();
const sessionId = responseHelper.getSessionId();
console.log('Intent:' + intent);
})
//終了時
.onSessionEndedRequest(responseHelper => {
const sessionId = responseHelper.getSessionId();
})
.handle();
const app = new express();
const port = process.env.PORT || 3000;
//リクエストの検証を行う場合。環境変数APPLICATION_ID(値はClova Developer Center上で入力したExtension ID)が必須
const clovaMiddleware = clova.Middleware({applicationId: 'YOUR_EXTENSION_ID'});
app.post('/clova', clovaMiddleware, clovaSkillHandler);
app.listen(port, () => console.log(`Server running on ${port}`));
起動
記述出来たら
$ node app.js
Server running on 3000
で起動です。エラーがなければとりあえずOKです。
ngrokでホスティングせずに疎通確認
ngrokというトンネリングツールを使ってローカル開発が出来るようにしましょう。
LINE BOTの開発でも同様ですが、通常はHTTPS対応したサーバーにプログラムをホスティングしてClovaと通信させます。
HTTPS対応したサーバーを用意するのは骨が折れるのとホスティングして失敗するとエラー修正が大変なので、ローカル開発で最初は挙動確認するのが個人的にはおすすめです。
ngrokを使うことでローカル環境をホスティング環境のようにエミュレート出来るイメージです。
$ npm i -g ngrok
これでインストール完了です。
以下のコマンドで利用しますが、ngrokがターミナル占有してしまうので、Node.jsを起動するターミナルとは別で立ち上げましょう。
$ ngrok http 3000
こんな雰囲気。右がngrok、左がNode.jsです。
ngrokを起動すると
Forwarding https://xxxxxxx.ngrok.io -> localhost:3000
といった項目が表示されます。
このhttps://xxxxxxx.ngrok.io
に/clova
を追加したアドレスをClovaのサーバー設定のExtensionサーバーのURL
に記載して保存しましょう。
https://xxxxxxx.ngrok.io/clova
となります。
xxxxxx
の箇所はngrokを再起動すると変わってしまうのでその際は再度サーバー設定を更新してください。
これでClovaに話しかけると手元(ローカル環境)のNode.jsまでリクエストが来ます。
テスターでテスト
直接話しかけても良いのですが、テスターを使ってみましょう。
対話モデルのダッシュボードに戻ります。
たぶんビルドは完了してますよね。
テスト
を選択し、ユーザーのサンプル発話をテスト
の箇所に「秋葉原のカレー屋を教えて」と入力しテストボタン
押しましょう。
Node.jsを起動させているターミナル側で
Intent:CurreySearchIntent
と表示されていればOKです。
疎通確認が出来ました!
コードでいうとonIntentRequest()
の箇所までリクエストが通ってることになります。
.onIntentRequest(async responseHelper => {
const intent = responseHelper.getIntentName();
const sessionId = responseHelper.getSessionId();
console.log('Intent:' + intent); //←ここが反応した
})
エラーが出る場合
Error: Invalid application id: ~~~
などのエラーが出た人はapp.js
内のExtension IDの設定を忘れている可能性が高いので再度チェックしてみましょう。
スロット情報も取得してみる
app.js
のonIntentRequest()
の箇所をまるっと差し替えてみましょう。
//ユーザーからの発話が来たら反応する箇所
.onIntentRequest(async responseHelper => {
const intent = responseHelper.getIntentName();
const sessionId = responseHelper.getSessionId();
console.log('Intent:' + intent);
if(intent === 'CurreySearchIntent'){
const slots = responseHelper.getSlots();
console.log(slots); //←ここでスロット(今回の場合エリア名)が反応
}
})
Node.jsを再起動して確認してみます。
テスターでは秋葉原のカレー情報教えて
、神保町のカレー情報教えて
、上野のカレー情報教えて
を順番に実行してみます。
$ node app.js
Server running on 3000
Intent:CurreySearchIntent
{ area: '秋葉原' } //←秋葉原のカレー情報教えて
Intent:CurreySearchIntent
{ area: '神保町' } //←神保町のカレー情報教えて
Intent:CurreySearchIntent
{} //←上野のカレー情報教えて
先ほどのスロット名登録の際に、秋葉原
、神保町
、神田
を登録してましたが、上野
は登録してなかったので「上野のカレー情報教えて」だと空になります。
Clovaにカレー屋情報をしゃべらせる
最後です!
先ほど同様にapp.js
のonIntentRequest()
の箇所をまるっと差し替えてみましょう。
.onIntentRequest(async responseHelper => {
const intent = responseHelper.getIntentName();
const sessionId = responseHelper.getSessionId();
console.log('Intent:' + intent);
if(intent === 'CurreySearchIntent'){
const slots = responseHelper.getSlots();
console.log(slots);
//デフォルトのスピーチ内容を記載 - 該当スロットがない場合をデフォルト設定
let speech = {
lang: 'ja',
type: 'PlainText',
value: `まだ登録されていないエリアです。`
}
if(slots.area === '秋葉原'){
speech.value = `${slots.area}のオススメのカレー屋は フジヤマドラゴンカレー です。`;
}else if(slots.area === '神保町'){
speech.value = `${slots.area}のオススメのカレー屋は 共栄堂 です。`;
}else if(slots.area === '神田'){
//神田のカレー情報検索
//何か自分で書いてみましょう。
}
responseHelper.setSimpleSpeech(speech);
responseHelper.setSimpleSpeech(speech, true);
}
})
slots.area
にエリア情報が入っているので、あとはif文で判定して喋らせる内容を変更していきます。
最後のresponseHelper.setSimpleSpeech()
を呼ぶことでClovaが喋ってくれます。
実機テスト
Node.jsのサーバーを再起動して試してみましょう。
起動する際は、{ウェイクワード} -> {スキル名}を起動してとなります。
- ウェイクワード: Clovaの呼び名
- スキル名: 基本情報に登録したスキル名
その後、設定したインテントを発話しましょう。
ということで、人によって違うのですが僕の場合はねぇ、Clova
がウェイクワードになっていて、今回はカレー情報
というスキル名でした。
のびすけ: 「ねぇクローバ」
Clova: 「ポンっ(LEDが緑色に光る)」
のびすけ: 「カレー情報を起動して」
Clova: 「カレー屋さんを探します。」 (← Node.jsで記述している)
Clova: 「ポンっ(LEDが緑色に光る)」
のびすけ:「秋葉原のカレー屋さんを教えて」
Clova: 「秋葉原のオススメのカレー屋はフジヤマドラゴンカレーです。」 (← Node.jsで記述している)
という感じの使い方になります。
動画もどうぞ
まとめ
こんな感じでとりあえず試す手順を紹介しました。
ホスティングもnowやherokuを使うと簡単に出来るので立花さんのハンズオン資料を参照して理解を深めましょう!
ホスティングに関しても余裕があれば追記したいと思います。