フォーム送信トリガー + Claude API 統合スクリプト
コピー
/**
* 問い合わせ受付 & 自動分類システム(完全版)
*
* 設定方法:
* 1. このスクリプトをスプレッドシートの Apps Script エディタに貼り付け
* 2. スクリプトプロパティに以下を設定:
* CLAUDE_API_KEY: sk-ant-xxxxxx
* MANAGER_EMAIL : 担当者のメールアドレス
* 3. setup() を一度実行してトリガーを設定する
*/
// ============ 設定 ============
const CATEGORY_LABELS = {
A: "材料問い合わせ",
B: "納期相談",
C: "新規見積もり",
D: "その他"
};
// ============ トリガー設定 ============
function setup() {
// フォーム送信時に自動実行するトリガーを設定
const ss = SpreadsheetApp.getActiveSpreadsheet();
ScriptApp.newTrigger('onFormSubmit')
.forSpreadsheet(ss)
.onFormSubmit()
.create();
Logger.log('トリガー設定完了');
}
// ============ メイン処理 ============
function onFormSubmit(e) {
const values = e.values;
// フォームの列順に合わせてデータを取得
const timestamp = values[0];
const company = values[1];
const name = values[2];
const email = values[3];
const inquiry = values[4];
const isUrgent = values[5] === "はい";
Logger.log(`新規問い合わせ: ${company} ${name}`);
// Step 1: Claude API でカテゴリ分類
const classification = classifyInquiry(inquiry);
// Step 2: 回答案を生成
const replyDraft = generateReplyDraft(
inquiry, classification.category, company, name
);
// Step 3: スプレッドシートに結果を書き込む
writeResultToSheet(
company, name, email, inquiry,
classification, replyDraft, isUrgent
);
// Step 4: 担当者に通知メールを送信
sendNotificationEmail(
company, name, email, inquiry,
classification, replyDraft, isUrgent
);
}
// ============ AI 分類 ============
function classifyInquiry(inquiry) {
const apiKey = PropertiesService.getScriptProperties()
.getProperty('CLAUDE_API_KEY');
if (!apiKey) return { category: 'D', reason: 'APIキー未設定', urgency: '中' };
const system = `銅・真鍮加工メーカー「石垣商店」の問い合わせ分類AIです。
以下のカテゴリに分類してJSON形式で回答してください。
A: 材料問い合わせ(在庫・規格・単価)
B: 納期相談(スケジュール・変更・急ぎ対応)
C: 新規見積もり(初回取引・見積依頼・加工仕様)
D: その他
{"category":"A","reason":"20字以内","urgency":"高/中/低"}`;
const options = {
method: "post",
headers: {
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
"content-type": "application/json"
},
payload: JSON.stringify({
model: "claude-3-5-haiku-20241022",
max_tokens: 256,
system: system,
messages: [{ role: "user", content: inquiry }]
}),
muteHttpExceptions: true
};
try {
const res = UrlFetchApp.fetch("https://api.anthropic.com/v1/messages", options);
const data = JSON.parse(res.getContentText());
if (data.error) return { category: 'D', reason: 'API エラー', urgency: '中' };
const text = data.content[0].text;
const match = text.match(/\{[\s\S]*\}/);
if (match) return JSON.parse(match[0]);
} catch(e) {
Logger.log('分類エラー: ' + e);
}
return { category: 'D', reason: '処理失敗', urgency: '中' };
}
// ============ 回答案生成 ============
function generateReplyDraft(inquiry, category, company, name) {
const apiKey = PropertiesService.getScriptProperties()
.getProperty('CLAUDE_API_KEY');
if (!apiKey) return '(APIキー未設定のため生成できませんでした)';
const system = `石垣商店の営業担当AIです。
${CATEGORY_LABELS[category]}の問い合わせへの返信案を150字以内で作成してください。
・丁寧なビジネスメール文体
・担当者が詳細確認後に改めてご連絡する旨を含める
・社名「株式会社石垣商店」を名乗る`;
const options = {
method: "post",
headers: {
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
"content-type": "application/json"
},
payload: JSON.stringify({
model: "claude-3-5-haiku-20241022",
max_tokens: 512,
system: system,
messages: [{ role: "user", content: `${company} ${name}様からの問い合わせ:\n${inquiry}` }]
}),
muteHttpExceptions: true
};
try {
const res = UrlFetchApp.fetch("https://api.anthropic.com/v1/messages", options);
const data = JSON.parse(res.getContentText());
if (!data.error) return data.content[0].text;
} catch(e) { Logger.log('回答案生成エラー: ' + e); }
return '(回答案の生成に失敗しました)';
}
// ============ スプレッドシート書き込み ============
function writeResultToSheet(company, name, email, inquiry, cls, reply, urgent) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName("処理結果");
if (!sheet) {
sheet = ss.insertSheet("処理結果");
sheet.appendRow(['受付日時','会社名','氏名','メール','問い合わせ','カテゴリ','緊急度','回答案','優先フラグ']);
}
sheet.appendRow([
new Date().toLocaleString('ja-JP'),
company, name, email, inquiry,
CATEGORY_LABELS[cls.category] || cls.category,
cls.urgency,
reply,
urgent || cls.urgency === '高' ? '★要対応' : ''
]);
}
// ============ 通知メール送信 ============
function sendNotificationEmail(company, name, email, inquiry, cls, reply, urgent) {
const TO = PropertiesService.getScriptProperties()
.getProperty('MANAGER_EMAIL');
if (!TO) { Logger.log('MANAGER_EMAIL 未設定'); return; }
const subject = `【石垣商店】${urgent ? '★急ぎ ' : ''}新規問い合わせ:${CATEGORY_LABELS[cls.category]} / ${company}`;
const body =
`新しいお問い合わせが届きました。
■ 送信者
会社名:${company}
お名前:${name}
メール:${email}
緊急 :${urgent ? 'はい' : 'いいえ'}
■ お問い合わせ内容
${inquiry}
■ AI 分類結果
カテゴリ:${CATEGORY_LABELS[cls.category]}
緊急度 :${cls.urgency}
判断理由:${cls.reason}
■ 回答案(AI 生成)
${reply}
--
このメールは自動送信です。
確認はスプレッドシート「処理結果」シートをご覧ください。`;
MailApp.sendEmail(TO, subject, body);
}
setup() を複数回実行するとトリガーが重複します。「Apps Script エディタ → トリガー(時計アイコン)」で不要なトリガーを削除してもらってください。フォーム列の順序がズレるとデータ取得が狂うので、values[0]=タイムスタンプ であることを必ず確認してください。