どうも。ケニー(tsujikenzo)です。このシリーズでは 「GASでGoogleChat APIを使いこなそう」 をお送りしています。今日は最終回です。
前回のおさらい
前回は、GoogleChatAPIで高度なメッセージを送信しようということで、GCPとGASの連携にチャレンジしました。
最終回は、【ハンズオン】「カスタムアプリ」でオウム返しBotを作ろう!をお届けします。
はじめに
これまでお届けしたのは、GASから一方的にメッセージを送信するアプリでした。
ここまできたら、双方向のやりとりを行うアプリも実現したいですよね。
「双方向のやりとり」とは、具体的に言うと 「スペースでBotにメンションを送ると、GASが自動的に返答を呼び出してくれる」という機能です。
ハンズオンでお送りしますので、手を動かしながらやってみましょう。
おおまかな流れ
- Step 1:onMessage(e)関数を実装する
- Step 2:ウェブアプリとしてデプロイする
- Step 3:GCPプロジェクトにデプロイIDを紐づけする
Step 1:onMessage(e)関数を実装する
双方向アプリの心臓部、それがonMessage(e)関数です。
これは、ユーザーが手動で実行する関数ではありません。ユーザーがBotにメンションを送ったときに、Googleのサーバーが自動的に呼び出してくれる、特別な「イベントハンドラ」です。
GASに慣れている方なら、スプレッドシートを開いたときに自動で実行されるonOpen()のような仕組み、と言えば分かりやすいでしょう。
オウム返しBotの基本コード
この「イベントハンドラ」として、onMessage(e)という、決まった名前の関数を用意します。
function onMessage(e) {
// ここに、応答のロジックを書いていく
}この関数の引数であるe(イベントオブジェクト)の中に、誰が、どこで、どんなメッセージを送ったか、すべての情報が詰まっています。このeの中身を正しく読み解くことこそが、双方向アプリ開発の鍵です。
イベントオブジェクトeの公式リファレンス
Google Chat APIの、公式リファレンスはこちらです。

しかし、今回作っているような、GCPの「構成」タブで設定を行うインタラクティブ(双方向)なアプリは、Googleのシステム上、より高機能な「Google Workspace アドオン」として扱われます。
そのため、われわれが受け取るイベントオブジェクトeは、「アドオン専用」の、特別な、そしてより複雑な構造をしています。(ドハマりポイント💦)
公式リファレンス:Google Workspaceアドオン – Chatイベントオブジェクト

