📅「LINEに話すだけ」で予定管理!ChatGPT × GAS × Googleカレンダーで作る秘書ボット
📖 1. はじめに
この記事では、ChatGPT API と Google Apps Script(以下 GAS)、LINE Messaging API を組み合わせて、「会話だけで予定管理ができる秘書ボット」を作成します。
こんなことができます
- LINEで「明日の10時に美容院」と送るだけで、Googleカレンダーに予定登録
- 「明日の予定教えて」で予定を確認
- 「明日の予定キャンセルして」で削除
📃 2. 使用技術と準備
使った技術
- Google Apps Script (GAS)
- OpenAI ChatGPT API (gpt-4o-mini)
- Googleカレンダー (CalendarApp)
- LINE Messaging API (Webhook と reply)
必要なもの
- OpenAI APIキー
- LINEのアカウント
- Googleアカウント
⚖️ 3. 構成図と構成概要
- LINE が入力受付、返信を担当
- GAS がロジックコントローラー
- ChatGPT が自然言語を構造化
- Googleカレンダー が予定の登録先
⚙️ 4. 実装手順
この秘書ボットは、LINE・ChatGPT・Googleカレンダー・GAS の4つを連携させて構築します。
4-1. LINE Botを作成しWebhook URLを設定
- LINE Developers Console にアクセス
- プロバイダーを作成(なければ新規作成)
- 「Messaging API」を選択してチャネルを作成
- チャネル作成後、以下を設定:
- Webhook送信 → オン
- 応答メッセージ → オフ
- Webhook URL → 後ほど作成する GAS の WebアプリURLを貼る
- チャネルアクセストークンを控える(GAS内で使う)
4-2. Google Apps Script(GAS)でWebアプリを作成
- Google Apps Script にアクセス
- 新規プロジェクトを作成し、以下のような構成で記述:
function doPost(e) {
const json = JSON.parse(e.postData.contents);
const replyToken = json.events[0].replyToken;
const userMessage = json.events[0].message.text;
const replyText = runSchedulerBot(userMessage); // 本体ロジック
UrlFetchApp.fetch("https://api.line.me/v2/bot/message/reply", {
method: "post",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + LINE_ACCESS_TOKEN
},
payload: JSON.stringify({
replyToken: replyToken,
messages: [{ type: "text", text: replyText }]
})
});
return ContentService.createTextOutput("OK");
}
-
runSchedulerBot() 関数
では、ChatGPT API とのやりとり・Googleカレンダー操作などの処理を実装(後述) -
「デプロイ」→「新しいデプロイ」→「Webアプリ」
- アクセス権は「全員(匿名ユーザー含む)」に設定
- 発行されたURLを LINE の Webhook に登録
4-3. 現在の日時を取得して基準にする
ここからはrunSchedulerBot関数
の解説を行います。
この関数は、LINEやスプレッドシートからの入力メッセージ(userMessage
)をもとに、ChatGPTに問い合わせ、予定の登録・確認・削除を行う本体ロジックです。
まず、GPT に「今が何年何月何日か」を伝えるため、現在時刻を取得してプロンプト内に組み込みます。
function runSchedulerBot(userMessage) {
const now = new Date();
const nowStr = Utilities.formatDate(now, Session.getScriptTimeZone(), "yyyy/MM/dd HH:mm");
<--- 省略 --->
}
function formatDate(date) {
return Utilities.formatDate(date, Session.getScriptTimeZone(), "yyyy/MM/dd HH:mm");
}
これにより、GPTが「明日」「今週末」などの相対表現を正しく解釈できるようになります。
4-4. ChatGPT へのプロンプト設計
次に、GPT に対して期待する出力形式を指示する プロンプト を組み立てます。
以下は簡略化したプロンプトです。
const systemPrompt = `
現在の日時は ${nowStr} です。
これを基準に、「明日」「来週」「◯月◯日」などを正確に解釈してください。
【出力フォーマット】
#操作
登録 / 削除 / 確認 のいずれか
#返答
秘書らしい丁寧な文章
#期間(確認時は必須)
開始: YYYY/MM/DD HH:mm
終了: YYYY/MM/DD HH:mm
#予定(登録・削除時は必須)
タイトル: ○○
開始: YYYY/MM/DD HH:mm
終了: YYYY/MM/DD HH:mm
`;
-
#操作
によって処理の種別を判断 -
#予定
はタイトル
,開始
,終了
を明示 -
#期間
(確認時)も ChatGPT に指示して含めさせます
✅ 登録・削除の操作では
#予定
ブロックが 必須 です。プロンプト内に明記。
4-5. Webhook処理
systemPrompt
と userMessage
を gpt-4o-mini
に送信し、応答を取得します。
const requestOptions = {
method: "post",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + OPENAI_API_KEY
},
payload: JSON.stringify({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: userMessage }
]
})
};
const gptResponse = UrlFetchApp.fetch("https://api.openai.com/v1/chat/completions", requestOptions);
const json = JSON.parse(gptResponse.getContentText());
const replyText = json.choices[0].message.content.trim();
4.6 ChatGPT の出力を解析して処理を分岐
ChatGPT の出力から、以下のブロックを正規表現で抽出します。
const operationMatch = replyText.match(/#操作\s*([\s\S]*?)#返答/);
const responseMatch = replyText.match(/#返答\s*([\s\S]*?)(#期間|#予定)/);
const periodMatch = replyText.match(/#期間\s*([\s\S]*?)($|#予定)/);
const scheduleMatch = replyText.match(/#予定\s*([\s\S]*)/);
抽出した内容をもとに、操作種別と返答文を決定します。
let operation = "登録";
let userMessageFormatted = "";
if (operationMatch) {
operation = operationMatch[1].trim();
}
if (responseMatch) {
userMessageFormatted = responseMatch[1].trim();
}
4.7 操作が「確認」の場合(予定の確認)
操作が「確認」のときは#期間
から開始・終了日時を取り出し、その期間に登録されている予定を取得します。
const events = CalendarApp.getDefaultCalendar().getEvents(start, end);
if (events.length > 0) {
userMessageFormatted += "\n\n📅 登録されている予定:\n";
userMessageFormatted += events.map(e => {
const time = formatDate(e.getStartTime());
return `・${time} ~ ${e.getTitle()}`;
}).join("\n");
} else {
userMessageFormatted += "\n(その期間に予定はありません)";
}
操作が「登録」または「削除」の場合
✅ 登録
calendar.createEvent(title, start, end);
return `📅 ${title} の予定を登録しました。`;
🗑️ 削除
const events = calendar.getEvents(start, end);
const targetEvents = events.filter(event => event.getTitle().includes(title));
if (targetEvents.length > 0) {
targetEvents.forEach(event => event.deleteEvent());
return `🗑️ ${targetEvents.length} 件の「${title}」の予定を削除しました。`;
} else {
return `❗「${title}」の予定が見つかりませんでした。`;
}
✅ 5. 動作例
入力例 | 結果 |
---|---|
明日の10時に〇〇入れて | 📅 予定がGoogleカレンダーに登録される |
明日の予定教えて | ✅ 登録済みの予定一覧が表示される |
明日の予定キャンセル | 🗑️ 指定の予定が削除される |
以下は実際に LINE に入力して、Googleカレンダーと連動した動作結果です。
📝 予定を登録する
入力:
明日の10時から1時間、美容院の予定を入れて
結果:
📅 美容院の予定を登録しました。
🔍 予定を確認する
入力:
明日の予定を教えて
結果:
明日の予定を確認いたします。
📅登録されている予定:
- 2025/04/23 10:00~ 美容院
🗑️ 予定を削除する
入力:
明日の美容院の予定を削除して
結果:
🗑️ 1件の「美容院」の予定を削除しました。
すべての操作が自然言語で完結します。しかもLINEで完結するので、予定管理がぐっと身近になります!
💬 感想・振り返り
今回の開発を通して、自然言語で予定を登録・確認できる仕組みがあると、日常の予定管理がとてもスムーズになると実感しました。
特に 予定の登録と確認は安定して動作できました。LINE に「明日10時に美容院」と話しかけるだけで予定が入るのは、ちょっと未来感があります。
ただし、削除機能についてはまだ不安定な部分も残っており、入力内容によって削除対象が見つからないケースもありました。この点は今後の精度向上の課題です。
🤔 実際に使うかどうか?
正直なところ、「ぱっとカレンダーを見たいとき」はやっぱり Google カレンダーそのものを開いた方が早いこともあります。そのため、LINEボットはあくまで補助的・並列的に使うのが現実的かもしれません。
とはいえ、「手がふさがっていてスマホしか触れない」「会話感覚で予定を入れたい」といったシーンではかなり便利に感じました。
🔮 今後のアイデア・改良したいこと
- ✅ 毎晩21:00に「明日の予定」をLINEでリマインドしてくれる機能を追加したい
- 📝 やるべきタスクや締切も管理できるように拡張していきたい
- 📆 カレンダーを見て「空いている時間」に自動で予定やタスクを配置してくれるような、提案型の秘書AI にしていきたい
今回の取り組みは、「未来の予定管理」に一歩近づいた感覚がありました。✨
📝 7. おわりに
この記事を読んで「やってみよう!」と思ってもらえたら嬉しいです。
試してみたら、Zenn や X で感想を聞かせてください!
Discussion