MENU

GAS×ChatGPTバッチ処理|大量データを一括処理する方法

GAS×ChatGPTバッチ処理|大量データを一括処理する方法

スプレッドシートに100件のデータがある。1件ずつChatGPTに入力していたら、それだけで半日が潰れる。

GASとChatGPT APIを組み合わせたバッチ処理なら、100件のデータもボタン1つで一括処理できる。API制限対策やコスト最適化も含めた実装方法を、コピペで動くコード付きで解説する。


目次

バッチ処理とは

バッチ処理の定義

バッチ処理とは、複数のデータをまとめて一括で処理する方式のことだ。

処理方式 説明
リアルタイム処理 1件ずつ即座に処理 Webフォーム送信
バッチ処理 複数件をまとめて処理 月末の給与計算

GASとChatGPTの組み合わせでは、スプレッドシートの複数行を順番にAPIへ送信し、結果を一括で書き戻す。これがバッチ処理にあたる。

なぜバッチ処理が必要か

1. 手作業の限界

件数 手作業(1件2分) バッチ処理
10件 20分 30秒
100件 3時間20分 3分
1,000件 33時間 30分

2. API制限への対処

ChatGPT APIにはレート制限がある。

プラン RPM(リクエスト/分) TPM(トークン/分)
無料 3 40,000
Tier 1 60 60,000
Tier 2以上 5,000+ 800,000+

バッチ処理で適切な待機時間を挟めば、レート制限を回避しながら安定して処理を進められる。

3. コスト最適化

一括処理すると、システムプロンプトの重複送信を減らせる。

処理方式 システムプロンプト コスト効率
1件ずつ(100回) 100回送信
バッチ処理 1回 + ループ

実装手順

事前準備

以下が必要になる。

  • Googleアカウント
  • OpenAI APIキー(取得方法
  • スプレッドシート(処理対象データ)

STEP 1: スプレッドシートを準備

A列 B列 C列
入力データ ステータス 出力結果
テキスト1
テキスト2

1行目はヘッダー行として使う。

STEP 2: GASスクリプトを作成

「拡張機能」→「Apps Script」で以下のコードを貼り付ける。


/**
 * GAS×ChatGPT バッチ処理スクリプト
 *
 * 機能:
 * - スプレッドシートのデータを一括でChatGPT APIに送信
 * - レート制限対策(待機時間)
 * - エラーハンドリング
 * - 進捗表示
 */

// ============================================
// 設定
// ============================================
const CONFIG = {
  SHEET_NAME: 'シート1',      // シート名
  INPUT_COL: 1,               // 入力列(A列=1)
  STATUS_COL: 2,              // ステータス列(B列=2)
  OUTPUT_COL: 3,              // 出力列(C列=3)
  START_ROW: 2,               // 開始行(ヘッダー除く)
  WAIT_MS: 1500,              // APIコール間の待機時間(ミリ秒)
  MODEL: 'gpt-4o-mini',       // 使用モデル
  MAX_TOKENS: 500,            // 最大トークン数
};

// ============================================
// メイン処理
// ============================================
function processBatch() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(CONFIG.SHEET_NAME);
  const lastRow = sheet.getLastRow();
  const apiKey = PropertiesService.getScriptProperties().getProperty('OPENAI_API_KEY');

  if (!apiKey) {
    SpreadsheetApp.getUi().alert('APIキーが設定されていません。\nスクリプトプロパティに OPENAI_API_KEY を設定してください。');
    return;
  }

  let processedCount = 0;
  let errorCount = 0;

  for (let row = CONFIG.START_ROW; row <= lastRow; row++) {
    const inputValue = sheet.getRange(row, CONFIG.INPUT_COL).getValue();
    const status = sheet.getRange(row, CONFIG.STATUS_COL).getValue();

    // 空行または処理済みはスキップ
    if (!inputValue || status === '完了') {
      continue;
    }

    // 処理中ステータスを設定
    sheet.getRange(row, CONFIG.STATUS_COL).setValue('処理中...');
    SpreadsheetApp.flush();

    try {
      // ChatGPT APIを呼び出し
      const result = callChatGPT(apiKey, inputValue);

      // 結果を書き込み
      sheet.getRange(row, CONFIG.OUTPUT_COL).setValue(result);
      sheet.getRange(row, CONFIG.STATUS_COL).setValue('完了');
      processedCount++;

    } catch (error) {
      // エラー処理
      sheet.getRange(row, CONFIG.STATUS_COL).setValue('エラー: ' + error.message);
      errorCount++;
      console.error(`Row ${row}: ${error.message}`);
    }

    // レート制限対策: 待機
    if (row < lastRow) {
      Utilities.sleep(CONFIG.WAIT_MS);
    }
  }

  // 完了通知
  SpreadsheetApp.getUi().alert(
    `処理完了\n\n` +
    `成功: ${processedCount}件\n` +
    `エラー: ${errorCount}件`
  );
}

// ============================================
// ChatGPT API呼び出し
// ============================================
function callChatGPT(apiKey, inputText) {
  const url = 'https://api.openai.com/v1/chat/completions';

  // プロンプトをカスタマイズ
  const systemPrompt = `あなたは優秀なアシスタントです。ユーザーの入力に対して簡潔に回答してください。`;

  const payload = {
    model: CONFIG.MODEL,
    messages: [
      { role: 'system', content: systemPrompt },
      { role: 'user', content: inputText }
    ],
    max_tokens: CONFIG.MAX_TOKENS,
    temperature: 0.7
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'Authorization': 'Bearer ' + apiKey
    },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };

  const response = UrlFetchApp.fetch(url, options);
  const responseCode = response.getResponseCode();
  const responseText = response.getContentText();

  if (responseCode !== 200) {
    const errorData = JSON.parse(responseText);
    throw new Error(errorData.error?.message || `HTTP ${responseCode}`);
  }

  const data = JSON.parse(responseText);
  return data.choices[0].message.content.trim();
}

