Gemini 対応の Google Chat アプリを作成する

1. はじめに

Gemini 対応の Google Chat アプリとは

Gemini 対応の Google Chat アプリでは、次のことができます。

  • サービスやリソースを Google Chat に取り入れることができるため、ユーザーは会話から離れることなくすばやく情報を取得したり、対処したりできます。
  • 生成 AI モデル Gemini と統合することで、特定の時間にテキストや画像などのデータを作成または検索し、ワークフローを効率化できます。

Google Chat アプリを Gemini と統合する理由

Gemini などの生成 AI モデルの一般的なユースケースは、次のカテゴリに分類されます。

  • コンテンツの作成と改善。マーケティング コピーの作成、ソーシャル メディア投稿の作成、リアルな画像の作成、音楽の制作、動画コンテンツの作成を支援します。
  • データ検索。高い精度と速度で、非構造化ナレッジベースから重要な分析情報を抽出したり、長いテキストを要約したり、コンテンツを分類したり、言語を翻訳したりできます。
  • 会話。自然で有益かつ創造的な会話を行います。

Google Chat の使い慣れたインターフェースにこうした機能を直接統合できるため、ユーザーのエクスペリエンスと生産性を向上させたいと考えている企業にとって大きなチャンスとなります。

前提条件

構築内容

この Codelab では、前のセクションで紹介した 3 つのユースケースに対応する、3 つの Gemini 対応 Google Chat アプリを作成します。

問題管理アプリ(コンテンツの作成と改善)

このアプリでは、次のことができます。

  • 基本的な操作、アプリホーム、アプリ認証を使用して、問題の作成から解決までを管理します。
  • メッセージをモニタリングし、イベントとアクセサリ ウィジェットでインクルーシビティ サポートを提供します。

Gemini を使用すると、次のことができます。

  • メッセージの履歴と問題の詳細に基づいて問題レポートを生成します。
  • メッセージ内の差別的な言葉を、ゲート付きのプロンプトで分類します。

使用される主なテクノロジーは、Vertex AI、Gemini、Apps Script、Google Workspace API(Admin、Chat、Docs、Events)です。

22efdecff4601417.png

2d127c63518673b2.png

9aea694937f2f3ed.png

このアプリは、Gemini を使用して自然言語で質問を理解して回答し、非構造化データからソース参照を返します。

使用される主なテクノロジーは、Dialogflow CX データストア エージェント、Dialogflow CX Webhook、Google Cloud Functions、Gemini です。

9468866bfe848bb8.png

フィードバック アプリ(会話)

このアプリでは、Gemini を使用して、自然言語での会話によるレビューを収集して保存します。

使用される主なテクノロジーは、Dialogflow CX エージェント、Dialogflow CX ツール、OpenAPI、Google Cloud Functions、Gemini です。

99a7a0295f122f31.png

学習内容

  • Vertex AI を介して Google Chat アプリを Gemini と統合する方法。
  • Google Chat アプリを Dialogflow CX エージェントと統合する方法。
  • Google Chat の最新機能(アプリホーム、Google Chat イベント、アクセサリ ウィジェット)を使用する方法。

必要なもの

2. セットアップする

リソースを初期化する

このセクションでは、お使いのウェブブラウザから次のリソースにアクセスして構成します。

Apps Script プロジェクト

Apps Script コンソールで、次の手順を行います。

  1. [設定] をクリックし、Google Apps Script API を有効にします。

ea06c593b347b9d1.png

  1. プロジェクトを選択します。
  2. [プロジェクトの設定] をクリックします。
  3. [appsscript.json」マニフェスト ファイルをエディタで表示する] チェックボックスをオンにします。
  4. プロジェクトの名前を Chat Apps Gemini に変更します。

12c1485bd248b766.png

Google Cloud プロジェクト

Google Cloud コンソールで、次の手順を行います。

  1. プロジェクトを選択します。
  2. メニュー アイコン ☰ > [API とサービス] > [OAuth 同意画面] > [アプリの編集] をクリックし、[アプリ名] を Chat Apps Gemini に設定します。

  1. Google Chat API の構成に移動し、[アプリ名] と [説明] を Chat Apps Gemini に設定します。

a71f040755da3b8b.png

Google Chat

Google Chat で次の手順を行います。

  1. 必要に応じて、Google Chat アプリでチャットを開始します。
  2. メッセージ(「Hello」など)を送信して、機能することを確認します。

9625418251528ae9.png

ソースコードとリソースをローカルにダウンロードする

  1. この GitHub リポジトリをダウンロードします。

  1. 任意の開発環境で apps-script/chat-apps-gemini ディレクトリを開き、ターミナルで同じディレクトリに移動します。

da9478df97c99194.png

clasp をインストールして構成する

clasp を使用すると、ローカル環境からソースコードのバージョンを簡単に編集して Apps Script プロジェクトに push できます。

  1. ローカル環境で、nodenpmclasp の最新バージョンをインストールします。
npm install -g @google/clasp
  1. アカウントにログインします。
clasp login

8bc2434e6dc6f22a.png

成功すると、ウェブブラウザに基本的な確認画面が表示され、クライアント認証情報を含む .clasprc.json ファイルが更新されます。ターミナルで場所を確認できます。

e1d833eb4d5b3a8f.png

3. アプリ 1: ビルド

コンセプトを確認する

Vertex AI

Vertex AI には、AI ソリューション、エージェント ビルダー、130 を超える基盤モデル、統合 AI プラットフォームなど、生成 AI を構築して使用するために必要なものがすべて揃っています。

c9e9c7a1945b22ac.png

Gemini

Gemini は、Vertex AI からアクセスできる Google のマルチモーダル LLM です。人々が、人間の可能性を解き放ち、想像力を高め、好奇心を刺激し、生産性を高めるお手伝いをします。

高度なチャット サービス

高度なチャット サービスを使用すると、Apps Script で Google Chat API を使用できます。これにより、スクリプトで Chat スペースの検索、作成、変更、スペースへのメンバーの追加または削除、テキスト、カード、添付ファイル、リアクションを含むメッセージの読み取りまたは投稿を行えます。

アーキテクチャを確認する

8c9c7b7328a69ea6.png

この Google Chat アプリは Apps Script で作成されています。機能は次のとおりです。

  1. ユーザーが、ダイレクト メッセージまたはスペースでアプリにメッセージを送信します。
  2. アプリはメッセージを処理します。このアプリは Apps Script プロジェクトで実装され、Google Cloud プロジェクトに関連付けられています。
  3. アプリは、Google ドキュメントと Google Chat API と統合されています。
  4. アプリは、プロパティ サービスを使用して、スクリプト プロパティにデータを保持します。
  5. アプリは、ダイレクト メッセージまたは元のスペースで同期応答を送信します。

フローを確認する

問題を作成する

7ca0e8ba3c8255bb.png

専用スペースで問題をトラブルシューティングする

51b47714c378a24b.png

専用スペースで問題をクローズする

89e50228deeab0f9.png

ソースコードを確認する

この Apps Script プロジェクトには、次のスクリプトが含まれています。

  • Configuration: 環境に応じて編集する定数。
  • ChatApp: メッセージ、カードのクリック数、スラッシュ コマンド、ダイアログなどの Google Chat 操作イベントを処理します。
  • Storage: Properties Services を利用するユーティリティ関数。
  • ChatAppAuth: Google Chat アプリの認証を利用するユーティリティ関数。
  • Docs: Google ドキュメントを利用するユーティリティ関数。
  • VertexAi: Vertex AI を利用するユーティリティ関数。

Gemini と Chat スペースの履歴を使用してレポート ドキュメントを生成する際、以下の部分がアクティブに使用されます。

appsscript.json

// Enables the Admin SDK Directory and Chat services, which you need to retrieve
// messages and usernames.

