はじめに:導入事例のご紹介

2024年6月14日に株式会社第一興商様のGoogle Cloud導入事例を公開しました!

生成 AI の活用で DX 促進! Google Cloud と Gemini で人的リソースのかかる集計業務を大幅改善。アイレットでは、デザインからシステム設計・開発、クラウドを活用したインフラ設計・構築・運用監視にいたるまで、あらゆる側面からサービスをご提供し、お客様の課...

本事例では楽曲リクエストデータの確認、集計作業を効率化するために、Google スプレッドシート上でGAS(Google App Script)からGeminiを呼び出してデータの名寄せ処理を行い、Looker Studioでクレンジングされたデータを見える化し、お客様の編成業務の効率化をご支援しました。

また、Google検索を利用して最新情報も加味しながらGeminiに推論を行わせるためにGrounding with Google Search in Vertex AIも利用しています。

本記事では事例のように、Google スプレッドシートとGeminiを組み合わせて手軽に生成AIモデルを活用する方法について解説します。

GASを使ったVertex AI Geminiの呼び出し方

サンプルとして、書籍の一覧からあらすじを生成するGASを作ってみます。

事前にVertex AIが利用できるGoogle Cloudプロジェクト用意し、そのプロジェクトへのアクセス権があるGoogleアカウントで手順を実行してください。

スプレッドシートを新規作成し、「拡張機能」>「App Script」からスクリプトエディタを開きます。

「プロジェクトの設定」から「appsscript.json」マニフェスト ファイルをエディタで表示する」にチェックを入れます。
「スクリプト プロパティ」に以下の3つを設定します。

  • model_id : gemini-1.5-flash-001
  • project_id : 利用するGoogle CloudプロジェクトID
  • project_location : 利用リージョン(asia-east1など)

次に「エディタ」を開き、「appsscript.json」を下記のように編集しGASの必要とする権限を与えます。

{
  "timeZone": "Asia/Tokyo",
  "dependencies": {
  },
  "exceptionLogging": "STACKDRIVER",
  "oauthScopes": [
    "https://www.googleapis.com/auth/spreadsheets.currentonly",
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/cloud-platform"
  ],
  "runtimeVersion": "V8"
}

「コード.gs」にボタン押下のイベントを受ける関数とGeminiを呼び出して結果を受け取る関数を記述します。

const PROJECT_ID = PropertiesService.getScriptProperties().getProperty('project_id');
const VERTEX_AI_LOCATION = PropertiesService.getScriptProperties().getProperty('project_location');
const MODEL_ID = PropertiesService.getScriptProperties().getProperty('model_id');

/**
 * ボタンのイベントで処理を実行
 */ 
function btnGemini() {
  // アクティブシートを取得
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();

  // A2より下のセルを取得
  const range = sheet.getRange('A2:A' + sheet.getLastRow());
  const values = range.getValues();

  for (let i = 0; i < values.length; i++) {
    let cellValue = values[i][0];
    if (cellValue) {  // 値が存在する場合
      // プロンプトを作成
      let prompt = `
${cellValue}:この書籍のあらすじを教えてください。
注意事項:書式設定は使用しないでください。
すべてのマークダウンを削除してください。
`;

      // Geminiへの問い合わせ
      let response = getAiSummary(prompt);

      // 隣のセルに結果をセット
      sheet.getRange(i + 2, 2).setValue(response);
    }
  }
}

/**
 * Geminiへの問い合わせ
 */