// ============================================
// メニュー追加
// ============================================
function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('ChatGPT一括処理')
    .addItem('バッチ処理を実行', 'processBatch')
    .addItem('APIキーを設定', 'setApiKey')
    .addToUi();
}

// ============================================
// APIキー設定ダイアログ
// ============================================
function setApiKey() {
  const ui = SpreadsheetApp.getUi();
  const result = ui.prompt(
    'APIキー設定',
    'OpenAI APIキーを入力してください:',
    ui.ButtonSet.OK_CANCEL
  );

  if (result.getSelectedButton() === ui.Button.OK) {
    const apiKey = result.getResponseText().trim();
    if (apiKey) {
      PropertiesService.getScriptProperties().setProperty('OPENAI_API_KEY', apiKey);
      ui.alert('APIキーを保存しました。');
    }
  }
}

STEP 3: APIキーを設定

  • メニュー「ChatGPT一括処理」→「APIキーを設定」
  • OpenAI APIキーを入力
  • 「OK」をクリック

STEP 4: 実行

  • A列にデータを入力
  • メニュー「ChatGPT一括処理」→「バッチ処理を実行」
  • 完了を待つ

処理時間・コスト比較表

処理時間の目安

件数 待機時間1.5秒 待機時間1秒 待機なし
10件 20秒 15秒 5秒
50件 1分30秒 1分 25秒
100件 3分 2分 50秒
500件 15分 10分 4分

※API応答時間を約0.5秒として計算

APIコストの目安(gpt-4o-mini)

件数 入力(平均500トークン) 出力(平均200トークン) 合計コスト
10件 $0.00075 $0.0006 約$0.001
100件 $0.0075 $0.006 約$0.01
1,000件 $0.075 $0.06 約$0.14

gpt-4o-mini料金(2026年1月時点):

  • 入力: $0.15 / 100万トークン
  • 出力: $0.60 / 100万トークン

注意点と対策

1. レート制限(Rate Limit)

問題: APIを短時間に呼びすぎると制限がかかる。

対策:


// 待機時間を設定(推奨: 1〜2秒)
Utilities.sleep(1500);

エラー例と対処:


// 429エラー(Too Many Requests)の場合、リトライ
if (responseCode === 429) {
  Utilities.sleep(60000); // 1分待機
  // リトライ処理
}

2. 実行時間制限(6分)

問題: GASの実行時間は最大6分に制限されている。

対策: 大量データは分割して処理する。


function processBatchWithContinuation() {
  const props = PropertiesService.getScriptProperties();
  let startRow = parseInt(props.getProperty('BATCH_START_ROW')) || 2;
  const BATCH_SIZE = 50; // 1回の処理件数

  // 50件ずつ処理
  const endRow = Math.min(startRow + BATCH_SIZE - 1, lastRow);

  for (let row = startRow; row <= endRow; row++) {
    // 処理
  }

  if (endRow < lastRow) {
    // 次のバッチのために開始行を保存
    props.setProperty('BATCH_START_ROW', (endRow + 1).toString());

    // 1分後に再実行
    ScriptApp.newTrigger('processBatchWithContinuation')
      .timeBased()
      .after(60000)
      .create();
  } else {
    // 完了
    props.deleteProperty('BATCH_START_ROW');
  }
}

3. エラーハンドリング

リトライ付きの呼び出し例:


function callChatGPTWithRetry(apiKey, inputText, maxRetries = 3) {
  let lastError;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return callChatGPT(apiKey, inputText);
    } catch (error) {
      lastError = error;
      console.log(`Attempt ${attempt} failed: ${error.message}`);

      if (attempt < maxRetries) {
        // 指数バックオフで待機
        const waitTime = Math.pow(2, attempt) * 1000;
        Utilities.sleep(waitTime);
      }
    }
  }

  throw lastError;
}

4. コスト管理

使用量の監視:


// トークン数をログに記録
function logUsage(response) {
  const usage = response.usage;
  console.log(`Tokens - Input: ${usage.prompt_tokens}, Output: ${usage.completion_tokens}`);
}

OpenAIダッシュボードで月額上限を設定しておくと安心だ。


応用例

商品説明文の自動生成


const systemPrompt = `
あなたはECサイトのコピーライターです。
商品の特徴から、購買意欲を高める説明文を150字程度で作成してください。
`;

アンケート回答の分類


const systemPrompt = `
以下のアンケート回答を分類してください。
分類: ポジティブ / ネガティブ / 中立
形式: 分類名のみを回答
`;

メール文面の自動作成


const systemPrompt = `
以下の情報から、ビジネスメールの本文を作成してください。
丁寧で簡潔な文章にしてください。
`;

まとめ

バッチ処理のポイント

ポイント 内容
待機時間 1〜2秒の間隔を空ける
エラー処理 try-catchでエラーをキャッチ
進捗表示 ステータス列で進捗を可視化
分割処理 100件以上は分割実行

このスクリプトでできること

  • スプレッドシートの大量データを一括処理
  • API制限を回避しながら安定実行
  • エラーが発生しても他の行は継続処理
  • 処理状況をリアルタイムで確認

次のステップ


よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次