はじめに
先週、cybozu developer networkにて、
LINE Clovaとkintoneを使って在庫管理をしよう!
という LINEのスマートスピーカー Clova と kintone を連携した記事を公開しました!
上の記事ではそれぞれのSDKを使ってかなりぱぱっと作ったのですが、
元々SDKなしで実装していたので、この記事ではSDKは使わずLambdaのcallbackで実装したものを紹介します!
(kintoneもSDKではなくrequestモジュールでやります)
作る連携シナリオ
流石にdevnet記事と同じ内容だと飽きちゃうので、今回は、
- Clovaに話しかけてkintoneのアプリ内を検索
- もし該当するレコードが1件あれば、そのレコードの内容を話す
- もし該当するレコードがなければ、「ないよ」と話す
- もし該当するレコードが複数あれば、「複数あるよ」と話す
って感じに作ってみました。超シンプルですね!( ̄ー ̄)
kintoneの設定
アプリの設定についてです!
今回はアプリストアにある「FAQ」を利用します!
そして、フィールドコードが初期値のままだと扱いづらいので、
それぞれ、
フィールド名 | フィールドコード |
---|---|
質問 | question |
回答 | answer |
とします。
あとは APIトークン (権限:取得のみ) を発行してkintone側の準備は完了です!
LINE Clovaの設定
かなり設定数が多いのでちょっと大変ですが、細かいところは上のdevnetの記事をご覧ください!
→ devnetの記事は超丁寧に書いたつもりです (^o^)
大事なところとしては、
- 呼び出し名 を設定 (これは当然)
-
ExtensionサーバーのURL
- AWS API GatewayのURLを記述してください
-
対話モデル (スピーカーの対話モデル)
- スロット (インテントの設定より先にこちらをやると楽です!)
- インテント
などがあります!
スロット
とりあえずで3種類単語を用意して、すべて1つのスロット(SearchVal)に格納されるようにしています。
インテント
実際にClovaに向けて発言しそうなサンプルを記述しました。
AWS の設定
中間サーバーとしてAWSのLambda (と API Gateway) を利用します。
こちらも上記のdevnet記事内で説明しているので細かい設定は割愛します。
API Gatewayの設定
認証をオープンにする or CORS設定をする必要があるかと思います!
※ CORSについては こちら に説明があります!
Lambda関数の作成
プログラムは Node.js で記述します!
Nodeのバージョンは 8.10 としてください!
→ async/await を利用します
コードの詳細は次へ
コード
Lambda関数にのせるNode.jsのコードです!
こちらのコードはGitHubに置いてあります。
httpリクエストのためにrequest-promiseモジュールを利用したので、
- request
- request-promise
をnpmでインストールしてください m(_ _)m
const request = require('request-promise');
// kintoneから該当するレコードの件数を返す処理
const getkintone = val => {
// kintone用パラメータ
const DOMAIN = '<domain>'; // sample.cybozu.com
const URL = 'https://' + DOMAIN + '/k/v1/records.json';
const APP_ID = '<app ID>';
const API_TOKEN = '<API Token>';
const headers = { 'X-Cybozu-API-Token': API_TOKEN };
// 発話した単語をkintoneの文字列複数行フィールドでLike検索
const params = {
app: APP_ID,
query: 'question like "' + val + '"',
totalCount: true,
};
const options = {
url: URL,
method: 'GET',
headers: headers,
'Content-Type': 'application/json',
json: params,
};
let text;
// 該当するレコードを取得
return request(options)
.then(resp => {
switch (resp.records.length) {
case 0:
text = val + 'に該当するレコードはありませんでした。';
break;
case 1:
text = resp.records[0].answer.value;
break;
default:
text = val + 'に該当するレコードが' + resp.totalCount + '件ありました!';
break;
}
return text;
})
.catch(err => {
console.log(err);
});
};
// Clovaに返す処理
const setClova = async (text, bool, callback) => {
// Clovaに返すJSON
const body = {
version: '1.0',
sessionAttributes: {},
response: {
outputSpeech: {
type: 'SimpleSpeech',
values: {
type: 'PlainText',
lang: 'ja',
value: text,
},
},
card: {},
directives: [],
shouldEndSession: bool,
},
};
const res = {
statusCode: 200,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
body: JSON.stringify(body),
};
callback(null, res);
};
exports.handler = async (event, conetext, callback) => {
const req = JSON.parse(event.body).request;
let text, word, val;
// ユーザのアクションによって処理を振り分ける
switch (req.type) {
case 'LaunchRequest':
text = 'kintoneで何を検索したいですか?';
break;
case 'SessionEndedRequest':
text = 'さようなら!';
break;
case 'IntentRequest':
// スロットの中身を格納
word = req.intent.slots;
// キーワードがわからなかった場合
if (!word) {
text = 'すみません。その言葉はまだ理解できません。';
break;
}
// スロット内のキーワードが認識できていれば
val = word.SearchVal.value;
text = await getkintone(val);
setClova(text, true, callback);
break;
default:
text = 'kintoneで調べたい単語を教えてください';
break;
}
// 対話を続けるので false を返す
setClova(text, false, callback);
};
プチ解説
コードについてちょっとだけ解説します!
kintone からレコード取得
「発話されたキーワード(val) → kintone側の質問フィールド(question)をlike検索」
するような処理をクエリに追加してレコードの取得をしています。
const params = {
app: APP_ID,
query: 'question like "' + val + '"',
totalCount: true,
};
そして、取得したレコードが、
- 0 の場合 → 該当するレコードがなかった旨を返す
- 1 の場合 → そのレコード内の回答フィールド(answer)の値を返す
- 1以上の場合 → 複数該当するレコードがあった旨を返す
と分けて処理してみました!
let text;
// 該当するレコードを取得
return request(options)
.then(resp => {
switch (resp.records.length) {
case 0:
text = val + 'に該当するレコードはありませんでした。';
break;
case 1:
text = resp.records[0].answer.value;
break;
default:
text = val + 'に該当するレコードが' + resp.totalCount + '件ありました!';
break;
}
return text;
})
.catch(err => {
console.log(err);
});
※ エラー処理はかなーり雑です。。
※ async/await を使うためにプロミスを返すようにしています。
Clovaに発話させる処理
ここの部分は、
AWS LambdaでLINE Clovaのスキルを作成する
を参考にさせていただきました!
Lambdaのイベントハンドラー
Clovaが受け取ったユーザーの発話情報は、
exports.handler = async (event, conetext, callback) => {
のeventの中に格納されています。そのため、このeventの中の情報を取得して
分岐処理をさせています。
おわりに
ということで、
ClovaとkintoneをSDKなしで連携してみました!!
思ったより難しくはなかったですが、やはりSDKを使わないと設定部分の記述量が多くなりますね。。
それでは!≧(+・` ཀ・´)≦