最近、Webサイトの右下に出てくるチャットボットをよく見ますよね。
本稿では以前にAutoMLで分類した飲食店のFAQをDialogflowに取り込んで精度を見てみます。
実装方針
- FAQの1つを1つのIntentに割り当てる
- Intent名は連番とする
- レスポンスはLabel名とする
データのインポートに関する注意
FAQのIntentを手動で投入してくのは骨が折れるので、インポート機能を使います。
しかし、このインポート機能がまた不便で、JSONファイルしかインポートできません。
そしてさらに不便なことに、JSONファイルを一括でアップロードする機能がありません。
仕方がないので、Agent単位でインポートする方法をとります。
AgentファイルをZIPでDLするとIntentフォルダに1Intentに対して、メタ情報と学習フレーズが別々のJSONファイルで保存されています。
なので、CSVからこの2つのJSONに変換するスクリプトを書きます。
今回は学習フレーズと回答しか考慮しないため、以下の必要最低限のフィールドのみでJSONを作成します。
No | Response | UserSays1 | UserSays2 | ... | UserSays10 |
---|---|---|---|---|---|
1 | toilet | お手洗いはどこですか | お手洗いはありますか | ... | トイレはどこ |
のような、1行1IntentのCSVデータから
{
"name": "No",
"responses": [
{
"messages": [
{
"type": "message",
"speech": [
"Response"
]
}
]
}
]
}
と
[
{
"data": [
{
"text": "UserSays1"
}
]
},
{
"data": [
{
"text": "UserSays2"
}
]
}
]
の2つのJSONファイルを作成します。
GASでJSONファイルを作成
CSVをスプレッドシートにインポートして、この記事を参考にJSONをZIPで固めて保存します。
function toIntents() {
const sheet = SpreadsheetApp.getActiveSheet();
const blobs = new Array();
for (let i = 2; i <= sheet.getLastRow(); i++) {
const name = ('000' + (i-1)).slice(-3);
// name.jsonの作成
const intent = {
"name": name,
"responses": createResponses(sheet.getRange(i, 2).getValue()),
}
const intentBlob = Utilities.newBlob(JSON.stringify(intent, null, 4),'application/json',name + '.json');
blobs.push(intentBlob);
// name_usersays_ja.jsonの作成
const userSays = createUserSays(sheet, i);
const userSaysBlob = Utilities.newBlob(JSON.stringify(userSays, null, 4),'application/json',name + '_usersays_ja.json');
blobs.push(userSaysBlob);
}
const folder = DriveApp.getFolderById('hogehoge');
const zip = Utilities.zip(blobs, 'jsons.zip');
folder.createFile(zip);
}
function createResponses(speech) {
return [
{
"messages": [
{
"type": "message",
"speech": [
speech
]
}
]
}
]
}
function createUserSays(sheet, rowNo) {
const userSays = new Array();
for (let i = 3; i <= 12; i++) {
userSays.push({
"data": [
{
"text":sheet.getRange(rowNo, i).getValue()
}
]
})
}
return userSays;
}
データのインポート
データができたら実際にインポートします。
前述しましたが、Agent単位でインポートします。
まずはAgentファイル群をZIPでダウンロードします。
歯車の設定をクリックします。
タブのExport and Importより、EXPORT AS ZIPをクリックします。
すると、Agentファイル群をZIPで手に入れることができます。
Angetフォルダの中のintentsフォルダに先ほど作成したJSONを全て格納して再びZIPで圧縮します。
├── agent.json
├── intents
│ ├── 001.json
│ ├── 001_usersays_ja.json
│ ├── 002.json
│ ├── 002_usersays_ja.json
│ ├── 003.json
│ ├── 003_usersays_ja.json
│ ├── 004.json
│ ├── 004_usersays_ja.json
│ ├── 005.json
│ ├── 005_usersays_ja.json
│ ├── 006.json
│ ├── 006_usersays_ja.json
│ ├── 007.json
│ ├── 007_usersays_ja.json
│ ├── 008.json
│ ├── 008_usersays_ja.json
│ ├── 009.json
│ ├── 009_usersays_ja.json
│ ├── 010.json
│ ├── 010_usersays_ja.json
│ ├── Default\ Fallback\ Intent.json
│ ├── Default\ Welcome\ Intent.json
│ └── Default\ Welcome\ Intent_usersays_ja.json
└── package.json
再び圧縮したZIPをRESTOREします。
Intentsを見てみると、無事取り込めたことが確認できると思います。
試しに、学習フレーズそのままで話しかけてみると、無事返ってきました!
しかし、学習フレーズには存在せずAutoMLでは精度を出してくれた「ニコチン最高!」を与えてみると、残念ながらFallback Intentに落ちてしまいました。
終わりに
エクセルで管理できるような単純な一問一答FAQであれば、簡単に取り込むことができました。
ただし、一括で取り込むのが超メンドクサイ...Googleさん、もう少しどうにかなりませんか?
もっとスマートな取り込み方法があれば教えてください。
また、FAQは色々な聞き方があるので、学習フレーズを全てを網羅するのは難しいですよね。少しでもフレーズから外れてしまうと、Fallback Intentに落ちてしまいます。未知のワードに関しては、AutoMLよりも弱いかも?
そこで、以前記事にした**構文を分割することで、1Intentで全てのFAQを対応してしまおう!**という構成に落ち着きました。