"enabledAdvancedServices": [
  ...
  {
    "userSymbol": "AdminDirectory",
    "version": "directory_v1",
    "serviceId": "admin"
  },
  {
    "userSymbol": "Chat",
    "version": "v1",
    "serviceId": "chat"
  }
  ...
]
// Includes the OAuth scopes to request the Admin SDK Directory, Google Chat,
// Google Docs, and Vertex AI APIs.

"oauthScopes": [
  ...
  "https://www.googleapis.com/auth/admin.directory.user.readonly",
  "https://www.googleapis.com/auth/chat.messages.readonly",
  "https://www.googleapis.com/auth/documents",
  "https://www.googleapis.com/auth/cloud-platform",
  ...
]

Configuration.js

// Relies on two constants: the first one is the Google Cloud project ID and the
// second one is the Vertex AI location to be used.

...
const PROJECT_ID = 'replace-with-gcp-project-id';
const VERTEX_AI_LOCATION_ID = 'us-central1';
...

ChatApp.js

// The slash command process function retrieves history, generates content, and passes
// it to the report generator.

function processSlashCommand(event) {
  ...
  if (event.message.slashCommand.commandId == CLOSE_COMMAND_ID
    && event.message.space.type !== "DM") {
    ...
    const history = exportSpaceHistory(spaceId);
    const summary = summarizeSpace(history);
    const docUrl = createReport(
      issue.title, issue.description, resolution, history, summary
    );
    ...
  }
  ...
}
/**
 * Fetches and concatenates the 100 first space messages by using the Google Chat API.
 *
 * Messages with slash commands are filtered (app command invocations).
 *
 * @return {string} concatenate space messages in the format "Sender's name: Message"
 */
function exportSpaceHistory(spaceName) {
  const messages = Chat.Spaces.Messages.list(spaceName, { 'pageSize': 100 }).messages;
  // Returns results after fetching message sender display names.
  let users = new Map();
  return messages
    .filter(message => message.slashCommand === undefined)
    .map(message =>
      `${getUserDisplayName(users, message.sender.name)}: ${message.text}`
    ).join('\n');
}
/**
 * Fetches a user's display name by using the Admin Directory API.
 *
 * A cache is used to only call the API once per user.
 *
 * @param {Map} cache the map containing users previously fetched
 * @param {string} userId the user ID to fetch
 * @return {string} the user's display name
 */
function getUserDisplayName(cache, userId) {
  if (cache.has(userId)) {
    return cache.get(userId);
  }
  let displayName = 'Unknown User';
  try {
    const user = AdminDirectory.Users.get(
      userId.replace("users/", ""),
      { projection: 'BASIC', viewType: 'domain_public' });
    displayName = user.name.displayName ? user.name.displayName : user.name.fullName;
  } catch (e) {
    // Ignores errors, uses 'Unknown User' by default.
  }
  cache.set(userId, displayName);
  return displayName;
}

VertexAi.js

/**
 * Summarizes a Google Chat space history with the Gemini Pro model using
 * Vertex AI API.
 *
 * @param {string} history the history
 * @return {string} the summary
 */
function summarizeSpace(history) {
  const url = `https://${VERTEX_AI_LOCATION_ID}-aiplatform.googleapis.com/v1`
    + `/projects/${PROJECT_ID}/locations/${VERTEX_AI_LOCATION_ID}`
    + "/publishers/google/models/gemini-1.0-pro:generateContent";
  const options = {
    method: "POST",
    headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
    contentType: "application/json",
    payload: JSON.stringify({
      contents: {
        role: "user",
        parts: {
          text: "Summarize the following conversation between engineers resolving"
              + " an issue in a few sentences.\n\n" + history
        }
      },
      safetySettings: {
        category: "HARM_CATEGORY_SEXUALLY_EXPLICIT",
        threshold: "BLOCK_LOW_AND_ABOVE"
      },
      generationConfig: {
        temperature: 0.2,
        topP: 0.8,
        topK: 40
      }
    })
  };

  return JSON.parse(UrlFetchApp.fetch(url, options).getContentText())
    .candidates[0].content.parts[0].text;
}

Docs.js

// The report generator function adds two sections: the first one is for the summary and the second one is for history.
function createReport(..., history, summary) {
  ...
  body.appendParagraph("Summary").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph(summary);
  body.appendParagraph("History").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph(history);
  ...
}

Google Cloud プロジェクトを更新する

API を有効にする

  1. Google Cloud コンソールで、Google ドキュメントGoogle Admin SDKVertex AI API を有効にします。

  1. メニュー アイコン ☰ > [API とサービス] > [有効な API とサービス] をクリックし、API が有効になっていることを確認します。

サービス アカウントを開始する

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [IAM と管理] > [サービス アカウント] > [+ サービス アカウントを作成] をクリックします。

74cf57426419f39.png

  1. [サービス アカウント名] を chat-app に設定します。
  2. [サービス アカウントの説明] を Chat app auth に設定します。
  3. [作成して続行] をクリックします。
  4. [完了] をクリックします。[サービス アカウント] ページにリダイレクトし、作成したサービス アカウントが表示されます。

ca0468f1f93990f9.png

  1. 新しく作成したサービス アカウントを選択します。
  2. [キー] タブを選択します。
  3. [鍵を追加] をクリックします。
  4. [新しい鍵を作成] をクリックします。
  5. [JSON] を選択します。
  6. [作成] をクリックします。

9f7e6ea020978ab0.png

ダイアログが閉じ、新しく作成された公開鍵/秘密鍵ペアが JSON ファイルとしてローカル環境に自動的にダウンロードされます。この内容は、後で Apps Script プロジェクトのソースコードを編集するときに使用します。

Google Chat API の構成を更新する

Google Cloud コンソールで、次の手順を行います。

  1. スラッシュ コマンドを追加します。
  2. [名前] を /create に設定します。
  3. [コマンド ID] を 1 に設定します。
  4. [説明] を Create a new issue に設定します。
  5. [ダイアログを開く] チェックボックスをオンにします。
  6. 別のスラッシュ コマンドを追加します。
  7. [名前] を /close に設定します。
  8. [コマンド ID] を 2 に設定します。
  9. [説明] を Close an issue に設定します。
  10. [保存] をクリックします。

bee2e7b63659ab33.png

Apps Script プロジェクトを更新する

  • ローカル ターミナルの現在のディレクトリを issue-management/1-baseline に変更します。ソースコードが含まれています。ソースコードを Apps Script プロジェクトに push する前に、構成を行う必要があります。

ソースコードを構成する

  1. Configuration.js ファイル内の CHAT_CREDENTIALS という名前の JSON 定数を、先ほどダウンロードした秘密鍵ファイルの内容に設定します。

d721f6bff73c5304.png

  1. Google Cloud コンソールで、メニュー アイコン ☰ > [IAM と管理] > [設定] をクリックします。

  1. プロジェクト ID をコピーします。

82592fa0bd113469.png

  1. Configuration.js ファイル内の PROJECT_ID という名前の文字列定数をプロジェクト ID に設定します。

383cee561130ceba.png

clasp 設定を構成する

ソースコードを適切な Apps Script プロジェクトに push するために clasp 設定を初期化するには、次の手順を行います。

  1. Apps Script コンソールで、プロジェクトを選択します。
  2. [プロジェクトの設定] を選択します。
  3. [ID] で [コピー] をクリックします。

20ea033b6de882c6.png

  1. 現在のディレクトリに .clasp.json ファイルを作成します。
  2. <your-script-id> をコピーした ID に置き換えます。
  3. 結果を .clasp.json ファイルにコピーします。
  4. .clasp.json ファイルを保存します。
{
  "scriptId": "<your-script-id>"
}

ソースコードを push する

  • 次のコマンドを実行します。
