Google Apps ScriptとSlackボットを連携してQ&Aボットを開発する話
-
2024年8月20日
こんにちは、クライアントエンジニアのMです。
今回は、SlackボットにGoogle Apps Scriptを連携させて、キーワードに自動で返信するQ&Aボットを開発したいと思います。具体的には、ユーザーのメッセージにGoogle スプレッドシートに記載されたキーワードが含まれている場合、そのキーワードに対応する回答を送信する機能と、ユーザーのIDと名前、そしてボットが質問に対応できたかどうかをチェックする機能も実装します。
まず、Google Apps Scriptについて説明します。Google Apps Scriptは、Googleが提供するスクリプトプラットフォームです。このツールを使うことで、繰り返し実行を行うなど、ちょっとした業務の自動化が可能です。サーバーレスで動作するため、サーバーを持たなくてもサーバーのような処理を実行できるのも特徴です。また、JavaScriptを基にしているので、JavaScriptに慣れている人なら使いやすいという点もあります。
このように、Google Apps ScriptとSlackボットを連携させることで、サーバーなしで簡単に開発できるのが大きなメリットです。
それではさっそく開発していきましょう!
Google Sheet作成

まず、Google Sheetsを作成しましょう。 シートの名前は何でも構いません。 今回の開発では、シートの「Keyword」列にあるキーワードが文中に含まれている場合に、「Answer」列の回答を送信するため、上の画像のように「Keyword」と「Answer」の2つの列を作成します。 また、下記の画像のようにユーザーの質問と応答の記録をするために、もう1つシートを追加します。 私の場合は、「KeywordList」がキーワード管理用のシートで、「UserQuestions」がユーザーの質問記入用のシートです。


「UserQuestions」シートでは、質問リスト、質問者の名前、質問に対応したかどうかを記録するために、列を分けて作成します。
ボット作成
次に、ボットを追加しましょう。以下のリンクからボットを追加してください。
https://api.slack.com/apps?new_app=1
「Create New App」ボタンをクリックした後、「From scratch」を選択し、アプリの名前と使うワークスペースを入力してください。
ボットの名前は、お好きな名前にしてください。
私の場合は「KeywordBot」という名前で追加しました。

成功すると、こうしてボットが追加されます。

その後、ボットをクリックし、Incoming Webhooksを選択して、OffをOnに切り替えてください。
SlackのIncoming Webhooksは、外部アプリケーションがSlackチャンネルにメッセージを送信できるようにする設定です。

次に、画像のように「Add New Webhook to Workspace」をクリックして、自分のワークスペースにボットを追加します。

そうすると、このようにWebhook URLが表示されます。Slackにメッセージを送信する際に必要になるので、コピーしておきます。後ほどGoogle Apps Scriptを実装するときに使います。
google app script作成

次に、Google Sheetsでアプリスクリプトを作成してみましょう。 シートの「拡張機能」から「アプリ スクリプト」をクリックします。
すると、Google Apps Scriptが作成されます。
まずはコード全体を書いておきます。
const SLACK_HOOK_URL = "ここに自分のSlackのWebhook URLを貼り付けます。";
const SHEET_URL = "ここに自分のシートのリンクを貼り付けます。
";
function doPost(e) {
// 通信確認
const params = JSON.parse(e.postData.getDataAsString());
if ('challenge' in params) {
return ContentService.createTextOutput(params.challenge);
}
//ボットのメッセージに反応しないように
if ('subtype' in params.event) {
return;
}
requestProcess(params);
}
function vlookup(value, sheet, column) {
const lastRow = sheet.getLastRow();
let returnValue = "";
let keywordFound = false;
let firstKeywordFound = false;
for (let i = 2; i <= lastRow; i++) {
const questions = sheet.getRange(i, 1).getValue().toLowerCase().split('/');
let answer = "";
let keyword = "";
for (const q of questions) {
if (value.toLowerCase().includes(q)) {
answer = sheet.getRange(i, column).getValue();
keyword += q + " ";
}
}
if (answer === "") {
continue;
}
if (!firstKeywordFound) {
returnValue += "答えが見つかりました。(^-^)\n";
firstKeywordFound = true;
}
returnValue += `キーワード:${keyword} \n${answer}\n`;
keywordFound = true;
}
return { answer: returnValue, keywordFound };
}
function postMessage(message) {
const options = {
"method": "post",
"contentType": "application/json",
"payload": JSON.stringify({
"text": message,
"link_names": 1
})
};
UrlFetchApp.fetch(SLACK_HOOK_URL, options);
}
function requestProcess(params) {
let contents = "";
const spreadsheet = SpreadsheetApp.openByUrl(SHEET_URL);
const keywordSheet = spreadsheet.getSheetByName("KeywordList");
const questionSheet = spreadsheet.getSheetByName("UserQuestions");
const userId = params.event.user;
const question = params.event.text;
const { answer, keywordFound } = vlookup(question, keywordSheet, 2);
if (keywordFound) {
contents = `<@${userId}>\n${answer}`;
} else {
contents = `<@${userId}>\nキーワードが見つかりませんでした。(._.)`;
}
postMessage(contents);
const lastRow = questionSheet.getLastRow() + 1;
questionSheet.getRange(lastRow, 1).setValue(question);
questionSheet.getRange(lastRow, 2).setValue(userId);
if (keywordFound) {
questionSheet.getRange(lastRow, 3).setValue('o');
}
else{
questionSheet.getRange(lastRow, 3).setValue('x');
}
}
- doPost(e)
- この関数はweb hook requestを処理します。主にSlackからPOSTリクエストを受け取ったときに呼び出されます。
- Slackイベントのsubtypeが含まれている場合(例えば、ボットのメッセージなど)は、処理せずに終了します。
- processRequest(params)を呼び出して、Slackメッセージに関連する処理を行います。
- vlookup(value, sheet, column)
- この関数は、指定されたvalueを使用してスプレッドシート(sheet)で検索を行い、一致する項目の回答を返します。
- 一致する質問が見つかると、その行の回答を取得しメッセージを作成し、返します。
- postMessage(message)
- この関数はSlackにメッセージを送信します。
- processRequest(params)
- この関数はSlackイベントを処理し、ユーザーの質問に対する応答を作成し、ユーザーの質問をスプレッドシートに記録します。
デプロイ
次は、コードをデプロイして適用してみましょう。

Google Apps Scriptで、右上にある「デプロイ」または「展開」ボタンをクリックします。

タイプ選択で「Webアプリ」を選択します。

上の画像のように設定して「デプロイ」または「展開」を押します。

この画面が表示されたら、WebアプリのURLをコピーしておきます。

次に、ボットの設定に戻り、「Event Subscriptions」項目に移動して、Request URLにWebアプリのURLを貼り付けます。

そのあとslackチャンネルにボットを招待するとこれで準備が完了です。
動作確認

ボットにシートに記入されているキーワードを入力すると、Answer列に事前に保存された回答が返されます。

また、シートに記載されていないキーワードを入力した場合には、「キーワードが見つかりませんでした」と返されます。

また、ユーザーの質問を記録するシートには、以下のようにユーザーのID、質問、質問に対応したかどうかを表示します。
最後に
こうして、今回はQ&AボットをGoogle Apps Scriptと連携させて開発しました。この開発を応用すると、たとえば以下のような機能も追加できます。
-
-
- 拡張機能として、質問がある程度溜まるとユーザーにリマインドする機能
- 特定のキーワードに対して複数の回答をする機能
-
このようにGoogle Apps ScriptとSlackボットを連携させることで、さらに多様で面白い機能を作ることができるので、一度挑戦してみるのも良いと思います。