🐧

全文取得したZenn記事に対して、GPT-4oで概要を出力する

2024/08/28に公開

Google App Script(GAS)を使って、全文取得したZenn記事に対して、GPT-4oで概要を出力してみます。
やりたいことのイメージは下記のようなかんじです。

最初にAPIキーと最大試行回数を設定します。
APIキーは、OpenAIのAPIのサイトでアカウントを作って取得してください。
最大試行回数は、OpenAIのAPIが失敗したときの再試行回数です。
1分間あたりの制限があるようで、最大試行回数を決めて再試行する作りにしています。

// OpenAI APIキーを設定します(実際のキーに置き換えてください)
const OPENAI_API_KEY = 'XXX';
const MAX_RETRIES = 3; // 最大再試行回数

処理対象はシート「Detail」となります。
各行ごとにGPT-4oで概要を出力してもらいます。
GASの実行時間が6分ほどでタイムアウトで中断するので、処理が完了したらフラグを「Y」と設定するように実装しています。また、再実行も考慮してフラグが「Y」の行は実行対象外としています。

function summarizeArticles() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Detail");  // Detailを使用
  
  // データを取得(A1セルから開始)
  var data = sheet.getDataRange().getValues();
  var headers = data.shift();  // ヘッダー行を除去
  
  // 必要な列のインデックスを見つける
  var summaryIndex = headers.indexOf("記事概要");
  var flagIndex = headers.indexOf("要約完了フラグ");
  if (summaryIndex === -1 || flagIndex === -1) {
    throw new Error("必要な列(記事概要または要約完了フラグ)が見つかりません。");
  }
  
  // 各記事を処理
  for (var i = 0; i < data.length; i++) {
    var row = data[i];
    var url = row[0];
    var title = row[2];  // タイトルは3列目(インデックス2)にあると仮定
    var content = row[3];  // 記事全文は4列目(インデックス3)にあると仮定
    var flag = row[flagIndex];
    
    // 要約完了フラグがYでない場合のみ処理
    if (flag !== "Y" && content && content.trim() !== "") {
      var retries = 0;
      while (retries < MAX_RETRIES) {
        try {
          var summary = generateSummary(title, content);
          // 「記事概要」列に要約を書き込む
          sheet.getRange(i + 2, summaryIndex + 1).setValue(summary);
          // 「要約完了フラグ」列に"Y"を書き込む
          sheet.getRange(i + 2, flagIndex + 1).setValue("Y");
          Logger.log("Summarized article: " + url);
          break; // 成功したらループを抜ける
        } catch (e) {
          retries++;
          Logger.log("Error summarizing article " + url + ": " + e.toString() + ". Retry " + retries + " of " + MAX_RETRIES);
          if (retries < MAX_RETRIES) {
            Utilities.sleep(60000); // 1分間待機
          } else {
            sheet.getRange(i + 2, summaryIndex + 1).setValue("Error after " + MAX_RETRIES + " retries: " + e.toString());
            // エラーの場合でも「要約完了フラグ」列に"Y"を書き込まない
          }
        }
      }
    } else if (flag === "Y") {
      Logger.log("Skipped already summarized article: " + url);
    }
  }
  
  Logger.log("Summarization completed.");
}

GPT-4oに記事全文を送り、記事概要を取得するFunctionです。

function generateSummary(title, content) {
  var prompt = `記事のタイトル:${title}\n\n記事の内容:${content}\n\n上記の記事を150文字で要約してください。`;
  
  var requestBody = {
    model: "gpt-4o-2024-08-06",  // GPT-4モデルを使用
    messages: [
      {role: "system", content: "あなたは記事の要約を作成する専門家です。「記事では」といった前置きは書かずに簡潔に150文字で要約します。記事の執筆者の名前は書かない。"},
      {role: "user", content: prompt}
    ],
    max_tokens: 180,  // 最大トークン数を制限(およそ180文字に相当)
    temperature: 0.7
  };
  
  var options = {
    method: 'post',
    headers: {
      'Authorization': 'Bearer ' + OPENAI_API_KEY,
      'Content-Type': 'application/json'
    },
    payload: JSON.stringify(requestBody)
  };
  
  var response = UrlFetchApp.fetch('https://api.openai.com/v1/chat/completions', options);
  var responseData = JSON.parse(response.getContentText());
  
  return responseData.choices[0].message.content.trim();
}

結果、このように記事概要が出力されました。

Accenture Japan (有志)

Discussion