$clasp push
? Manifest file has been updated. Do you want to push and overwrite? Yes
└─ appsscript.json
└─ ChatApp.js
└─ ChatAppAuth.js
└─ Configuration.js
└─ Docs.js
└─ Storage.js
└─ VertexAi.js
Pushed 7 files.

試してみる

  1. Google Chat で、アプリにダイレクト メッセージで Hello! を送信します。アプリは応答しませんが、構成を促すメッセージが表示されます。

4c1fc68121dcffed.png

  1. [設定] をクリックします。
  2. Google アカウントを選択します。
  3. 認証します。
  4. アプリへのアクセスを確認して許可します。

4a2fd7ac5918bf1a.png

成功すると、ウェブページに基本的な確認画面と、元のメッセージに対するアプリからの実際のレスポンスが表示されます。

acb9065568fe47d2.png

2d6ef9c62f47e082.png

  1. アプリに別のダイレクト メッセージを送信します。今回はスラッシュ コマンド /create を使用します。

be3f3c6eb0f929c1.png

  1. ダイアログで [タイトル] を Issue Title 1 に設定します。
  2. [説明] を 問題 Description 1 に設定します。
  3. [作成] をクリックします。

22efdecff4601417.png

このアプリは次の処理を行います。

  1. ダイアログを閉じます。
  2. 新しく作成された問題の専用スペースを同じタイトルで作成します。
  3. 新しく作成されたスペースに参加します。
  4. 新しく作成されたスペースで、問題の説明を含むメッセージを送信します。
  5. 新しく作成されたスペースへのリンクが記載されたダイレクト メッセージを送信します。

3253cec2392e281f.png

  1. 新しく作成したスペースで、スラッシュ コマンド /close と解決策(Not reproducible など)を含むメッセージを送信します。

132cc4acfc10b98c.png

このアプリは次の処理を行います。

  1. Google ドキュメントでレポート ドキュメントを作成します。
  2. 問題専用のスペースに、新しく作成されたレポート ドキュメントへのリンクを含むメッセージを送信します。

2d127c63518673b2.png

  1. レポート ドキュメントを開きます。基本情報、履歴、概要が含まれます。

9aea694937f2f3ed.png

4. 省略可: アプリ 1: アプリホームを追加する

コンセプトを確認する

アプリホームは、ユーザーが Chat アプリのダイレクト メッセージから [ホーム] タブにアクセスしたときに Chat アプリがユーザーに送信する、カスタマイズ可能なカード メッセージです。通常、アプリのドキュメントや概要を表示するために使用されます。技術的には、処理する専用のイベントがあり、カード メッセージと同じ基本原則に基づいています。

65f56f70f67a32e4.png

フローを確認する

問題を管理する

10663f5fc107fb3f.png

ソースコードを確認する

Apps Script プロジェクトを編集する必要があります。

ChatApp.js

/**
 * Handles app home requests in Google Chat.
 * 
 * Displays the latest status of all issues.
 */
function onAppHome() {
  // Generates one card section per issue.
  var sections = [];
  for (var issueKey in appProperties.getProperties()) {
    const issue = JSON.parse(appProperties.getProperty(issueKey));
    if (issue.spaceId) {
      sections.push({
        header: `${issue.status} - ${issue.title}`,
        widgets: [{ textParagraph: {
            text: `Description: ${issue.description}`
          }}, { textParagraph: {
            text: `Resolution: ${issue.resolution}`
          }}, { buttonList: { buttons: [{
              text: "Open space",
              onClick: { openLink: {
                url: `https://mail.google.com/mail/u/0/#chat/space/${issue.spaceId}`
              }}
            }, {
              text: "Open report",
              onClick: { openLink: {
                url: issue.reportUrl !== "" ? issue.reportUrl : "docs.new"
              }},
              disabled: issue.reportUrl === ""
          }]}
        }]
      });
    }
  }

  return { action: { navigations: [{ push_card: {
    sections: sections
  }}]}};
}

Google Cloud プロジェクトを更新する

Google Cloud コンソールで、次の手順を行います。

  1. [インタラクティブ機能] セクションで、[アプリのホームをサポートする] チェックボックスをオンにします。

97159c1c69ca8303.png

ローカル環境で次の手順を行います。

  1. ターミナルで現在のディレクトリを issue-management/2-app-home に変更します。使用する必要があるソースコードが含まれています。
  2. issue-management/1-baseline/.clasp.json ファイルを現在のディレクトリにコピーします。
  3. issue-management/1-baseline/Configuration.js ファイルを現在のディレクトリにコピーして、既存のファイルを置き換えます。
  4. 次のコマンドを実行します。
clasp push

試してみる

Google Chat で次の手順を行います。

  1. スラッシュ コマンド /create を含むダイレクト メッセージをアプリに送信します。アプリでダイアログが開きます。
  2. [タイトル] を Issue Title 2 に設定します。
  3. [説明] を 問題 Description 2 に設定します。
  4. [作成] をクリックします。

3b2a8690e758f965.png

  1. Google Chat アプリでスペースの [ホーム] タブを選択します。作成した問題の詳細が表示されます。

ed8e32da0e6f2ac6.png

5. 省略可: アプリ 1: スペースのモニタリングを追加する

コンセプトを確認する

Pub/Sub

Pub/Sub は、メッセージを生成するサービスと処理するサービスとを切り離す、非同期のスケーラブルなメッセージング サービスです。Pub/Sub を使用すると、イベント プロデューサー(パブリッシャー)とコンシューマー(サブスクライバー)のシステムを作成できます。パブリッシャーは、同期リモート プロシージャ コール(RPC)ではなく、イベントをブロードキャストすることによってサブスクライバーと非同期に通信します。

パブリッシャーは、イベントが処理される方法やタイミングとは無関係に、Pub/Sub サービスにイベントを送信します。その後、Pub/Sub によって、イベントに反応するすべてのサービスにイベントが配信されます。RPC を介して通信するシステムでは、パブリッシャーはサブスクライバーがデータを受信するのを待つ必要があります。ただし、Pub/Sub で非同期統合を行うと、システム全体の柔軟性と堅牢性が向上します。

トピック: メッセージのフィードを示す名前付きエンティティ。トピックをパブリッシュまたはサブスクライブする前に、トピックを作成する必要があります。

サブスクリプション: トピックに公開されたメッセージを受信するには、そのトピックへのサブスクリプションを作成する必要があります。サブスクライバー クライアントは、トピックにパブリッシュされたメッセージを受信して処理します。トピックは複数のサブスクリプションを持つことができますが、特定のサブスクリプションは単一のトピックに属します。

Google Workspace のイベント

Google Workspace のイベントは、Google Workspace のリソースに対する変更(リソースの作成、更新、削除など)を表します。アプリは Google Workspace のリソースをサブスクライブして、関連するイベントを非同期で受信および処理できます。

7816e477b112bfb6.png

Google Workspace Events API は、次のような手順でサブスクリプションを通じてアプリにイベントを配信します。

  1. アプリが Google Workspace アプリのリソースをサブスクライブします(スペースなど)。
  2. アプリが変更をサブスクライブしたリソースです。
  3. Google Workspace アプリは、Pub/Sub のトピックにイベントを配信します。トピックは、アプリの Google Workspace サブスクリプションの通知エンドポイントとして機能します。このイベントには、リソースで変更された内容に関するデータが含まれます。
  4. アプリは、イベントを含む Pub/Sub メッセージを処理し、必要に応じてアクションを実行します。

フローを確認する

問題を作成する(更新)

6d7a9d7a68666a80.png

専用スペースで問題をトラブルシューティングする(更新)

17e60f052f222456.png

専用スペースで問題をクローズする(更新)

742d490ea0b6fe3a.png

サブスクリプションを処理する

de3017100dec6401.png

ソースコードを確認する

Apps Script プロジェクトを編集する必要があります。

appsscript.json

