Core Media Lab記事一覧
開発・インフラ

【コピペで動く】DifyのAPIをGASから叩いてスプレッドシート上でAI自動化する完全手順!

【コピペで動く】DifyのAPIをGASから叩いてスプレッドシート上でAI自動化する完全手順!

Googleスプレッドシートと生成AIを連携させて業務やメディア運営を効率化したいと考えたとき、多くの方は「GAS(Google Apps Script)からOpenAIのAPI(ChatGPT)を直接呼び出すスクリプト」を思い浮かべるはずです。

しかし、スクリプト内に長大なプロンプトを直書きしたり、複雑な条件分岐や複数回のLLM呼び出し(チェーン処理)をGASのコードだけで組もうとすると、すぐに次のような壁に突き当たります。

  • プロンプトを修正するたびにGASのエディタを開いてデプロイし直すのが面倒
  • Webスクレイピング結果の要約や独自ナレッジ(RAG)の参照をGAS単体で組むのは難易度が高すぎる
  • AIの回答生成に時間がかかり、GASの「実行時間6分制限」でタイムアウトエラー(Exceeded maximum execution time)が頻発する

これらの課題を一瞬で解決するのが、「自前のVPSで動くDify(ディファイ)に高度なAIワークフローを任せ、Googleスプレッドシート(GAS)からはシンプルなAPIを1本叩くだけ」という役割分担構成です。

本記事では、Dify側のAPI設定方法から、スプレッドシートからコピペで呼び出せるGASの実践スクリプト、そしてタイムアウトを防ぐ運用の工夫までをステップバイステップで徹底解説します。

なぜ「Dify × GAS」なのか?OpenAI API直叩きにはない3つの決定的な強み

GASからOpenAIやClaudeのAPIを直接叩く方式と比べ、間に「Dify」を挟むことには圧倒的な実務上のメリットがあります。

1. 複雑なAIワークフローをノーコードで組み、いつでも画面上で微調整できる

OpenAIのAPIを直叩きする場合、「入力テキストの整形 ➔ 検索 ➔ プロンプト適用 ➔ JSONフォーマット変換」といった一連の流れをすべてJavaScript(GAS)のコードで泥臭く書かなければなりません。

Difyを使えば、ブラウザ上のビジュアルキャンバスでノードを繋ぐだけで、「Web検索ノード」「LLMノード」「Pythonコードノード」「IF/ELSE条件分岐」を組み合わせた極めて高度なワークフローを構築できます。プロンプトやモデル(GPT-4o / Claude 3.5 Sonnet / Gemini等)を変更したいときも、GASのコードには一切手を触れず、DifyのWeb管理画面で修正して保存するだけで即座に反映されます。

2. 独自ドキュメント(RAG)やナレッジ検索を簡単にスプレッドシートへ組み込める

自社メディアの過去記事、製品仕様書、SEOマニュアルなどのPDFやテキストをDifyの「ナレッジ」にアップロードしておくだけで、GAS側から送ったキーワードに応じて関連情報を自動検索(RAG)し、それを踏まえた正確な記事ドラフトや回答をシート上に吐き出させることができます。これをGAS単体でゼロから実装するのはほぼ不可能です。

3. 自前VPSホストのDifyなら、クレジットやアプリ作成数の上限を気にせず回し放題

Dify Cloud(無料版)だとメッセージクレジット制限(200回)がありますが、格安VPSにDockerでセルフホストしたDifyを使えば、何千行のスプレッドシートデータをバッチ処理させてもDify側の利用料は0円(各LLMのAPI実費のみ)で済みます。

💡 まだ自前のDify環境を用意していない方はこちら:
月額1,000円前後の格安VPSを借りて、30分でDifyセルフホスト環境を立ち上げる全手順は以下の記事で詳しく解説しています。
👉 【脱・無料枠制限】Difyを格安VPSにセルフホスト構築する完全手順!Dockerで無制限AI環境を作る

Dify側の準備|APIキー発行とワークフロー型アプリのエンドポイント確認

GASから接続する前に、まずはDifyの管理画面側で「外部APIから呼び出すための準備」を整えます。

