この記事は最終更新日から1年以上が経過しています。
@programming
投稿日 2020/2/4
更新日 2020/2/19 ✏
Node.jsでチャットボット
Node.jsでチャットボットを作る方法です。 以下で紹介するサンプルでは、チャットボットにテキトーに機械学習 (multi-label classification) させて、ユーザからの質問に近い情報を返すプログラムです。 サンプルコードはローカルだけで完結しています。
目次:
前提
- node.js バージョン: v8.11.3
- limdunpmモジュールを利用
サンプルコード
以下のサンプルコードはゴミの分別をアドバイスするチャットボットです。 ユーザから入力されたゴミの種類を元にゴミの出し方を出力します。
/**
* multilabel-classification-example.js
*
* 使用例:
* $ node multilabel-classification-example.js
*/
// multi-label classification対応のマシンラーニングモジュール limdu をインポート
const limdu = require("limdu");
// ユーザ入力をインタラクティブに受け付けるため
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
//
// 篩(ふるい)をセットアップ
//
const MyWinnow = limdu.classifiers.Winnow.bind(0, {
retrain_count: 10
});
//
// 分別機能をセットアップ
//
const intentClassifier = new limdu.classifiers.multilabel.BinaryRelevance({
binaryClassifierType: MyWinnow
});
//
// トレーニング
// NOTE: 2gramに分かち書きしてトレーニングしてみた
//
intentClassifier.trainBatch([{
input: create2gramInput("空き缶、空き瓶、ペットボトル、新聞紙、雑誌、ダンボール(段ボール)"),
output: "「資源ごみ」としてお出しください(空き缶、空き瓶、ペットボトル、新聞紙、雑誌、ダンボール(段ボール)など)"
}, {
input: create2gramInput("生ごみ、アルミホイル、貝がら、衣類、布類 汚れた紙など 木製品・木材、製品プラスチック、ゴム・革・ビニール製品"),
output: "「燃やせるごみ」としてお出しください(生ごみ、アルミホイル、貝がら、衣類、布類 汚れた紙など 木製品・木材、製品プラスチック、ゴム・革・ビニール製品など)"
}, ]);
//
// ユーザからの入力を受付
//
quest();
function quest() {
rl.question('ごみの出し方をアドバイスします。どんなごみを捨てますか?(例: ペットボトル) ', (answer) => {
//
// 分別実施
// NOTE: ユーザの入力値を2gramに分かち書きして投入
//
const input2gram = create2gramInput(answer);
const result = intentClassifier.classify(input2gram);
if (result.length >= 1) {
console.log("回答: " + result[0]); // e.g."「資源ごみ」としてお出しください(空き缶、空き瓶、ペットボトル、新聞紙、雑誌、ダンボール(段ボール)など)"
} else {
console.log(`回答: ごめんなさい、"${answer}" の出し方は分かりません。`);
}
// rl.close();
quest(); // 再帰質問
});
}
/**
* 入力された文章を2gram分かち書きし、
* { "xx": 1, ... } なフォーマットのオブジェクトを返します。
*
* @param {String} e.g. "空き缶、空き瓶、ペットボトル、新聞紙、雑誌、ダンボール(段ボール)"
* @return {Object} e.g. { '空き': 1,
* 'き缶': 1,
* 'き瓶': 1,
* 'ペッ': 1,
* 'ット': 1,
* 'トボ': 1,
* 'ボト': 1,
* 'トル': 1,
* '新聞': 1,
* '聞紙': 1,
* '雑誌': 1,
* 'ダン': 1,
* 'ンボ': 1,
* 'ボー': 1,
* 'ール': 1,
* '段ボ': 1 }
*/
function create2gramInput(s) {
const ret = {};
const arr = s.split("");
for (let len = arr.length, i = 0; i < len; i++) {
const c0 = arr[i]; // 2gramの1文字目
const c1 = arr[i + 1]; // 2gramの2文字目
// 1文字目or2文字目のどちらかに記号や区切り文字が入ってれば無視
if (shouldIgnore(c0) || shouldIgnore(c1)) continue;
ret[c0 + c1] = 1;
}
return ret;
// 記号や区切りチェック
function shouldIgnore(c) {
if (!c) return true;
return / | |,|、|\.|。|・|:|:|\(|\)/.test(c);
}
}
NOTE:上記コードの「トレーニング」と「分析」の処理では文章を2gram化し日本語マッチの精度を上げています。
実行例
$ node multilabel-classification-example.js
ごみの出し方をアドバイスします。どんなごみを捨てますか?(例: ペットボトル) ペットボトル
回答: 「資源ごみ」としてお出しください(空き缶、空き瓶、ペットボトル、新聞紙、雑誌、ダンボール(段ボール)など)
ごみの出し方をアドバイスします。どんなごみを捨てますか?(例: ペットボトル) 生ごみ
回答: 「燃やせるごみ」としてお出しください(生ごみ、アルミホイル、貝がら、衣類、布類 汚れた紙など 木製品・木材、製品プラスチック、ゴム・革・ビニール製品など)
ごみの出し方をアドバイスします。どんなごみを捨てますか?(例: ペットボトル) あああ
回答: ごめんなさい、"あああ" の出し方は分かりません。
以上です。