// Enables the Workspace Events service.

"enabledAdvancedServices": [
  ...
  {
    "userSymbol": "WorkspaceEvents",
    "version": "v1",
    "serviceId": "workspaceevents"
  }
  ...
]

Configuration.js

// Adds two constants: the first one is the Pub/Sub topic ID and the second one
// is the Pub/Sub subscription ID to be used to retrieve Google Workspace events.

...
const GWS_PUBSUB_TOPIC_ID = `projects/${PROJECT_ID}/topics/workspace-events`;
const GWS_PUBSUB_SUBSCRIPTION_ID =
  `projects/${PROJECT_ID}/subscriptions/workspace-events-sub`;
...

ChatApp.js

// Edits the function to delete the subscription at issue closure.

function processSlashCommand(event) {
  ...
  if (event.message.slashCommand.commandId == CLOSE_COMMAND_ID
    && event.message.space.type !== "DM") {
    ...
    deleteSubscription(issue.subscriptionId);
    ...
  }
  ...
}
// Edits the function to create the subscription.

function createIssue(event) {
  ...
  const subscriptionId = createSpaceSubscription(spaceUrl);
  const createdIssue = saveCreatedIssue(..., subscriptionId);
  ...
}
// Edits the function to delete the subscription.

function onRemoveFromSpace(event) {
  ...
  deleteSubscription(issue.subscriptionId);
  ...
}

Storage.js

// Edits the function to keep track of the subscription ID.

function saveCreatedIssue(..., spaceId, subscriptionId) {
  ...
  appProperties.setProperty(spaceId, JSON.stringify({
    ...
    subscriptionId: subscriptionId,
    ...
  }));
  ...
}

WorkspaceEvent.js

/**
 * Creates a new subscription to Google Workspace Events associated to a
 * Google Chat space.
 * 
 * The subscription scope includes message creation events and resources.
 * 
 * @param {string} spaceId the space ID to create a subscription for
 * @return the ID of the newly created subscription
 */
function createSpaceSubscription(spaceId) {
  const operation = WorkspaceEvents.Subscriptions.create({
    targetResource: `//chat.googleapis.com/${spaceId}`,
    eventTypes: ["google.workspace.chat.message.v1.created"],
    notificationEndpoint: { pubsubTopic: GWS_PUBSUB_TOPIC_ID },
    payloadOptions: { includeResource: true },
  });

  return operation.response.name;
}
/**
 * Processes events from subscription by using the Google Cloud PubSub API.
 * 
 * It pulls and acknowledges each event.
 */
function processSubscription() {
  const response = UrlFetchApp.fetch(
    `https://pubsub.googleapis.com/v1/${GWS_PUBSUB_SUBSCRIPTION_ID}:pull`,
    {
      method: "POST",
      contentType: "application/json",
      headers: { "Authorization": "Bearer " + ScriptApp.getOAuthToken() },
      payload: JSON.stringify({ maxMessages: 10 })
    }
  );

  const messages = JSON.parse(response.getContentText()).receivedMessages;
  for (var messageIndex in messages) {
    const message = messages[messageIndex];
    const ceType = message.message.attributes["ce-type"];
    const dataStr = Utilities.newBlob(Utilities.base64Decode(message.message.data))
      .getDataAsString();
    if (ceType === "google.workspace.events.subscription.v1.expirationReminder") {
      // Renews subscription.
      renewSubscription(JSON.parse(dataStr).subscription.name);
    } else if (ceType === "google.workspace.chat.message.v1.created") {
      // Processes the message text when it's sent in a space.
      const chatMessage = JSON.parse(dataStr).message;
      if (chatMessage.sender.type !== "BOT") {
        console.log("Message was processed.");
      }
    }
    // Acknowledges successful processing to avoid getting it again next time.
    ackSubscription(message.ackId);
  }
}
/**
 * Acknowledges a subscription event by using the Google Cloud PubSub API.
 * 
 * @param {string} ackId the ID of the event acknowledgment to send
 */
function ackSubscription(ackId) {
  UrlFetchApp.fetch(
    `https://pubsub.googleapis.com/v1/${GWS_PUBSUB_SUBSCRIPTION_ID}:acknowledge`,
    {
      method: "POST",
      contentType: "application/json",
      headers: { "Authorization": "Bearer " + ScriptApp.getOAuthToken() },
      payload: JSON.stringify({
        ackIds: [ackId]
      })
    }
  );
}
/**
 * Renews a subscription to Google Workspace Events.
 * 
 * The default time to live option is used.
 * 
 * @param {string} subscriptionId the ID of the subscription to renew
 */
function renewSubscription(subscriptionId) {
  WorkspaceEvents.Subscriptions.patch({ttl: '0s'}, subscriptionId);
}
/**
 * Deletes a subscription to Google Workspace Events.
 * 
 * @param {string} subscriptionId the ID of the subscription to delete
 */
function deleteSubscription(subscriptionId) {
  WorkspaceEvents.Subscriptions.remove(subscriptionId);
}

Google Cloud プロジェクトを更新する

API を有効にする

  1. Google Cloud コンソールで、Google Workspace イベントと PubSub を有効にします。

  1. メニュー アイコン ☰ > [API とサービス] > [有効な API とサービス] の順にクリックして、両方が有効になっていることを確認します。

サブスクリプションを開始する

すべてのワークスペース イベントを送信するには、Pub/Sub トピックを作成してサブスクライブする必要があります。

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [Pub/Sub] > [トピック] に移動します。

  1. [トピックを作成] をクリックします。
  2. [トピック ID] を workspace-events に設定します。
  3. [デフォルトのサブスクリプションを追加する] チェックボックスをオンにします。
  4. [作成] をクリックします。

b39f9a0aec7c9939.png

新しく作成したトピックに Pub/Sub メッセージをパブリッシュする権限を Google Chat から付与する手順は次のとおりです。

  1. リストからトピックを選択します。
  2. [権限] タブを選択します。
  3. [新しいプリンシパル] に chat-api-push@system.gserviceaccount.com を追加します。
  4. [ロール] で [Pub/Sub パブリッシャー] を選択します。
  5. [保存] をクリックします。

8d4016c37532503.png

Apps Script プロジェクトを更新する

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [IAM と管理] > [設定] に移動します。

  1. プロジェクト ID をコピーします。

82592fa0bd113469.png

ローカル環境で次の手順を行います。

  1. ターミナルで現在のディレクトリを issue-management/3-message-monitoring に変更します。必要なソースコードが含まれています。
  2. Configuration.js ファイル内の PROJECT_ID という名前の文字列定数を、コピーしたプロジェクト ID に設定します。
  3. Configuration.js ファイル内の CHAT_CREDENTIALS という名前の JSON 定数を、先ほどダウンロードした秘密鍵ファイルの内容に設定します。
  4. issue-management/2-app-home/.clasp.json ファイルを現在のディレクトリにコピーします。
  5. 次のコマンドを実行します。
clasp push

試してみる

Google Chat で次の手順を行います。

  1. スラッシュ コマンド /create を含むダイレクト メッセージをアプリに送信します。アプリでダイアログが開きます。
  2. [タイトル] を Issue Title 3 に設定します。
  3. [説明] を 問題 Description 3 に設定します。
  4. [作成] をクリックします。
  5. 新しく作成したスペースで、問題について説明するメッセージをいくつか送信します。
  6. スラッシュ コマンド /close と解決策(Fixed など)を含むメッセージを送信します。

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [Pub/Sub] > [サブスクリプション] に移動します。

  1. サブスクリプション [workspace-events-sub] を選択します。
  2. [メッセージ] タブを選択します。
  3. [Pull] をクリックします。新しく作成したスペースに送信したメッセージに関連するメッセージが表に表示されます。

82631c9792d83889.png