STEP 1:ワークフロー(またはチャットボット)を作成して公開する

  1. Difyのダッシュボードにログインし、「スタジオ」➔「最初から作成」をクリックします。
  2. アプリタイプとして「ワークフロー(Workflow)」を選択し、名前(例:記事構成自動生成ツール)を付けて作成します(単発のデータ入力に対して決まった形式のテキストを返す処理にはワークフロー型が最適です)。
  3. 「開始」ノードの入力フィールドに、スプレッドシートから受け取る変数を設定します(例:変数名 topic / タイプ: Paragraph)。
  4. 後続に「LLM」ノードを繋ぎ、モデルを選択してプロンプト(例:以下のテーマについてSEOに強い記事見出し案を作成してください:{{#sys.query#}} または {{#1729xxxx.topic#}})を設定します。
  5. 「終了」ノードに出力変数を設定したら、画面右上の「公開する」➔「更新」をクリックしてワークフローを本番稼働状態にします。

STEP 2:APIアクセスを有効化し「API Secret Key」を発行する

ワークフローを公開したら、左側メニューの「APIアクセス」をクリックします。

  1. 画面右上の「APIキー」ボタンをクリックし、「新しいキーを作成」を押します。
  2. 生成されたシークレットキー(例:app-xxxxxxxxxxxxxxxxxxxxxxxx)をコピーしてメモ帳などに控えておきます(このキーはGAS側で認証ヘッダーとして使用します)。
  3. 画面に表示されている「APIサーバー」のベースURLを確認します。
    自前VPS環境の場合、エンドポイントは通常以下の形式になります。
    http://あなたのVPSのIPアドレス/v1/workflows/run
    (※ドメインとSSLを設定している場合は https://dify.example.com/v1/workflows/run)
⚠️ セキュリティ上の注意点:
APIキーはOpenAIキーと同様に機密情報です。スプレッドシートのセル内に直接平文で書くのではなく、GASの「スクリプトプロパティ」に保存してコードから呼び出すのが安全なベストプラクティスです。

【実践】コピペで動く!スプレッドシートからDify APIを叩くGAS完全コード

ここからは、実際にGoogleスプレッドシートの「拡張機能」➔「Apps Script」を開き、DifyのワークフローAPIを呼び出して結果をセルに自動出力する実装手順を解説します。

STEP 1:スクリプトプロパティに「APIキー」と「エンドポイントURL」を安全に保存する

コード内にAPIキーを直接ハードコーディングするのを防ぐため、まずはGASのプロジェクト設定に認証情報を登録します。

  1. Apps Scriptエディタ左側の歯車アイコン「プロジェクトの設定」をクリックします。
  2. 一番下にある「スクリプト プロパティ」セクションで「スクリプト プロパティを追加」をクリックし、以下の2つを登録して保存します。
プロパティ(キー名) 設定する値(例)
DIFY_API_KEY app-xxxxxxxxxxxxxxxxxxxxxxxx(Difyで発行したシークレットキー)
DIFY_API_URL https://あなたのドメイン/v1/workflows/run(またはIPアドレスのURL)

STEP 2:DifyワークフローAPIを呼び出す基本関数(UrlFetchApp)

Apps Scriptの「コード.gs」を開き、以下のコードをそのままコピー&ペーストしてください。

このスクリプトには、① DifyのAPIを叩くコア関数(callDifyWorkflow)と、② スプレッドシートの未処理行を一括処理するバッチ関数(runSheetBatch)、そして③ スプレッドシート上部に専用メニューボタンを追加する関数(onOpen)のすべてが含まれています。

/**
 * スプレッドシートを開いたときにカスタムメニューを追加
 */
function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu('🚀 Dify自動生成')
    .addItem('未処理の行を一括AI生成する', 'runSheetBatch')
    .addToUi();
}

/**
 * DifyのワークフローAPIを呼び出すコア関数(blockingモード)
 * @param {string} topicInput - Difyの開始ノード変数「topic」に渡すテキスト
 * @return {string} Difyの終了ノード変数「result」から返ってきたテキスト
 */
function callDifyWorkflow(topicInput) {
  const props = PropertiesService.getScriptProperties();
  const apiKey = props.getProperty('DIFY_API_KEY');
  const apiUrl = props.getProperty('DIFY_API_URL');

  if (!apiKey || !apiUrl) {
    throw new Error('スクリプトプロパティに DIFY_API_KEY または DIFY_API_URL が設定されていません。');
  }

  // DifyのWorkflow API仕様に合わせたリクエストボディ
  const payload = {
    inputs: {
      // ★Difyの「開始」ノードで設定した変数名(例: topic)と一致させる
      topic: topicInput
    },
    response_mode: 'blocking',
    user: 'gas-spreadsheet-bot'
  };

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

  const response = UrlFetchApp.fetch(apiUrl, options);
  const statusCode = response.getResponseCode();
  const responseText = response.getContentText();

  if (statusCode !== 200) {
    throw new Error('Dify APIエラー (HTTP ' + statusCode + '): ' + responseText);
  }

  const json = JSON.parse(responseText);

  // ★Difyの「終了」ノードで定義した出力変数名(例: result または text)を取得
  if (json.data && json.data.outputs) {
    return json.data.outputs.result || json.data.outputs.text || JSON.stringify(json.data.outputs);
  } else {
    throw new Error('Difyからのレスポンス形式が想定外です: ' + responseText);
  }
}

/**
 * シートのA列(キーワード/入力)を読み取り、B列に生成結果、C列にステータスを書き込む
 */
function runSheetBatch() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const lastRow = sheet.getLastRow();
  if (lastRow < 2) return;

  // 2行目から最終行までのA〜C列を取得(A:入力, B:出力結果, C:状態)
  const range = sheet.getRange(2, 1, lastRow - 1, 3);
  const values = range.getValues();

  // GASの6分制限を防ぐため、起動時刻を記録(4分30秒経過で安全に中断)
  const startTime = new Date().getTime();
  const maxExecutionTimeMs = 4.5 * 60 * 1000;

  for (let i = 0; i < values.length; i++) {
    const rowNumber = i + 2;
    const inputTopic = String(values[i][0]).trim();
    const currentStatus = String(values[i][2]).trim();

    // 入力が空、またはすでに「完了」している行はスキップ
    if (!inputTopic || currentStatus === '完了') {
      continue;
    }

    // 経過時間をチェックし、4分30秒を超えていたら安全にループを終了
    if (new Date().getTime() - startTime > maxExecutionTimeMs) {
      Logger.log('安全制限時間(4分30秒)に達したため、一時中断しました。次回実行時に続きから再開します。');
      break;
    }

    try {
      sheet.getRange(rowNumber, 3).setValue('処理中...');
      SpreadsheetApp.flush();

      // Dify APIを呼び出して結果をB列に書き込み
      const aiOutput = callDifyWorkflow(inputTopic);
      sheet.getRange(rowNumber, 2).setValue(aiOutput);
      sheet.getRange(rowNumber, 3).setValue('完了');
      SpreadsheetApp.flush();

      // APIの連続負荷を抑えるため1秒待機
      Utilities.sleep(1000);
    } catch (e) {
      sheet.getRange(rowNumber, 3).setValue('エラー: ' + e.message);
    }
  }
}

STEP 3:スプレッドシートの準備とワンクリック実行

コードを保存したら、スプレッドシートの画面に戻ってページを再読み込みしてください。

  1. シートの1行目(見出し)に、A列:キーワード・指示、B列:Dify生成結果、C列:ステータス と入力します。
  2. 2行目以降のA列に、処理させたいテーマや長文テキストを入力します。
  3. 画面上部のメニューバーに出現した「🚀 Dify自動生成」➔「未処理の行を一括AI生成する」をクリックします(初回のみGoogleアカウントの権限承認画面が出るので許可してください)。

これだけで、C列が「処理中...」➔「完了」とリアルタイムに変わりながら、B列にDifyが生成した高品質なテキストが次々と自動で書き込まれていきます。

💡 さらに自動化を進めるなら(microCMSへのワンクリック入稿):
Difyでスプレッドシート上に生成した記事HTMLを、そのままヘッドレスCMS(microCMS)へボタン1つで自動入稿する連携コードは以下の記事で公開しています。
👉 【脱コマンド】GoogleスプレッドシートからmicroCMSへワンクリック自動入稿する完全手順(GASコード付き)

GASの「6分制限」とDifyタイムアウトを回避する実務テクニック

「Dify × GAS」を実務で安定稼働させるうえで、必ず知っておくべき2つの技術的な制限と、その回避策を解説します。

1. 1回の処理が長い場合は「blocking」ではなく分割設計にする理由

DifyのAPIには、処理がすべて終わってから一括でJSONを返す blocking(ブロッキングモード) と、生成された文字を端から少しずつ返す streaming(ストリーミングモード) の2種類があります。

GASの UrlFetchApp.fetch() は仕様上、ストリームの逐次受信に対応しておらず、かつ「1回のHTTPリクエストの最大待機時間は約60秒〜360秒、またCloudflare等のプロキシを経由している場合は100秒でゲートウェイタイムアウト(HTTP 504)になる」という制限があります。

したがって、1つのDifyワークフローの中にLLMノードを5個も6個も直列に繋いで「1回の実行に2分以上かかる巨大フロー」を作ってしまうと、通信が途中で切れてしまいます。長文記事を作る場合は以下のように分割するのが鉄則です。

  • Difyワークフロー①(構成・前半生成): 30秒〜50秒以内で完了させ、シートのB列に出力する
  • Difyワークフロー②(後半・まとめ生成): B列の結果を入力として受け取り、C列に後半を出力する

2. 大量行のバッチ処理は「4分30秒の安全ブレーキ」またはVPS側への移行で解決

先ほど紹介した runSheetBatch() のコードには、あらかじめ「開始から4分30秒が経過したらループを安全に止めるブレーキ処理(maxExecutionTimeMs)」を組み込んであります。

これにより、たとえば100行分のデータを一気に処理させても、GASの「6分制限」で強制クラッシュすることなく、完了した行には「完了」フラグが記録されます。あとはGASの「時間主導型トリガー(10分おきに実行など)」をセットしておくだけで、未処理の行だけをバトンリレー形式で最後まで自動完走させることができます。

もし「トリガーで小分けに待つのではなく、数十分かかる重いバッチ処理を1回で一気に終わらせたい!」という場合は、Difyが動いているVPS上にPythonスクリプトやn8nを同居させ、VPS側からGoogle Sheets APIを直接操作する構成へステップアップするのが最もスマートです。

💡 あわせて読みたい(GASの制限突破&n8n連携ガイド):
・【脱・6分制限】GASの「実行時間エラー」を根本解決!重い定期処理をVPS×Pythonへ逃がすハイブリッド自動化術
・【脱Zapier】n8nを格安VPSにDocker構築する完全手順!タスク無制限のAPI自動化基盤を作る

まとめ:スプレッドシートを最強のAI作業ダッシュボードに進化させよう

本記事では、Googleスプレッドシート(GAS)から自前DifyのワークフローAPIを呼び出し、シート上でAI自動生成を行う完全手順を解説しました。

  • プロンプト管理とロジックをDifyに分離: GASのコードを汚さず、ブラウザ上のノーコード画面でいつでもAIモデルやRAG、プロンプトを改善できる。
  • スクリプトプロパティと UrlFetchApp で安全連携: APIキーを安全に隠蔽しつつ、コピペコードだけでシート上の未処理行を一括処理できる。
  • タイムアウト対策も万全: 1ワークフロー60秒以内を目安に設計し、GAS側の「4分30秒ブレーキ+完了フラグ管理」を使うことで、6分制限エラーを完全に回避できる。

いつも使い慣れているGoogleスプレッドシートに「自前VPS上のDify」という頭脳を接続すれば、キーワード整理から記事ドラフト作成、データ分類まであらゆるルーティン業務がワンクリックで完結するようになります。ぜひ今日からあなたのシートに組み込んでみてください。

🚀 【2026年最新】Dify・自動化におすすめの国内VPS 3選を比較する