スキル用プロジェクトの解説
では、第1回で利用した完成済みプロジェクトを一から作りながら解説します。ソースコードを見て処理内容が分かる方はスキップしていただいて構いません。適当な場所に新しいフォルダを作成し、ターミナルでそのフォルダにcdしておいてください。
ライブラリのインポート
ソースコードを記載する前に、まずはライブラリ(以後パッケージと呼びます)をインストールします。パッケージを利用することで、Webアプリケーションなど一から開発すると工数のかかる機能を、簡単かつシンプルに実装することができます。
また、スキルの開発に使うSDKも公式からパッケージとして配布されているので、こちらも併せてインストールしましょう。
ターミナルから以下のコマンドを実行します。
# カレントディレクトリを確認
$ pwd
/path/to/created/folder
# Node.jsプロジェクトを初期化
$ npm init -y
Wrote to /path/to/created/folder/package.json:
{...}
# 必要なパッケージをインストール
$ npm install -s @line/clova-cek-sdk-nodejs express body-parser
以下のパッケージをインストールしました。
| パッケージ | 内容 |
|---|---|
| @line/clova-cek-sdk-nodejs | LINE株式会社により提供されているNode.js版公式CEK SDK |
| express | Node.js用のWebアプリケーション・フレームワーク |
| body-parser | HTTPで渡されたリクエストの内容をあらかじめパースできるミドルウェア |
npm initでpackage.json、npm installでpackage-lock.jsonが作成されます。
またnode_modulesという名前のフォルダが作成され、パッケージと依存パッケージ(インストールしようとしているパッケージの動作のために必要なパッケージ)が格納されます。重く、またHerokuにデプロイする必要がないフォルダなので.gitignoreに記載してデプロイの対象から外しておきましょう。
.gitignoreという名前のファイルを作成し、以下のように入力します。
node_modules/
パッケージを使う準備
index.jsを作成し、インストールしたパッケージをソースコード内で利用できるよう以下の内容を追記します。
const clova = require('@line/clova-cek-sdk-nodejs');
const express = require('express');
const bodyParser = require('body-parser');
返答テンプレートの作成
次に、返答のテンプレートを作成しておきます。スキル開発においてはユーザーからヘルプの要求があった場合や、返答がなかった場合の聞き返しのために同様の応答が必要になる場面が多いため、予め定数として設定しておきます。
index.jsに以下を追記してください。
// 応答の最後に追加するテンプレート const TEMPLATE_INQUIRY = '挨拶をするか、使い方もしくは終了、と呼びかけてください。';
ハンドラーを定義する
ではリクエストを処理するためのコードを書いていきましょう。index.jsに以下を追記します。
const clovaSkillHandler = clova.Client
.configureSkill()
// スキルの起動リクエスト
.onLaunchRequest(responseHelper => {
responseHelper.setSimpleSpeech({
lang: 'ja',
type: 'PlainText',
value: `「挨拶サンプル」が起動されました。${TEMPLATE_INQUIRY}`,
});
})
// カスタムインテント or ビルトインインテント
.onIntentRequest(responseHelper => {
const intent = responseHelper.getIntentName();
let speech;
switch (intent) {
// ユーザーのインプットが挨拶だと判別された場合。第2引数はreprompt(入力が行われなかった場合の聞き返し)をするか否か。省略可。
case 'GreetingsIntent':
speech = {
lang: 'ja',
type: 'PlainText',
value: `ご挨拶していただきありがとうございます。${TEMPLATE_INQUIRY}`
}
responseHelper.setSimpleSpeech(speech)
responseHelper.setSimpleSpeech(speech, true)
// 下記でも可
/*
responseHelper.setSimpleSpeech(
clova.SpeechBuilder.createSpeechText(`ご挨拶していただきありがとうございます。${TEMPLATE_INQUIRY}`)
);
*/
break;
// ビルトインインテント。ユーザーによるインプットが使い方のリクエストと判別された場合
case 'Clova.GuideIntent':
speech = {
lang: 'ja',
type: 'PlainText',
value: TEMPLATE_INQUIRY
}
responseHelper.setSimpleSpeech(speech)
responseHelper.setSimpleSpeech(speech, true)
//});
break;
// ビルトインインテント。ユーザーによるインプットが肯定/否定/キャンセルのみであった場合
case 'Clova.YesIntent':
case 'Clova.NoIntent':
case 'Clova.CancelIntent':
speech = {
lang: 'ja',
type: 'PlainText',
value: `意図しない入力です。${TEMPLATE_INQUIRY}`
}
responseHelper.setSimpleSpeech(speech)
break;
}
})
// スキルの終了リクエスト
.onSessionEndedRequest(responseHelper => {
})
.handle();
長いので一つずつ解説します。
ハンドラーの利用準備
const clovaSkillHandler = clova.Client .configureSkill() // スキルの起動リクエスト
このコードでハンドラーを利用するための準備を行います。
リクエストの種類によって処理を分岐させる
.onLaunchRequest(responseHelper => {
// スキル起動時の処理
})
.onIntentRequest(responseHelper => {
// カスタムインテントやビルトインインテント時の処理
})
.onSessionEndedRequest(responseHelper => {
// スキル終了リクエスト時の処理
})
.handle();
configureSkillした後にこれらのコードを追加することで、渡ってきたインテントに応じて処理を分岐させることが可能になります。
結果を返却する
LaunchRequest
.onLaunchRequest(responseHelper => {
responseHelper.setSimpleSpeech({
lang: 'ja',
type: 'PlainText',
value: `「挨拶サンプル」が起動されました。${TEMPLATE_INQUIRY}`,
});
})
onLaunchRequestは「ねぇClova、○○を起動して」というようなユーザーの発話によりスキルが起動されたタイミングで呼ばれます。インテント情報もスロット情報も含まれません。
返答としてテキストの読み上げを指定したい場合は、関数responseHelper.setSimpleSpeechを利用します。langにはjaの他に、en、koも指定可能です。その場合はvalueはそれぞれ英語、韓国語である必要があります。
取り得るパラメータに関しては公式ドキュメントをご確認ください。
IntentRequest
.onIntentRequest(async responseHelper => {
const intent = responseHelper.getIntentName();
let speech;
switch (intent) {
// ユーザーのインプットが挨拶だと判別された場合。第2引数はreprompt(入力が行われなかった場合の聞き返し)をするか否か。省略可。
case 'GreetingsIntent':
speech = {
lang: 'ja',
type: 'PlainText',
value: `ご挨拶していただきありがとうございます。${TEMPLATE_INQUIRY}`
}
responseHelper.setSimpleSpeech(speech)
responseHelper.setSimpleSpeech(speech, true)
// 下記でも可
/*
responseHelper.setSimpleSpeech(
clova.SpeechBuilder.createSpeechText(`ご挨拶していただきありがとうございます。${TEMPLATE_INQUIRY}`)
);
*/
break;
// ビルトインインテント。ユーザーによるインプットが使い方のリクエストと判別された場合
case 'Clova.GuideIntent':
・
・
・
・
}
})
IntentRequestはユーザーの発話が対話モデル作成画面で作成したカスタムのインテントや、予め用意されているインテントに該当すると判断された場合に呼ばれます。
関数responseHelper.setSimpleSpeechの第二引数にtrueを指定すると、Clovaデバイスによる発話後一定時間ユーザーが何も言わなかった場合に再度呼びかけるrepromptを指定することができます。
詳しくは公式ドキュメントをご覧ください。
sessionEndedRequest
.onSessionEndedRequest(responseHelper => {
})
onSessionEndedRequestはスキルが起動し、ユーザーからの発言を待っている状態(ランプが緑に点灯)の時にユーザーから「終了して」といった明確な終了の意図の発話がされた場合に呼ばれます。onSessionEndedRequestが発生したタイミングでセッションが終了しているため返答を返しても、Clovaデバイスに発話させることはできません。
ミドルウェアを定義する
const app = new express();
// リクエストの検証を行う場合。環境変数APPLICATION_ID(値はClova Developer Center上で入力したExtension ID)が必須
const clovaMiddleware = clova.Middleware({
applicationId: process.env.APPLICATION_ID
});
app.post('/clova', clovaMiddleware, clovaSkillHandler);
// リクエストの検証を行わない
//app.post('/clova', bodyParser.json(), clovaSkillHandler);
new express()でexpressを使う準備をします。
関数app.postを呼び出すことでWebアプリケーションの処理方法を定義できるのですが、第二引数にclova.Middlewareを利用することで、リクエストが不正でないかを検証することができます。検証にはClova Developer Centerで入力したExtension IDが必要になりますので、そちらを以下のコマンドでHerokuの環境変数に追加します。
# Heroku上のアプリケーションに環境変数を追加 $ heroku config:set APPLICATION_ID='Extension ID' -a アプリ名
ミドルウェアとしてbodyParser.json()を利用すると検証を行わず全てのリクエストを処理することができますが、こちらは開発のためだけに利用し、審査への提出時には必ず署名の検証を行う必要があります。
第一引数にはエンドポイント(http://xxxxxx.herokuapp.com/以降の部分)、第三引数には先程作成したハンドラーを指定します。
HTTPリクエストの待受を開始する
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server running on ${port}`);
});
Webアプリケーションの準備ができましたので、起動します。Herokuの場合は起動するべきポートが環境変数process.env.portに格納されていますので、それを引数にapp.listenを呼び出します。第二引数は起動成功時に呼び出されるコールバックです。
これでスキル用のWebサービスの完成です。
