こんにちは。まりもです。
GoogleAppScriptを使っていい感じに返信してくれるLINEBOTを作ったので、作り方を公開します(主にソースコードを載せるだけ)
必要な環境など
・Googleアカウント(たぶんみんな持ってる)
・LINE developersアカウント(10分あれば作れます)
・PC(Windows/Macどちらでも)
作成にかかった時間
2時間
※大枠の実装1時間 + 返信用のデータ登録1時間くらい
作成の経緯・ロジックとか
諸事情で、友人とのラインのログをテキストに落としていろいろ作業しているときに思いつきました。
「2年分のLINEの発言のログをデータとして格納してやって、その手札を使えばユーザーの発言に対していい感じの返答を返すことができるbotが作れるのでは??」
って感じです。
もうすこし詳しく
友人をA、僕をBとします。
A:ラーメン食べたい B:わかる
A:でんわしよ B:いいよ
A:男の人は一生中二病だと思う B:それはある
こんな感じのなんでもない会話を記録しておいて、LINEBOTに向かって投げられた発言(strとします)と、格納されているAをすべて比べて、strと最も近いAを特定します。
特定したAに紐づくBを、LINEBOTから返してやればいい感じに返事が帰って来たふうに見えるのでは、という感じです。
上記の例では、3会話しかありませんが、実際は2年分の会話のすべてを格納します(テキストで2万行くらいでした)
LINEBOTに投げられた発言と最も近いAの特定方法
これはだいぶ迷いましたが、機械学習とかAIを実装できる気はしなかったので、レーベンシュタイン距離という考え方を使うことにしました。
レーベンシュタイン距離は、二つの文字列がどの程度異なっているかを示す距離の一種である。編集距離とも呼ばれる。具体的には、1文字の挿入・削除・置換によって、一方の文字列をもう一方の文字列に変形するのに必要な手順の最小回数として定義される。
レーベンシュタイン距離 - Wikipedia
ここではレーベンシュタイン距離の詳しい説明は省略します(数学とかそっちらへんの話になってしまうので)
いよいよ実装
BOTを作るための諸々の手続き、どこにコーディングすんの? みたいなのは説明省略します。
【LINE Botの作り方】Messaging API × GAS(Google Apps Script)でおうむ返しボットを作成する|TAKEIHO
https://www.takeiho.com/messaging-api-gas
こちらの方のブログを参考にしました。非常にわかりやすくておすすめです。
リンクを参考にGoogleAppsScriptを書くぞ! って部分まで環境を整えてからこの下を読むといいかもしれないです。
コード.gs
var channel_access_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
function doPost(e) {
var posted_json = JSON.parse(e.postData.contents);
var events = posted_json.events;
var json = JSON.parse(e.postData.contents);
var user_message = json.events[0].message.text;
var receive_message_type = json.events[0].message.type;
events.forEach(function(event) {
var ArrayMessage = ['明日が本番だから','酔ってると八方美人やめれる','焼きあごラーメン','秋の四角形みたいなやつが同時に見えた','星めっちゃ見た','なにたべるかまじでまよう','とりあえずこたつ買って電車乗っとこ','ちょっと盛った','夏終わる','しおり作りたい','くそかわいい','東京湿度高すぎ','帰ってる','後でまた連絡するね','まじ寝坊しないか不安','7時集合','美味しすぎた','たのしい','とおくね?','1分くらい待って','でんわしよ','いま家?','どへんたいだな','気が向いたらもってくる','でんぱくそわるい','こんどいこ','秋の四角形みたいなやつが同時に見えた'];
var ArrayResponse = ['気合い入れないと','常に酔ってれば勝てる','たべたい','秋の四辺形わかるの強すぎ','羨ましすぎ','ラーメンが肉か定めよう','そして夜行バス','盛りすぎ','夏らしいことやってないわ','旅行の時しおり作る派だわ','かわいい','まじで暑い','おつ','まってる','モニコするわ','早い','うらやま','いいなあ','遠いわ','まつわ','おけまる水産','家なう','ばれた','#持ってこなそう','無線LAN繋がらなさそう','いこ','秋の四辺形わかるの強すぎ'];
var minlevenshtein = levenshtein(user_message, ArrayMessage[0]);
var min_i = 0;
for(var i=1;i<ArrayMessage.length;i++){
if (levenshtein(user_message, ArrayMessage[i]) < minlevenshtein){
minlevenshtein = levenshtein(user_message, ArrayMessage[i]);
min_i = i;
}
}
var postData = {
"replyToken" :event.replyToken,
"messages" : [
{
"type" : "text",
"text" : ArrayResponse[min_i]
}
]
};
var options = {
"method" : "post",
"headers" : {
"Content-Type" : "application/json",
"Authorization" : "Bearer " + channel_access_token
},
"payload" : JSON.stringify(postData)
};
var reply = UrlFetchApp.fetch("https://api.line.me/v2/bot/message/reply", options);
});
};
function levenshtein (s1, s2) {
if (s1 == s2) {
return 0;
}
var s1_len = s1.length;
var s2_len = s2.length;
if (s1_len === 0) {
return s2_len;
}
if (s2_len === 0) {
return s1_len;
}
var split = false;
try{
split=!('0')[0];
} catch (e){
split=true;
}
if (split){
s1 = s1.split('');
s2 = s2.split('');
}
var v0 = new Array(s1_len+1);
var v1 = new Array(s1_len+1);
var s1_idx=0, s2_idx=0, cost=0;
for (s1_idx=0; s1_idx<s1_len+1; s1_idx++) {
v0[s1_idx] = s1_idx;
}
var char_s1='', char_s2='';
for (s2_idx=1; s2_idx<=s2_len; s2_idx++) {
v1[0] = s2_idx;
char_s2 = s2[s2_idx - 1];
for (s1_idx=0; s1_idx<s1_len;s1_idx++) {
char_s1 = s1[s1_idx];
cost = (char_s1 == char_s2) ? 0 : 1;
var m_min = v0[s1_idx+1] + 1;
var b = v1[s1_idx] + 1;
var c = v0[s1_idx] + cost;
if (b < m_min) {
m_min = b; }
if (c < m_min) {
m_min = c; }
v1[s1_idx+1] = m_min;
}
var v_tmp = v0;
v0 = v1;
v1 = v_tmp;
}
return v0[s1_len];
}
上記のコードのうち、2行目のトークンを書き換えてください。最低限それで動きます。
ソース上の方にある鬼みたいな配列は、発言Aと発言Bです。最終的には6000アイテムくらい入れる予定なので、配列の要素は外付けで持つように拡張する予定です(このままベタで書いてもソースが汚いだけで普通に動きます)
なお、スタンプと画像が送られて来た際の処理は未実装です。(テキスト以外が送られた処理は非常に面倒っぽかったので)
動かしてみた
格納しているデータが少ないこともあり、怪しい箇所もありますがまあまあいい感じに返信してくれてます(返信しやすいようなメッセージを送ったのもありますが)
ちなみに、アイコンがキズナアイちゃんなのは「AI返信したかった(技術が足りなくてできなかった)」という悲しい事情からです。
まとめ
機械学習もAIも使わずにレーベンシュタイン距離でいい感じの返答ができるLINEBOTを作ることができました。
LINEでの発言をLINEBOTに使うって、なんかエモさがあって楽しかったです。
最後に、今回作成したアカウントを載せておくのでよかったら友達登録してね!!