Apps Script コンソールで、次の手順を行います。

  1. プロジェクトを選択します。
  2. [エディタ] を選択します。
  3. WorkspaceEvent.gs ファイルを選択します。
  4. [実行] セクションで、[processSubscription] を選択します。
  5. [Run] をクリックします。実行ログで、メッセージが処理されたことを確認できます。

c612e8fa2bd0a163.png

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [Pub/Sub] > [サブスクリプション] に移動します。

  1. サブスクリプション [workspace-events-sub] を選択します。
  2. [メッセージ] タブを選択します。
  3. [Pull] をクリックします。新しく作成したスペースに送信したメッセージに関連するメッセージは表に表示されなくなります。

e185454cac862a7b.png

  • Google Chat で、スラッシュ コマンド /create を使用して作成した 3 つ目の問題専用のスペースに、その問題について議論するメッセージをさらにいくつか送信します。

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [Pub/Sub] > [サブスクリプション] に移動します。

  1. サブスクリプション [workspace-events-sub] を選択します。
  2. [メッセージ] タブを選択します。
  3. [Pull] をクリックします。新しく作成したスペースに送信したメッセージに関連するメッセージは表に表示されません。

6. 省略可: アプリ 1: インクルーシビティ サポートを追加する

コンセプトを確認する

生成 AI プロンプトとは、生成 AI モデルが特定の種類の出力を生成できるように、指示や質問を作成する技術です。一般的な方法は、プロンプトにルールと条件を追加して回答を制限することです。これにより、安全で関連性と一貫性のある、期待どおりの出力ができます。

フローを確認する

サブスクリプションを処理する(更新)

780d0802f77dd180.png

ソースコードを確認する

Apps Script プロジェクトを編集する必要があります。

WorkspaceEvent.js

// Edits the function to replace logging by an actual card message.

function processSubscription() {
  ...
  for (var messageIndex in messages) {
    ...
    } else if (ceType === "google.workspace.chat.message.v1.created") {
      ...
      const inclusivityCheck = getInclusivityFeedback(chatMessage.text);
      if (inclusivityCheck !== "It's inclusive!") {
        createAppMessageUsingChatService({
          cardsV2: [{ cardId: "1", card: { header: {
              title: "Inclusivity",
              subtitle: `The following words are not inclusive: ${inclusivityCheck}`
          }}}]
        },
        chatMessage.space.name);
      }
      ...
    }
    ...
  }
  ...
}

VertexAi.js

/**
 * Gets feedback on inclusivity for a text with the Gemini Pro model using
 * Vertex AI API.
 * 
 * Returns "It's inclusive!" when it is otherwise a list of word(s) that might not
 * be optimal.
 *
 * @param {string} text the text
 * @return {string} the feedback
 */
function getInclusivityFeedback(text) {
  const url = `https://${VERTEX_AI_LOCATION_ID}-aiplatform.googleapis.com/v1`
    + `/projects/${PROJECT_ID}/locations/${VERTEX_AI_LOCATION_ID}`
    + "/publishers/google/models/gemini-1.0-pro:generateContent";
  const options =  {
    method: "POST",
    headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
    contentType: "application/json",
    payload: JSON.stringify({
      contents: {
        role: "user",
        parts: {
          text: "Are there any words that obviously go against inclusivity "
            + "in this text:"
            + `\n\n----------\n${text}\n----------\n\n`
            + "If there are not, answer \"It's inclusive!\" "
            + "otherwise answer by listing them separated by commas. "
            + "Do not answer with any explanation."
        }
      },
      safetySettings: {
        category: "HARM_CATEGORY_SEXUALLY_EXPLICIT",
        threshold: "BLOCK_LOW_AND_ABOVE"
      },
      generationConfig: {
        temperature: 0.2,
        topP: 0.8,
        topK: 40
      }
    })
  };

  return JSON.parse(UrlFetchApp.fetch(url, options).getContentText())
    .candidates[0].content.parts[0].text;
}

Apps Script プロジェクトを更新する

ローカル環境で次の手順を行います。

  1. ターミナルで現在のディレクトリを issue-management/4-inclusivity-help に変更します。必要なソースコードが含まれています。
  2. issue-management/3-message-monitoring/.clasp.json ファイルを現在のディレクトリにコピーします。
  3. issue-management/3-message-monitoring/Configuration.js ファイルを現在のディレクトリにコピーして、既存のファイルを置き換えます。
  4. 次のコマンドを実行します。
clasp push

試してみる

Google Chat で次の手順を行います。

  1. スラッシュ コマンド /create を含むダイレクト メッセージをアプリに送信します。アプリでダイアログが開きます。
  2. [タイトル] を Issue Title 4 に設定します。
  3. [説明] を 問題 Description 4 に設定します。
  4. [作成] をクリックします。
  5. 新しく作成したスペースで、It happened to me last week as well を送信します。

Apps Script コンソールで、次の手順を行います。

  1. プロジェクトを選択します。
  2. [エディタ] を選択します。
  3. WorkspaceEvent.gs ファイルを選択します。
  4. [実行] セクションで、[processSubscription] を選択します。
  5. [実行] をクリックします。実行ログで、メッセージが処理されたことを確認できます。

Google Chat で次の手順を行います。

  1. アプリは、新しく作成されたスペースでインクルーシビティ サポートを送信していないことに注意してください。
  2. 新しく作成したスペースで、メッセージ「I had to add myself from the master to fix it」を送信します。

Apps Script コンソールで、次の手順を行います。

  1. プロジェクトを選択します。
  2. [エディタ] を選択します。
  3. WorkspaceEvent.gs ファイルを選択します。
  4. [実行] セクションで、[processSubscription] を選択します。
  5. [実行] をクリックします。実行ログで、メッセージが処理されたことを確認できます。Google Chat でアプリが、新しく作成されたスペースで、インクルーシビティ サポートに関するメッセージを送信しました。

7936342847acbe2d.png

7.省略可: アプリ 1: 設定を追加する

.

コンセプトを確認する

アクセサリ ウィジェットは、アプリから送信されたメッセージの下部に付加される、枠線のないウィジェットです。通常、メッセージの特定のコンテキストでユーザーがすばやくリアクションできるようにするために使用されます。技術的には、カードボタンと同じ基本原則に基づいています。

eebe88238f6b13f.png

フローを確認する

インクルーシビティ サポートを無効にする

1bb7a8592ee6221e.png

ソースコードを確認する

Apps Script プロジェクトを編集する必要があります。

ChatApp.js

// Edits the function to handle the inclusivity help disablement action for a
// given space.

function onCardClick(event) {
  ...
  if (event.action.actionMethodName === "disableInclusivityHelp") {
    disableInclusivityHelp(event.common.parameters.spaceId);
  }
}

Storage.js

// Edits the function to keep track of the inclusivity help setting.

function saveCreatedIssue(title, description, spaceId, subscriptionId) {
  appProperties.setProperty(spaceId, JSON.stringify({
    ...
    inclusivityHelp: true,
    ...
  }));
  ...
}
/**
 * Disables inclusivity help in a space.
 * 
 * @param {string} spaceId the ID of dedicated space of the issue
 */
function disableInclusivityHelp(spaceId) {
  var issue = JSON.parse(appProperties.getProperty(spaceId));
  issue.inclusivityHelp = false;
  appProperties.setProperty(spaceId, JSON.stringify(issue));
}
/**
 * Checks whether the app should help with inclusivity in a given space.
 * 
 * @param {string} spaceId the ID of dedicated space of the issue
 * @return whether the app should help with inclusivity
 */
function shouldHelpWithInclusivity(spaceId) {
  return JSON.parse(appProperties.getProperty(spaceId)).inclusivityHelp;
}

WorkspaceEvent.js

// Edits the function to display the accessory widget to the existing card message.