ユーザー名を取得する方法
「アドオン イベント オブジェクト」の公式リファレンスを見ると、メッセージを送信したユーザーの情報は、イベントオブジェクトeの直下ではなく、e.chat.userという階層に格納されていることが分かります。
以下のコードで、ユーザーの表示名を取得できます。
const userName = e.chat.user.displayName;Botへのメンションを除いた純粋な本文を取得する方法
同様に、ユーザーが入力したメッセージ本文も、e.chat.messagePayload.messageという、深い階層の中にあります。
ここで便利なのが、argumentTextというプロパティです。これは、「@Bot名 こんにちは」という、元のメッセージから、Botへのメンション部分を取り除いた、純粋な本文(こんにちは)だけを返してくれます。
@Bot名 こんにちは
↓
こんにちわコードはこちらです。
const userMessage = e.chat.messagePayload.message.argumentText;応答を返す
応答を返すには、前回お届けした、API経由で新しいメッセージを投稿する方法(Chat.Spaces.Messages.create())がいいでしょう。
これは、非同期応答という手法で、時間がかかる処理(スプレッドシートの読み書きなど)を挟む場合にも有効です。
※onMessage(e)関数のreturn処理を使う、「同期応答」という手法があるようですが、ケニーは実装できませんでした。(ドハマりポイント💦)
onMessage(e) 関数の全体像はこちらです。
/**
* Google Chatからのメッセージイベントに応答し、非同期でオウム返しする関数
* @param {Object} e - Chatから送られてくるアドオン形式のイベントオブジェクト
*/
function onMessage(e) {
try {
// -----------------------------------------------------------------
// Step 1: 必要な情報をイベントオブジェクトeから取得する
// -----------------------------------------------------------------
// 応答先のスペース名とスレッド名(会話の場所)を、正確に取得する
const spaceName = e.chat.messagePayload.message.space.name;
const threadName = e.chat.messagePayload.message.thread.name;
// 送信者の名前と、メンションを除いたメッセージ本文を取得
const userName = e.chat.user.displayName;
const userMessage = e.chat.messagePayload.message.argumentText.trim();
// -----------------------------------------------------------------
// Step 2: 応答メッセージを作成し、非同期で投稿する
// -----------------------------------------------------------------
const replyText = `【オウム返し】${userName}さん、こんにちは!「${userMessage}」って言いましたね!`;
// 送信するメッセージの本体(メッセージリソースオブジェクト)を作成
const message = {
text: replyText
};
// Chat APIを直接呼び出し、新しいメッセージとして投稿する
// { threadKey: threadName } を指定することで、必ず同じスレッドに返信される
Chat.Spaces.Messages.create(message, spaceName, { threadKey: threadName });
} catch (err) {
// もし、この処理の途中でエラーが起きたら、その内容をログに記録する
// これにより、GCPのログエクスプローラでエラーの原因を追跡できる
console.error(`onMessageでエラーが発生: ${err.stack}`);
}
}Step 2:ウェブアプリとしてデプロイする
onMessage(e)関数は、外部のGoogleサーバーから呼び出されるため、われわれのGASスクリプトには、外部からアクセス可能な「住所」が必要です。
そのために、GASを「ウェブアプリ」としてデプロイ(誰でも使える状態にすること)します。
GASエディタ右上の「デプロイ」から「新しいデプロイ」をクリックします。※スクショは割愛します
種類を「ウェブアプリ」に設定します。
【超重要】 「アクセスできるユーザー」を「全員」に設定します。(Googleのサーバーからのアクセスを許可するため)
最後に「デプロイ」をクリックします。
デプロイが完了すると、「デプロイID」が表示されるので、メモしておきましょう。 
Step 3:GCPプロジェクトにデプロイIDを紐づけする
前回(メッセージ送信のみ)の記事で、Google Chat APIの構成から作成したアプリの「接続設定」の「トリガー」で、ダミーのURLを入れたことを覚えていますでしょうか。 
今回は、送信のみならず「受信」にチャレンジしますので、ここの設定をしていきます。
GCPプロジェクトは、新規で1つ作成しましょう。(トラブルを防ぐためです。前回に引き続きでもOKです)
GCPプロジェクトの「APIとサービス」から「Google Chat API」をクリックして、「構成」タブを開きます。※省略します
「接続設定」の項目で、「Apps Script」にチェックを入れて、デプロイIDを入力します。 
最下部の「Save」をクリックします。※省略します
サーバー上に設定が反映されるまで、少し時間をあけた方がよさそうです(ドハマりポイント💦)。小休憩して、いよいよ最後のGASを送信しましょう。
小休憩中なのでちなみに、トリガーに、イベントハンドラ(Chatアプリとやり取りを処理する方法)としての関数がデフォルトで入力されています。 
イベントハンドラ名は自由に変えられるようですが、オススメはしないです。
ちなみに、Step 3で作成したアプリのことを「(Google Chatの)カスタムアプリ」と呼んだりします。
Step 4:スペースからメンション付きでメッセージを送信する
まず、スペースで事前準備があります。
スペースにアプリを追加する
スペースのタイトル横の▼をクリックして、「アプリと統合」をクリックします。 
「+アプリを追加」をクリックします。

カスタムアプリを選択して、「追加」をクリックします。

スペースに、カスタムアプリが追加できました。

Botにメンション付きでメッセージを送信する
さぁ、すべての準備が整いました。スペースで、Botにメンション付きでメッセージを送信します。
Botが「【オウム返し】〇〇さん、こんにちは!「○○!」って言いましたね!」と返信してくれば、成功です! 
GASの更新作業
GASに更新があるときは、「デプロイを管理」から、ペンのアイコン(編集)をクリックしてから、「新バージョン」を選択すると、デプロイIDに変更なく、更新できます。 
補足
GCPを管理するアカウントでGCPプロジェクトを作ったけど、GASは1ユーザーとして作成する、というときは、ひと手間が必要です。
ナビゲーションメニューの「IAMと管理」から「IAM」をクリックします。
「アクセスを許可」をクリックします。
新しいプリンシパルとして、ユーザーのメールアドレスを入力して、ロール(オーナーや編集者など)を設定したら、最後に「保存」をクリックします。

まとめ
以上で、「カスタムアプリ」でオウム返しBotを作ろう!をお届けしました。
今回つくったのは、シンプルな「オウム返しBot」ですが、onMessage(e)関数の中に、スプレッドシート連携、外部API連携、そしてインタラクティブなカードメッセージといった、あなたのアイデアという名の「魂」を吹き込んでいくことで、その可能性は、無限に広がります。
写経してみて、動くことを確認したら、このブログ記事と公式リファレンスを、どうぞAIに食わせてください。生産性爆上がり間違いなしです。
あー疲れました。



