GASで売上データをAIで分析し
要点コメントを自動生成する方法
スプレッドシートの月次売上を集計し、Claude API(Anthropic社の対話AIをプログラムから呼び出す仕組み)に渡して、前月比や傾向を日本語のコメントで自動生成する方法を解説します。 前月比の計算はGAS側で行い、AIには「説明」だけを任せるのがポイントです。
Table of Contents
AIに売上コメントを任せると何が便利か
月次の売上表は作れても、「今月はどうだったか」を毎回コメントにまとめる作業は地味に手間です。 数字の増減を眺めて一言添えるだけでも、担当者の時間を奪います。ここをAIに任せると、集計と同時に要点コメントが付き、報告資料の下書きがそのまま出来上がります。
報告の下書きが自動化
前月比・傾向・注目点を日本語の文章にしてくれるので、月次報告の叩き台になる
見落としを拾える
数字を並べただけでは気づきにくい伸び・落ち込みを、AIが言葉にして指摘する
属人化を防ぐ
コメントの観点が一定になり、担当者が変わっても報告の質がぶれにくい
売上以外にも応用可
アクセス数・問い合わせ件数など、時系列の数値なら同じ仕組みで使える
ただし生成AIは複雑な計算が苦手です。前月比のような割合はGAS側で正確に計算し、AIには「渡した数値を使って傾向を説明する」役割だけを任せます。この分担が、事実と異なるコメントを防ぐ最大のコツです。
全体の処理の流れ
今回作るスクリプトは、次の5ステップで動きます。数値の準備をGASが担い、文章化だけをAIに任せる構成です。
明細を月ごとに集計
日付と金額の明細シートを読み、月単位の売上合計を求める
前月比を計算
直近3か月を取り出し、前月比(%)をGAS側で算出しておく
AIにコメント生成を依頼
集計済みの数値をプロンプトに埋め込み、Claude APIに送る
JSONで受け取る
要点・注目点・注意点を決まったJSON形式で返してもらう
シートに追記
月次サマリーシートに書き戻す。生成済みの月はスキップ
月ごとに売上を集計する
まずは「明細」シート(A列=日付、B列=金額)を読み、月単位の合計を作ります。getValues()で一括取得し、YYYY-MMをキーに合計していきます。
// 「明細」シート: A列=日付, B列=金額 を月ごとに合計する
function aggregateMonthlySales() {
const sheet = SpreadsheetApp.getActive().getSheetByName("明細");
const rows = sheet.getRange(2, 1, sheet.getLastRow() - 1, 2).getValues();
const totals = {}; // { "2026-05": 3200000, ... }
rows.forEach(([date, amount]) => {
if (!(date instanceof Date) || !amount) return;
const ym =
date.getFullYear() +
"-" +
String(date.getMonth() + 1).padStart(2, "0");
totals[ym] = (totals[ym] || 0) + Number(amount);
});
// 月順に並べた配列で返す
return Object.keys(totals)
.sort()
.map((ym) => ({ month: ym, total: totals[ym] }));
}日付が正しいDate型でない行や金額が空の行は、returnで読み飛ばしています。ここで表記ゆれや空行を弾いておくと、後段のコメントが安定します。
前月比はGASで計算しておく
コメントに前月比を入れたい場合、割合の計算はAIに任せず、必ずGAS側で行います。 直近3か月を取り出し、前月比(%)を添えた配列を作っておきます。
// 直近3か月を取り出し、前月比までGAS側で計算しておく
function buildRecentStats(monthly) {
const recent = monthly.slice(-3); // 直近3か月
return recent.map((cur, i) => {
const prev = recent[i - 1];
let growth = null;
if (prev && prev.total > 0) {
// 前月比(%)を小数第1位まで。計算はAIに任せない
growth = Math.round(((cur.total - prev.total) / prev.total) * 1000) / 10;
}
return {
month: cur.month,
total: cur.total,
growthPercent: growth, // 例: 12.5 / -4.3 / null
};
});
}比較対象がない最初の月はnullにしています。この「計算済みの数値」だけをAIに渡すことで、AIが数字を作り替える余地をなくします。
Claude APIにコメントを生成させる
集計済みの数値をプロンプトに埋め込み、UrlFetchApp(GASから外部APIを呼ぶ機能)でClaude APIに送ります。APIキーはスクリプトプロパティに保管し、コードに直書きしません。
function generateSalesComment(stats) {
const apiKey =
PropertiesService.getScriptProperties().getProperty("CLAUDE_API_KEY");
const prompt =
"あなたはECサイトの売上分析担当です。以下は月次売上の集計データです。\n" +
"数値の再計算はせず、渡した値だけを使って、経営者向けに要点を日本語で説明してください。\n" +
"growthPercentは前月比(%)です。nullは比較対象なしを意味します。\n\n" +
JSON.stringify(stats, null, 2) +
"\n\n次のJSON形式のみを返してください(前後に文章を付けない):\n" +
'{"summary":"全体の要点を2文以内","highlight":"最も注目すべき点を1文","caution":"注意点があれば1文、なければ空文字"}';
const res = UrlFetchApp.fetch("https://api.anthropic.com/v1/messages", {
method: "post",
contentType: "application/json",
headers: {
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
},
payload: JSON.stringify({
model: "claude-sonnet-4-5",
max_tokens: 600,
messages: [{ role: "user", content: prompt }],
}),
muteHttpExceptions: true,
});
if (res.getResponseCode() !== 200) {
throw new Error("API error: " + res.getContentText());
}
const text = JSON.parse(res.getContentText()).content[0].text;
return JSON.parse(extractJson(text));
}
// AIの返答から最初のJSON部分だけを取り出す保険
function extractJson(text) {
const start = text.indexOf("{");
const end = text.lastIndexOf("}");
return text.slice(start, end + 1);
}ポイントは3つです。プロンプトで「数値の再計算はしない」と明示すること、返答を決まったJSON形式に固定すること、そしてextractJson()でAIが前後に文章を付けても最初のJSONだけを取り出すことです。muteHttpExceptions: trueでエラー時も本文を読めるようにし、ステータスコードで失敗を検知します。
結果をシートに書き戻し二重生成を防ぐ
生成した要点・注目点・注意点を「月次サマリー」シートに追記します。 すでにその月のコメントが入っている場合はAPIを呼ばずにスキップし、無駄な呼び出しと二重記録を防ぎます。
// 「月次サマリー」シート: A列=月, B列=売上, C列=要点, D列=注目点, E列=注意点
function updateMonthlySummary() {
const monthly = aggregateMonthlySales();
const stats = buildRecentStats(monthly);
const target = stats[stats.length - 1]; // 最新月
const sheet = SpreadsheetApp.getActive().getSheetByName("月次サマリー");
const data = sheet.getDataRange().getValues();
// すでにコメント済みの月はスキップ(二重生成防止)
const done = data.some(
(row) => row[0] === target.month && row[2]
);
if (done) {
Logger.log(target.month + " は生成済みのためスキップ");
return;
}
const comment = generateSalesComment(stats);
sheet.appendRow([
target.month,
target.total,
comment.summary,
comment.highlight,
comment.caution,
]);
}コメント列(C列)が埋まっているかどうかで「生成済み」を判定しています。 手動でもう一度実行しても、同じ月のコメントが重複して追記されることはありません。
毎月1日のトリガーで自動化する
最後に、時間主導トリガー(決めた時刻に関数を自動実行する仕組み)を設定します。 毎月1日の朝に実行すれば、前月分のコメントが自動で追記されていきます。
// 毎月1日の午前8時に前月分のコメントを自動生成
function createMonthlyTrigger() {
ScriptApp.newTrigger("updateMonthlySummary")
.timeBased()
.onMonthDay(1)
.atHour(8)
.create();
}onMonthDay(1)で毎月1日を指定します。トリガーは一度作れば消すまで有効なので、この登録関数は初回に一度だけ実行してください。 APIキーが未設定だと実行時に失敗するため、先にスクリプトプロパティへ登録しておきます。
まとめ
GASとClaude APIを組み合わせると、月次売上の集計とコメント生成を一気通貫で自動化できます。 コツは、前月比などの計算をGAS側で正確に済ませ、AIには「渡した数値を使って傾向を日本語で説明する」役割に絞ること。 返答をJSONに固定し、生成済みの月をスキップすれば、毎月の報告資料の下書きが自動でたまっていきます。 売上以外の時系列データにもそのまま応用できます。
よくある質問
スプレッドシートから取り出した数値を、そのままJSON文字列やCSV風のテキストに整形してプロンプトに埋め込むのが簡単です。「2月: 320万円、3月: 410万円」のように単位付きで並べると、AIが前月比や増減の傾向を正しく読み取りやすくなります。桁区切りや通貨記号は付けても外しても構いませんが、統一しておくと安定します。
生成AIは複雑な計算が苦手なため、前月比などの割合はGAS側で計算してからプロンプトに含めるのが安全です。AIには「与えた数値を変えずに、傾向を日本語で説明する」役割に絞って依頼します。プロンプトで「数値の再計算はせず、渡した値のみを使う」と明示すると、事実と異なるコメントを減らせます。
できます。生成結果を書き込む列が空のときだけAIを呼び出すようにすれば、すでにコメントが入っている月はスキップされます。時間主導トリガーで毎月1日に実行するように設定すれば、前月分のコメントだけが自動で追記されていきます。
料金はモデルと送受信するトークン量で決まります。月次の集計値とコメント生成であれば1回あたりのテキスト量は少なく、月に一度の実行なら費用はごくわずかです。大量の明細をそのまま送るのではなく、GAS側で月ごとに集計してから渡すと、トークン量も精度も改善します。最新の料金は公式の料金ページで確認してください。
使えます。アクセス数・問い合わせ件数・在庫数など、時系列で並ぶ数値であれば同じ仕組みでコメントを生成できます。プロンプトの「何の数値か」「どんな観点でコメントしてほしいか」を対象に合わせて書き換えるだけで応用できます。
売上分析の自動化を
相談する。
売上・アクセス・問い合わせなどのデータ集計とAIコメント生成、月次レポートの自動化まで、GAS×AIの業務自動化をご相談いただけます。