function processSubscription() {
  ...
  for (var messageIndex in messages) {
    ...
    } else if (ceType === "google.workspace.chat.message.v1.created") {
      ...
      if (... && shouldHelpWithInclusivity(chatMessage.space.name)) {
        createAppMessageUsingChatService({
          ...
          accessoryWidgets: [{ buttonList: { buttons: [{
            altText: "Disable inclusivity help",
            icon: {
              iconUrl: "https://upload.wikimedia.org/.../Stop_hand_rugen.png"
            },
            onClick: { action: {
              function: "disableInclusivityHelp",
              parameters: [{
                key: "spaceId",
                value: chatMessage.space.name
              }]
            }}
          }]}}]
        }, ...);
        ...
      }
      ...
    }
    ...
  }
  ...
}

Apps Script プロジェクトを更新する

ローカル環境で次の手順を行います。

  1. ターミナルで現在のディレクトリを issue-management/5-disable-help に変更します。必要なソースコードが含まれています。
  2. issue-management/4-inclusivity-help/.clasp.json ファイルを現在のディレクトリにコピーします。
  3. issue-management/4-inclusivity-help/Configuration.js ファイルを現在のディレクトリにコピーして、既存のファイルを置き換えます。
  4. 次のコマンドを実行します。
clasp push

試してみる

サポートを無効にする

  • Google Chat で、スラッシュ コマンド /create を使用して作成した 3 つ目の問題専用のスペースに、メッセージ「I had to add myself from the master to fix」を送信します。

Apps Script コンソールで、次の手順を行います。

  1. プロジェクトを選択します。
  2. [エディタ] を選択します。
  3. WorkspaceEvent.gs ファイルを選択します。
  4. [実行] セクションで、[processSubscription] を選択します。
  5. [実行] をクリックします。実行ログで、メッセージが処理されたことを確認できます。

Google Chat で次の手順を行います。

  1. アクセサリ ウィジェットに関する問題専用のスペースに、アプリがインクルーシビティ サポートに関するメッセージを送信します。
  2. アクセシビリティ ウィジェットをクリックし、インクルーシビティ サポートを無効にします。

de722cff1928dec9.png

無効化を確認する

  • Google Chat で、スラッシュ コマンド /create を使用して作成した 3 つ目の問題専用のスペースに、メッセージ「I had to add myself from the master to fix」を送信します。

Apps Script コンソールで、次の手順を行います。

  1. プロジェクトを選択します。
  2. [エディタ] を選択します。
  3. WorkspaceEvent.gs ファイルを選択します。
  4. [実行] セクションで、[processSubscription] を選択します。
  5. [実行] をクリックします。実行ログで、メッセージが処理されたことを確認できます。Google Chat では、無効にされていたため、この問題専用のスペースに、インクルーシビティ サポートのメッセージを送信しませんでした。

347d659db53b73e9.png

8. アプリ 2: ビルド

コンセプトを確認する

生成 AI のグラウンディング

検証可能な知識源に AI モデルを紐付けることで、AI モデルをより事実に基づいた信頼性の高いものにします。この手法は、AI が情報を作り出すのを防ぐのに役立ち、コンテキストに関連性のある偏りのない回答を生成できます。

自然言語

人工言語やコンピュータ ベースの言語とは対照的に、日常的なコミュニケーションのために人間が話したり書いたりする言語。

Cloud Storage

Cloud Storage では、世界中のどこからでも、いつでもデータを保存、取得できます。データの量に制限はありません。ウェブサイト コンテンツの提供、アーカイブと障害復旧のためのデータの保存、直接ダウンロードによるユーザーへの大規模なデータ オブジェクトの配布など、さまざまなシナリオで使用できます。

Dialogflow CX データストア

Dialogflow CX は、データストアと統合されます。データストアは、データストア エージェントがエンドユーザーの質問に対する回答を特定のデータから見つけるために使用するウェブサイトとドキュメントの集まりです。特定の質問に対して、データストア エージェントは特定のソース コンテンツから回答を検索し、見つかった結果を簡潔な回答に要約します。また、エンドユーザーが詳細を確認できるように、回答のソースへのサポートリンクも提供します。

アーキテクチャを確認する

9d3342d12f3b4dda.png

この Google Chat アプリは Dialogflow CX で構築されており、次のように動作します。

  1. ユーザーが、ダイレクト メッセージまたはスペースでアプリにメッセージを送信します。
  2. 送信されたメッセージをアプリが処理します。このアプリは Dialogflow CX エージェントで、Google Cloud プロジェクトに関連付けられています。
  3. アプリは、Cloud Storage にあるデータストアと統合されます。
  4. アプリは、ダイレクト メッセージまたは元のスペースで同期応答を送信します。

フローを確認する

質問に答える

aad9fb5a7ca48956.png

ソースコードを確認する

必要なソースはコードではなく、グラウンディングに使用するデータです。

google-chat-overview.pdf

Google Chat アプリの構造化されていない情報(Google Workspace デベロッパー ウェブサイトのページの印刷版)が含まれています。

e9b91c4587b1a3a0.png

Google Cloud プロジェクトを更新する

Google Cloud コンソールで、次の手順を行います。

  1. Dialogflow API と Cloud Storage API を有効にします。

  1. Vertex AI Agent Builder API を有効にします。

  1. メニュー アイコン ☰ > [API とサービス] > [有効な API とサービス] をクリックし、すべての API が有効になっていることを確認します。

.

Dialogflow CX データストア エージェントを作成する

ナレッジデータを開始する

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [Cloud Storage] > [バケット] をクリックします。

4f15978ae9f1b687.png

  1. [作成] をクリックします。
  2. [名前] を gchat-knowledge に設定します。
  3. [作成] をクリックします。

6b38c6d4d2c41bba.png

  1. [gchat-knowledge] バケットを選択します。
  2. [ファイルをアップロード] をクリックします。
  3. ローカル環境から knowledge-app/grounding/google-chat-overview.pdf ファイルを選択します。

df89acb22e1762af.png

アプリを作成する

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [エージェント ビルダー] > [アプリ] をクリックします。

  1. [新しいアプリ] をクリックします。
  2. チャットの種類を選択します。

44276003074bcf14.png

  1. Company name を会社名に設定します。
  2. Agent nameknowledge に設定します。
  3. [続行] をクリックします。

c4fedfd7556f723b.png

  1. [新しいデータストアの作成] をクリックします。
  2. データソースとして Cloud Storage を選択します。

6e2440ecf0f8f9bd.png

  1. [ファイル] を選択します。
  2. [参照] をクリックします。
  3. google-chat-overview.pdf ファイルを選択します。
  4. [続行] をクリックします。
  5. データストア名を gchat-knowledge-ds に設定します。
  6. [作成] をクリックします。

a675df7490b83900.png

  1. テーブルで [gchat-knowledge-ds] データストアを選択します。
  2. [作成] をクリックします。

f121d580771ed96.png

  1. 数分後にメニュー アイコン ☰ > [エージェント ビルダー] > [アプリ] をクリックすると、アプリが表示されます。

d929a7431dd84968.png

  1. メニュー アイコン ☰ > [エージェント ビルダー] > [データストア] をクリックします。

  1. [gchat-knowledge-ds] データストアをクリックします。ドキュメントの数は 1 になっており、準備ができていることを示します。

558319790a0accf2.png

アプリを完成させてテストする

Dialogflow CX コンソールで、次の手順を行います。

  1. Google Cloud プロジェクトを選択します。
  2. ナレッジ エージェントを選択します。

ca9b2fb4be92e8e4.png

  1. [Agent settings] > [Generative AI] > [Generative agent] を選択します。
  2. モデルを [Text Bison] から [Gemini Pro] に切り替えます。
  3. [Save] をクリックします。

68cc4713ec9b25a0.png

  1. [Test agent] をクリックします。
  2. What is Google Chat? を送信します。エージェントが意味のある回答を返します。