function getAiSummary(prompt) {

  let request = {
    "contents": [{
      "role": "user",
      "parts": [{
        "text": prompt
      }]
    }],
    tools: [
      {
        // Google検索による根拠づけ
        googleSearchRetrieval: {
          disableAttribution: false,
        },
      },
    ],
    "generationConfig": {
      "temperature": 0,
      "maxOutputTokens": 2048,
    },
    "safetySettings": [
      {
        "category": "HARM_CATEGORY_HARASSMENT",
        "threshold": "BLOCK_NONE"
      },
      {
        "category": "HARM_CATEGORY_HATE_SPEECH",
        "threshold": "BLOCK_NONE"
      },
      {
        "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
        "threshold": "BLOCK_NONE"
      },
      {
        "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
        "threshold": "BLOCK_NONE"
      }
    ]
  };

  let url = `https://${VERTEX_AI_LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/`
  + `locations/${VERTEX_AI_LOCATION}/publishers/google/models/${MODEL_ID}:generateContent`;
  let fetchOptions = {
    method: 'post',
    headers: {
      'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
    },
    contentType: 'application/json',
    payload: JSON.stringify(request)
  };

  const response = UrlFetchApp.fetch(url, fetchOptions);

  const payload = JSON.parse(response);
  const text = payload.candidates[0].content.parts[0].text;

  return text;
}

あとはこのようなシートを作り、「挿入」>「図形描画」からボタンに見立てたオブジェクトを作ります。
オブジェクトに「スクリプトを割り当て」し、作ったbtnGemini関数を割り当てれば完成です。

こちらのように、「Geminiを実行」ボタンを押すことで本のあらすじが生成されるはずです。
※初回Googleの認証を求めるダイアログが立ち上がるので許可してください。

カスタム関数を使う

ボタンではなくカスタム関数を使って、SUMなどの組み込み関数のように利用することもできます。
先程のコードに追記、修正を行って保存します。

// 〜省略〜

/**
 * Geminiに指定範囲のセルの情報とプロンプトを送信し、回答を得る
 * @param {range} セル範囲
 * @param {string} プロンプト
 * @return Geminiの回答
 * @customfunction
 */
function gemini(range, prompt) {
  apiKey = PropertiesService.getScriptProperties().getProperty('api_key');
  prompt = `参考情報: ${range}、次の質問に答えてください: ${prompt}。注意事項:書式設定は使用しないでください。すべてのマークダウンを削除してください。`
  return getAiSummary(prompt, apiKey);
}

/**
 * Geminiへの問い合わせ
 */
function getAiSummary(prompt, apiKey=null) {

// 〜省略〜

  let url;
  let fetchOptions;
  if(!apiKey){
    // ボタン用
    url = `https://${VERTEX_AI_LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/`
    + `locations/${VERTEX_AI_LOCATION}/publishers/google/models/${MODEL_ID}:generateContent`;
    fetchOptions = {
      method: 'post',
      headers: {
        'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
      },
      contentType: 'application/json',
      payload: JSON.stringify(request)
    };
  }else{
    // 関数用
    url = `https://generativelanguage.googleapis.com/v1beta/models/${MODEL_ID}:generateContent?key=${apiKey}`;
    delete request.tools; // Google検索による根拠づけは非対応
    fetchOptions = {
      method: 'post',
      contentType: 'application/json',
      muteHttpExceptions: false,
      payload: JSON.stringify(request)
    };
  }

  const response = UrlFetchApp.fetch(url, fetchOptions);

  const payload = JSON.parse(response);
  const text = payload.candidates[0].content.parts[0].text;

  return text;
}

「スクリプト プロパティ」に追加で「api_key」を設定します。
設定する文字列はこちらから取得してください。
カスタム関数では「ScriptApp.getOAuthToken()」による認証が使えなかったのでこのようにしています。

このように自由にセルのデータとプロンプトを渡せる関数が作れました。
例では市町村の一部の情報から都道府県を返却させています。
ファジーな入力をうまく吸収してくれるのがLLMの便利なところですね。

注意点

注意点としてモデルには1分あたりのリクエスト数制限が設けられているため大量のセルの情報を一度に扱う必要がある場合はGASの処理の組み方に注意が必要です。
※ユースケースを説明することで緩和の申請を行うこともできます。


このように手軽に実施できて、Google スプレッドシートとVertex AI Geminiの組み合わせは第一興商様のようにアイデア次第で色々なことができる可能性を秘めてることがわかっていただけたかと思います。
アイレットではこのようなGWS(Google Workspace)を組み合わせた業務ツール提案、開発のご支援も承っておりますのでぜひお気軽にご相談ください!