GASでAI活用

GASでAI活用【Google Apps ScriptとLLMの連携】

GASとAIを組み合わせれば、Googleサービスの自動化がさらに進化します。

この記事では、Google Apps ScriptでAIを活用する方法を解説します。

1. GAS×AIでできること

活用例

用途 内容
データ分類 スプレッドシートのデータを自動分類
要約生成 長文を自動要約
メール下書き 定型メールを自動作成
問い合わせ対応 フォーム回答を自動処理
レポート生成 データから報告書を自動作成

利用できるAI

【Google AI】
・Gemini API(推奨)
・Vertex AI

【外部API】
・OpenAI API
・Anthropic API
・ローカルLLM(Ollama)

2. Gemini APIの利用

APIキーの取得

1. Google AI Studioにアクセス
   https://makersuite.google.com/
2. 「Get API key」をクリック
3. APIキーを生成
4. キーを安全に保管

基本的な呼び出し

JavaScript (GAS)
function callGemini(prompt) {
  const API_KEY = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
  const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${API_KEY}`;

  const payload = {
    contents: [{
      parts: [{
        text: prompt
      }]
    }]
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload)
  };

  const response = UrlFetchApp.fetch(url, options);
  const json = JSON.parse(response.getContentText());

  return json.candidates[0].content.parts[0].text;
}

// 使用例
function testGemini() {
  const result = callGemini("日本の首都は?");
  Logger.log(result);
}

APIキーの安全な管理

JavaScript (GAS)
// スクリプトプロパティに保存
function setApiKey() {
  PropertiesService.getScriptProperties().setProperty('GEMINI_API_KEY', 'your-api-key');
}

// 取得
function getApiKey() {
  return PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
}

3. スプレッドシート連携

テキスト分類

JavaScript (GAS)
function classifyTexts() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('データ');
  const data = sheet.getDataRange().getValues();

  for (let i = 1; i < data.length; i++) {
    const text = data[i][0];  // A列:テキスト

    if (text && !data[i][1]) {  // B列が空なら処理
      const category = classifyText(text);
      sheet.getRange(i + 1, 2).setValue(category);

      // API制限対策
      Utilities.sleep(1000);
    }
  }
}

function classifyText(text) {
  const prompt = `
以下のテキストを分類してください。
カテゴリ:問い合わせ、クレーム、要望、その他
1つだけ回答してください。

テキスト:${text}
`;

  return callGemini(prompt).trim();
}

要約の自動生成

JavaScript (GAS)
function summarizeColumn() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const lastRow = sheet.getLastRow();

  for (let i = 2; i <= lastRow; i++) {
    const originalText = sheet.getRange(i, 1).getValue();  // A列
    const summaryCell = sheet.getRange(i, 2);  // B列

    if (originalText && !summaryCell.getValue()) {
      const summary = summarizeText(originalText);
      summaryCell.setValue(summary);
      Utilities.sleep(1000);
    }
  }
}

function summarizeText(text) {
  const prompt = `以下の文章を50文字以内で要約してください:\n\n${text}`;
  return callGemini(prompt);
}

カスタム関数として使用

JavaScript (GAS)
/**
 * AIで要約を生成
 * @param {string} text 要約したいテキスト
 * @return {string} 要約結果
 * @customfunction
 */
function AI_SUMMARIZE(text) {
  if (!text) return '';

  const cacheKey = 'summary_' + Utilities.computeDigest(
    Utilities.DigestAlgorithm.MD5,
    text
  ).join('');

  const cache = CacheService.getScriptCache();
  const cached = cache.get(cacheKey);

  if (cached) return cached;

  const result = summarizeText(text);
  cache.put(cacheKey, result, 3600);  // 1時間キャッシュ

  return result;
}

4. メール自動処理

問い合わせメールの自動分類

JavaScript (GAS)
function classifyEmails() {
  const threads = GmailApp.search('label:問い合わせ is:unread', 0, 10);

  for (const thread of threads) {
    const message = thread.getMessages()[0];
    const subject = message.getSubject();
    const body = message.getPlainBody();

    const category = classifyInquiry(subject, body);

    // ラベルを付与
    const label = GmailApp.getUserLabelByName(category)
      || GmailApp.createLabel(category);
    thread.addLabel(label);

    // 分類結果をスプレッドシートに記録
    logClassification(subject, category);

    Utilities.sleep(1000);
  }
}

function classifyInquiry(subject, body) {
  const prompt = `
以下のメールを分類してください。
カテゴリ:見積依頼、技術相談、クレーム、その他

件名:${subject}
本文:${body.substring(0, 500)}

カテゴリ名のみ回答:
`;

  return callGemini(prompt).trim();
}

返信メールの下書き作成

JavaScript (GAS)
function createReplyDraft() {
  const threads = GmailApp.search('label:要返信 is:unread', 0, 5);

  for (const thread of threads) {
    const message = thread.getMessages()[0];
    const subject = message.getSubject();
    const body = message.getPlainBody();
    const from = message.getFrom();

    const replyText = generateReply(subject, body);

    // 下書きを作成
    thread.createDraftReply(replyText);

    Utilities.sleep(1000);
  }
}

function generateReply(subject, body) {
  const prompt = `
以下のメールに対する返信を作成してください。
丁寧なビジネスメールの形式で。

件名:${subject}
本文:${body.substring(0, 500)}

返信文:
`;

  return callGemini(prompt);
}

5. ドキュメント生成

議事録の自動生成

JavaScript (GAS)
function createMeetingMinutes() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('メモ');
  const memo = sheet.getRange('A1').getValue();

  const minutes = generateMinutes(memo);

  // Googleドキュメントを作成
  const doc = DocumentApp.create('議事録_' + Utilities.formatDate(new Date(), 'JST', 'yyyyMMdd'));
  doc.getBody().setText(minutes);

  // URLをスプレッドシートに記録
  sheet.getRange('B1').setValue(doc.getUrl());
}

function generateMinutes(memo) {
  const prompt = `
以下のメモから議事録を作成してください。

形式:
# 議事録
## 日時・参加者
## 議題
## 決定事項
## アクション項目

メモ:
${memo}
`;

  return callGemini(prompt);
}

報告書の自動生成

JavaScript (GAS)
function generateMonthlyReport() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('月次データ');
  const data = sheet.getDataRange().getValues();

  // データを整形
  const dataText = formatDataForAI(data);

  const report = generateReport(dataText);

  // スライドを作成
  const presentation = SlidesApp.create('月次報告_' + Utilities.formatDate(new Date(), 'JST', 'yyyyMM'));
  const slide = presentation.getSlides()[0];
  slide.getShapes()[0].getText().setText(report);
}

function formatDataForAI(data) {
  let text = '';
  const headers = data[0];

  for (let i = 1; i < data.length; i++) {
    for (let j = 0; j < headers.length; j++) {
      text += `${headers[j]}:${data[i][j]}\n`;
    }
    text += '\n';
  }

  return text;
}

function generateReport(dataText) {
  const prompt = `
以下のデータから月次報告のサマリーを作成してください。
3〜5行で簡潔にまとめてください。

データ:
${dataText}
`;

  return callGemini(prompt);
}

6. 実践的な活用例

フォーム回答の自動処理

JavaScript (GAS)
function onFormSubmit(e) {
  const responses = e.values;
  const name = responses[1];
  const inquiry = responses[2];

  // 問い合わせ内容を分析
  const analysis = analyzeInquiry(inquiry);

  // スプレッドシートに分析結果を追加
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const lastRow = sheet.getLastRow();
  sheet.getRange(lastRow, 4).setValue(analysis.category);
  sheet.getRange(lastRow, 5).setValue(analysis.urgency);
  sheet.getRange(lastRow, 6).setValue(analysis.summary);

  // 緊急の場合は通知
  if (analysis.urgency === '高') {
    sendUrgentNotification(name, inquiry, analysis);
  }
}

function analyzeInquiry(inquiry) {
  const prompt = `
以下の問い合わせを分析してください。
JSON形式で回答:
{
  "category": "カテゴリ(見積、技術、クレーム、その他)",
  "urgency": "緊急度(高、中、低)",
  "summary": "20文字以内の要約"
}

問い合わせ:${inquiry}
`;

  const result = callGemini(prompt);
  return JSON.parse(result);
}

定期レポートの自動送信

JavaScript (GAS)
function sendWeeklyReport() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('週次データ');
  const data = sheet.getDataRange().getValues();

  const reportText = generateWeeklyReport(data);

  // メール送信
  GmailApp.sendEmail(
    'manager@example.com',
    '週次レポート ' + Utilities.formatDate(new Date(), 'JST', 'yyyy/MM/dd'),
    reportText
  );
}

function generateWeeklyReport(data) {
  const dataText = formatDataForAI(data);

  const prompt = `
以下の週次データからレポートを作成してください。

形式:
1. 今週のサマリー(3行)
2. 主なトピック(箇条書き)
3. 来週の見通し

データ:
${dataText}
`;

  return callGemini(prompt);
}

// トリガー設定
function setWeeklyTrigger() {
  ScriptApp.newTrigger('sendWeeklyReport')
    .timeBased()
    .onWeekDay(ScriptApp.WeekDay.FRIDAY)
    .atHour(17)
    .create();
}

7. 注意点とベストプラクティス

API利用の注意

JavaScript (GAS)
// レート制限対策
function callGeminiWithRetry(prompt, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return callGemini(prompt);
    } catch (e) {
      if (i === maxRetries - 1) throw e;
      Utilities.sleep(2000 * (i + 1));  // 指数バックオフ
    }
  }
}

// キャッシュの活用
function callGeminiWithCache(prompt) {
  const cache = CacheService.getScriptCache();
  const cacheKey = Utilities.computeDigest(
    Utilities.DigestAlgorithm.MD5,
    prompt
  ).join('');

  const cached = cache.get(cacheKey);
  if (cached) return cached;

  const result = callGemini(prompt);
  cache.put(cacheKey, result, 3600);

  return result;
}

エラーハンドリング

JavaScript (GAS)
function safeCallGemini(prompt) {
  try {
    const result = callGemini(prompt);
    return { success: true, data: result };
  } catch (e) {
    Logger.log('API Error: ' + e.message);
    return { success: false, error: e.message };
  }
}

コスト管理

コスト削減のコツ
  • キャッシュを活用
  • プロンプトを短くする
  • 不要な呼び出しを避ける
  • バッチ処理でまとめる

8. まとめ

GAS×AIの活用パターン

活用パターン
  • スプレッドシートのデータ処理
  • メールの自動分類・返信
  • ドキュメントの自動生成
  • フォーム回答の分析
  • 定期レポートの作成

導入ステップ

1. Gemini APIキーを取得
2. 簡単な関数から試す
3. スプレッドシート連携
4. 自動化トリガーを設定

注意点

注意点
  • API制限を考慮
  • キャッシュを活用
  • エラーハンドリング
  • コスト管理

関連記事

お問い合わせ

GASとAIの連携についてのご相談は、お気軽にお問い合わせください。

お問い合わせはこちら

最終更新: 2025年1月