8e3a2cb02469041a.png

Google Chat アプリを統合する

Dialogflow CX コンソールで、次の手順を行います。

  1. Google Cloud プロジェクトを選択します。
  2. ナレッジ エージェントの行で、1e7ede7abae4aa3c.png > [Copy name] をクリックします。

e19f61185158110d.png

Google Cloud コンソールで、次の手順を行います。

  1. Google Chat API の構成に移動します。

  1. [接続設定] で [Dialogflow] を選択します。
  2. [Dialogflow の設定] で [Dialogflow CX] を選択します。
  3. [エージェントまたは環境リソース名] を、コピーしたエージェント名に設定します。
  4. 2 つのスラッシュ コマンドを削除します。

505ff39a50880904.png

  1. Google Chat で、Google Chat アプリにダイレクト メッセージで What is Google Chat? を送信します。エージェントが意味のある応答を返します。

abda9e43b81fb0ea.png

9.省略可: アプリ 2: ソースを追加する

コンセプトを確認する

Dialogflow CX Webhook

ビジネス ロジックをホストしたり、他のサービスを呼び出したりするサービスです。Dialogflow CX のセッション中に、Webhook は自然言語処理で抽出されたデータを使用して、動的レスポンスの生成、収集したデータの検証、バックエンドでのアクションのトリガーを行うことができます。

Cloud Functions

Cloud Functions は、サーバーレス バックエンドの構築、リアルタイムのデータ処理、インテリジェント アプリの作成に最適です。プロビジョニング、管理、パッチ適用、アップデートを行うサーバーはありません。自動スケーリングし、高可用性とフォールト トレランスを備えています。

フローを確認する

質問に答える(更新)

92767c07c7b252aa.png

ソースコードを確認する

必要なソースコードは、エージェントの回答を Google Chat のメッセージに適応させる関数だけです。これは Webhook として使用されます。

package.json

// The function relies on the Cloud Functions framework to run.

{
  "name": "agent-response-adapter",
  "version": "0.0.1",
  "dependencies": {
    "@google-cloud/functions-framework": "^3.0.0"
  },
  ...
}

index.js

/** 
 * Handles all incoming requests.
 *
 * It takes a Dialogflow CX agent response as input and returns a
 * valid Google Chat card message with both the text and source links
 */
functions.http('agent-response-adapter', (request, response) => {
  // Creates Google Chat buttons based on the data store agent response
  // grounding details.
  var linkTitles = [];
  var linkButtons = [];
  const grounding = request.body.messages[1].payload.richContent[0][0];
  if (grounding.type === "match_citations") {
    // Supports citation match type.
    grounding.citations.forEach((citation) => {
      // Avoid duplications.
      if (linkTitles.indexOf(citation.title) < 0) {
        linkButtons.push({
          text: citation.title,
          onClick: { openLink: {
            url: citation.actionLink
          }}
        });
        linkTitles.push(citation.title);
      }
    });
  } else if (grounding.type === "info") {
    // Supports info type.
    if (linkTitles.indexOf(grounding.title) < 0) {
      linkButtons.push({
        text: grounding.title,
        onClick: { openLink: {
          url: grounding.actionLink
        }}
      });
      linkTitles.push(grounding.title);
    }
  }

  // Sends the Dialogflow CX fulfillment response to replace the agent response
  // with the Chat message with text and source buttons.
  response.send({ fulfillment_response: {
    merge_behavior: "REPLACE",
    messages: [{ payload: {
      // Reuses the original data store agent response text.
      text: request.body.messages[0].text.text[0],
      cardsV2: [{
        cardId: "sourcesCard",
        card: { sections: [{
          header: "Sources",
          widgets: [{ buttonList: {
            buttons: linkButtons
          }}]
        }]}
      }]
    }}]
  }});
});

Google Cloud プロジェクトを更新する

Google Cloud コンソールで、次の手順を行います。

  1. Cloud Build、Cloud Functions、Cloud Logging、Artifact Registry、Cloud Run API を有効にします。

  1. メニュー アイコン ☰ > [API とサービス] > [有効な API とサービス] をクリックし、API が有効になっていることを確認します。

Dialogflow CX データストア エージェントを更新する

可能であれば、Cloud Functions の関数をデプロイし、Dialogflow CX Webhook を更新して、複数のソースでトリガーする必要があります。

複数のソースを返す

デフォルトでは、新しいデータストア エージェントは最大で 1 つのソースのみを返しますが、変更して増やすことができます。

Dialogflow CX コンソールで、次の手順を行います。

  1. Google Cloud プロジェクトを選択します。
  2. ナレッジ エージェントを選択します。
  3. [Start page] を選択します。
  4. [Edit data stores] を選択します。
  5. [Agent responses section] で、[Data store response options] を 5 に設定します。
  6. [Save] をクリックします。

f5932d03057df645.png

Cloud Functions を開始する

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [Cloud Functions] をクリックします。

  1. [関数を作成] をクリックします。
  2. [基本] で、[名前] を function-1 に設定します。
  3. [認証] で、[未認証の呼び出しを許可する] ラジオボタンを選択します。
  4. [ランタイム、ビルド、接続、セキュリティの設定] で、[インスタンスの最大数] を 3 に設定します。
  5. [次へ] をクリックします。

bd3790a9285f9c07.png

  1. [エントリ ポイント] を agent-response-adapter に設定します。
  2. デフォルトのコンテンツを、knowledge-app/agent-response-adapter ディレクトリにあるファイルで置き換えます。
  3. [デプロイ] をクリックします。

b379bb8ca0fc1079.png

  1. 関数がデプロイされるまで数分待って、URL をコピーします。

eaae08cf048b9b1c.png

Webhook を開始する

新しくデプロイされた関数をトリガーする Webhook を使用するように Dialogflow CX エージェントを構成する必要があります。

Dialogflow CX コンソールで、次の手順を行います。

  1. Google Cloud プロジェクトを選択します。
  2. ナレッジ エージェントを選択します。
  3. [Manage] > [Webhooks] > [Create] を選択します。
  4. [Display name] を Google Chat Response Adapter に設定します。
  5. [Webhook URL] を、先ほどコピーした URL に設定します。
  6. [Save] をクリックします。

5f3c6804d52b87c1.png

  1. [Build] をクリックします。
  2. [Start page] を選択します。
  3. [Edit data stores] を選択します。
  4. [Webhook settings] で、[Enable webhook] の切り替えボタンをクリックします。
  5. [Google Chat Response Adapter for Webhook] を選択します。
  6. [tag] を arbitrary_tag に設定します。
  7. [Save] をクリックします。

442fcaaec9b8f2e3.png

アプリをテストする

  • Google Chat で、Google Chat アプリにダイレクト メッセージで What is Google Chat? を送信します。エージェントが意味のある応答とソースを含むカード(ある場合)を返します。

9468866bfe848bb8.png

10. アプリ 3: ビルド

コンセプトを確認する

会話型の操作

会話とは、2 人以上の人々が自然言語で情報やアイデアをやり取りすることです。これは、多くの場合ステートレスで高度に構造化され、決まった操作が必要な技術インターフェースとは対照的です。

OpenAPI 仕様

API ライフサイクルの各ステージで情報を一貫して伝達する手段を提供します。HTTP API の仕様言語であり、API の作成に使用されるプログラミング言語に依存しない方法で構造と構文を定義します。API 仕様は通常、YAML または JSON で記述されます。これにより、仕様を容易に共有、使用できるようになります。

Dialogflow CX エージェント

エージェント アプリの基本的なビルディング ブロックです。通常、エージェント アプリには多数のエージェントが存在し、各エージェントは特定のタスクを処理するように定義されています。エージェントのデータは LLM に提供されるため、LLM には、質問に回答し、タスクを実行するために必要な情報が含まれています。各エージェントは、情報を提供したり、外部サービスにクエリを送信したりすることができます。また、サブタスクを処理するために、会話処理を Dialogflow CX フローや別のエージェントに委ねることも可能です。

Dialogflow CX ツール

ツールは、エージェント アプリを外部システムに接続するために使用されます。接続された外部システムによって、エージェント アプリの知識を補完し、複雑なタスクを効率的に実行できます。

アーキテクチャを確認する

9d3342d12f3b4dda.png

この Google Chat アプリは Dialogflow CX で構築されており、次のように動作します。

  1. ユーザーが、ダイレクト メッセージまたはスペースでアプリにメッセージを送信します。
  2. 送信されたメッセージをアプリが処理します。このアプリは Dialogflow CX エージェントで、Google Cloud プロジェクトに関連付けられています。
  3. またエージェントと統合されています。
  4. アプリは、ダイレクト メッセージまたは元のスペースで同期応答を送信します。

フローを確認する

レビューを収集する

a67a5b8b513bfc2c.png

ソースコードを確認する

必要なソースコードは、エージェントがツールとして使用するバックエンド サービスをモックする関数だけです。

package.json

// The function relies on the Cloud Functions framework to run.

{
  "name": "feedback-app-backend",
  "version": "0.0.1",
  "dependencies": {
    "@google-cloud/functions-framework": "^3.0.0"
  },
  ...
}

index.js

/** 
 * Handles all incoming requests.
 * 
 * It always returns OK in plain text.
 */
functions.http('feedback-app-backend', (request, response) => {
    response.send('OK');
});

service-openapi.yaml

// Defines the backend service structure and how to request it.

openapi: 3.1.0
info:
  title: Review Store
  license:
    name: Apache 2.0
    identifier: Apache-2.0
  version: 0.0.1
servers:
  - url: https://us-central1-project-0.cloudfunctions.net
paths:
  /store-review:
    post:
      operationId: storeReview
      summary: Store a new review
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                stars:
                  type: integer
                  format: int64
      responses:
        '200':
          description: success
          content:
            application/json:
              schema:
                type: string

バックエンド サービスのモックを開始する

Dialogflow CX エージェント アプリが統合してツールとして呼び出す必要があるバックエンド サービスをシミュレーションするため、Cloud Function をデプロイします。

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [Cloud Functions] をクリックします。

  1. [関数を作成] をクリックします。
  2. [基本] で、[名前] を function-2 に設定します。
  3. [認証] で、[未認証の呼び出しを許可する] ラジオボタンを選択します。
  4. [ランタイム、ビルド、接続、セキュリティの設定] で、[インスタンスの最大数] を 3 に設定します。
  5. [次へ] をクリックします。

e8cf0ee7441bf634.png

  1. [エントリ ポイント] を feedback-app-backend に設定します。
  2. デフォルトのコンテンツを、feedback-app ディレクトリにあるファイルで置き換えます。
  3. [デプロイ] をクリックします。

bdb5cf9f503aa7f6.png

  1. 関数がデプロイされるまで数分待って、URL をコピーします。

Dialogflow CX エージェント アプリを作成する

アプリを作成する

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [エージェント ビルダー] > [アプリ] をクリックします。

  1. [新しいアプリ] をクリックします。
  2. [エージェント] を選択します。
  3. [Display name] を Feedback App に設定します。
  4. [作成] をクリックします。

7ef3dbacee96c5aa.png

ツールを開始する

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [エージェント ビルダー] > [アプリ] をクリックします。

  1. [Feedback App] エージェントを選択します。
  2. [ツール] > [+ 作成] をクリックします。
  3. [名前] を review に設定します。
  4. [OpenAPI] を選択します。
  5. [説明] を次の値に設定します。
The tool takes the number of stars as a parameter of the store review method and saves it in a database for later use.
  1. feedback-app/service-openapi.yaml ファイルの $URL を、前にコピーした URL に置き換えます。
  2. YAML Schemafeedback-app/service-openapi.yaml ファイルの編集済みコンテンツに設定します。
  3. [保存] をクリックします。

58085d6d56b603f7.png

エージェントを開始する

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [エージェント ビルダー] > [アプリ] をクリックします。

  1. [Feedback App] エージェントを選択します。
  2. [エージェント] > [デフォルトの生成エージェント] を選択します。
  3. [エージェント名] を Feedback collector に設定します。
  4. goal を次の値に設定します。
You are an agent that collects reviews from Google Chat app developers.
A review may be between 0 and 5 stars. The more stars, the more positive the review.
  1. [手順] を次の値に設定します。
If the developer didn't provide the number of stars, ask for the number of stars.
After the developer provides the number of stars of the review, confirm the number with the developer and use ${TOOL: review} to store the review with the number of stars.
If ${TOOL: review} fails, apologize and ask to try again later. Otherwise, thank the developer for the review.
  1. [保存] をクリックします。

ebee7fdfa826b487.png

アプリをテストする

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [エージェント ビルダー] > [アプリ] をクリックします。

  1. [Feedback App] エージェントを選択します。
  2. [プレビュー エージェント] に移動します。
  3. [エージェント] で [フィードバック コレクタ] を選択します。
  4. [生成モデルを選択] で、[gemini-pro] を選択します。
  5. メッセージ「Hello!」を送信して開始します。

90ca8cb7b2c1cb4b.png

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [Cloud Functions] をクリックします。

  1. [function-2] > [ログ] を選択します。一部のログの呼び出し元が Google-Dialogflow と表示されます。

48bfdf1788004d18.png

Google Chat アプリを統合する

Dialogflow CX コンソールで、次の手順を行います。

  1. Google Cloud プロジェクトを選択します。
  2. Feedback App エージェントの操作メニューをクリックします。
  3. [Copy name] をクリックします。

Google Cloud コンソールで、次の手順を行います。

  1. Google Chat API の構成に移動します。

  1. [エージェントまたは環境リソース名] を、コピーしたエージェント名に設定します。

df16619a1cb85cf8.png

  • Google Chat で、Google Chat アプリにダイレクト メッセージで Hello! を送信して開始します。エージェントは、Dialogflow CX コンソールからのテストと同様に応答します。

99a7a0295f122f31.png

11. クリーンアップ

Google Cloud プロジェクトを削除する

この Codelab で使用したリソースに対して Google Cloud アカウントで課金されないようにするには、Google Cloud プロジェクトを削除することをおすすめします。

Google Cloud コンソールで、次の手順を行います。

  1. メニュー アイコン ☰ > [IAM と管理] > [設定] をクリックします。

  1. [シャットダウン] をクリックします。
  2. プロジェクト ID を入力します。
  3. [このままシャットダウン] をクリックします。

407699a4e03afea6.png

Apps Script プロジェクトを削除する

Apps Script プロジェクトも削除することをおすすめします。

Apps Script コンソールで、次の手順を行います。

  1. プロジェクトを選択します。
  2. 操作メニューをクリックします。
  3. [削除] をクリックします。

fa3a42d7d2201eb9.png

12. 完了

これで完了です。Gemini を使用して Google Chat アプリを作成できました。

次のステップ

この Codelab ではシンプルなユースケースのみを紹介しましたが、Google Chat アプリはさまざまな形で拡張して使用できます。たとえば次のような例があります。

  • カスタムのものを含む他の生成 AI モデルと統合します。
  • 音声、画像、動画など、他の種類のメディアをサポートします。
  • マルチモダリティを使用します。
  • 長いコンテキスト ウィンドウとフィードバック ループを利用します。
  • 本番環境に対応した Google Chat アプリを Marketplace で公開します。YouTube 動画、ドキュメント ウェブサイト、コードサンプル、チュートリアルなど、さまざまなデベロッパー向けリソースがあります。
  • 組織向けに Google Chat を有効にします。インポート モード機能により、簡単に使い始められます。

詳細