はじめまして。私はフリーランス の取材ライターとして働いており、日々いろんなインタビューやイベントの案内メールが届きます。
そのたびに 「○月○日 ○時」 とか 「場所:○○ビル」 みたいな情報を手動でGoogleカレンダー に登録するのですが、これが地味に面倒で...。
「AIの時代なんだから、こういう単純作業は自動化できるのでは?」と思い立ち、ChatGPT を使って自分なりにWebアプリ を作ってみることにしました。
この記事では、その開発過程を初心者目線 でまとめてみます。
何を作ろうとしているか
自作Webアプリの動作イメージ
私のレベル感
Node.js・Docker・クラウド → ほぼ触ったことなし
AIのコード生成 → ChatGPTに簡単な質問をした程度
でも「やればなんとかなるかも?」という勢いだけで始めました。
ChatGPTとの対話で進める開発
1. 「メール本文→日時抽出」はFunction Callingが便利
ChatGPTにはFunction Calling という機能があり、指定した「関数(=データ構造)」に合う形で回答を返してくれます。
これを使うと、「JSON 形式でタイトル・日付・場所を返して」 と明示できるので、パースがシンプルで済むんですね。
サンプル:メール本文を分析して予定情報を返す
// (一部省略: ExpressやCORS設定は省略してます)
// OpenAIの初期化
const OpenAI = require('openai');
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// メール解析用のルート
app.post('/api/parse', async (req, res) => {
const { emailContent } = req.body;
if (!emailContent) {
return res.status(400).json({ error: "メール本文が空です。" });
}
// ChatGPTにFunction Callingで解析を依頼
const response = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [
{ role: "system", content: "あなたはメール本文から予定情報を抽出する有能なアシスタントです。" },
{ role: "user", content: emailContent }
],
functions: [{
name: "extract_event_info",
description: "メール本文から日時や場所などのイベント情報を抽出する",
parameters: {
type: "object",
properties: {
title: { type: "string", description: "イベントのタイトル" },
location: { type: "string", description: "開催場所" },
startTime: { type: "string", description: "開始日時(YYYY-MM-DDTHH:mm:ss)" },
endTime: { type: "string", description: "終了日時(無ければ開始+1h)" },
description:{ type: "string", description: "イベントの詳細" }
},
required: ["title", "startTime", "endTime"]
}
}],
function_call: { name: "extract_event_info" }
});
// レスポンスの処理
const funcCall = response.choices[0].message.function_call;
if (!funcCall) {
return res.json({
title: '',
location: '',
startTime: '',
endTime: '',
description: 'Function Callの応答がありませんでした。'
});
}
try {
const parsedData = JSON.parse(funcCall.arguments);
return res.json({
title: parsedData.title || '',
location: parsedData.location || '',
startTime: parsedData.startTime || '',
endTime: parsedData.endTime || '',
description: parsedData.description || ''
});
} catch (err) {
return res.json({
title: '',
location: '',
startTime: '',
endTime: '',
description: `JSONパースエラー: ${funcCall.arguments}`
});
}
});
ポイント
functions で「extract_event_info」というオブジェクトを定義し、ChatGPTに「ここに合うJSON を返してね」と指示。
function_call.name で強制的に その関数を呼び出す形式。
arguments はJSON 文字列なので JSON.parse() が必要。
ChatGPTには「終了時刻が無ければ開始+1時間」といった指示も書ける。
2. iCalendar(.ics)ファイルの生成
メール本文の解析結果(title, location, startTime, endTime, description)を .ics にまとめるのは、以下のようなシンプルな関数でやっています。
function createICS(title, location, startTime, endTime, description) {
const dtStamp = new Date().toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z';
const uid = `${Date.now()}@example.com`;
const dtStart = formatICSDate(startTime);
const dtEnd = formatICSDate(endTime);
const esc = str => (
str.replace(/\\/g, '\\\\')
.replace(/;/g, '\\;')
.replace(/,/g, '\\,')
.replace(/\n/g, '\\n')
);
return `BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
UID:${uid}
DTSTAMP:${dtStamp}
SUMMARY:${esc(title)}
LOCATION:${esc(location)}
DESCRIPTION:${esc(description)}
DTSTART:${dtStart}
DTEND:${dtEnd}
END:VEVENT
END:VCALENDAR`;
}
function formatICSDate(dateString) {
if (!dateString) return '';
const date = new Date(dateString);
// 例: "2023-08-05T12:34:56Z" → "20230805T123456Z"
return date.toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z';
}
iCalendar形式では、行の折り返し が必要になる場合や、改行文字を \\n に変換する必要があります。
上のサンプルは最小限のエス ケープしかしていませんが、より厳密にやるなら「70文字超えで行を折り返す」等の処理も入れる必要があります。
これを res.setHeader('Content-Type', 'text/calendar') で返し、ユーザーにダウンロードしてもらうと、Googleカレンダー やOutlook にインポート可能!(ただし手間がかかる)
3. 新しい技術との出会い
「Googleカレンダー に直接登録したい!」となると、OAuth2 を導入する必要があります。
- client_id, client_secret, redirect_uri を設定し、同意画面を経てアクセストーク ンを取得。
- そのトーク ンを googleapis ライブラリの calendar.events.insert に渡して予定を作成。
これが初めてだと意外に大変 。リダイレクトURI がローカルと本番で違ったり、トーク ンをセッションに保存したり…。
「初心者にはハードル高いな…」と痛感しましたが、ChatGPT にエラー内容を投げると大体ヒントをくれるので助かりました。
- Docker & Cloud Run
いざNode.jsアプリをDocker化し、以下のような流れでCloud Runにデプロイしてみたら、あっという間にWeb上に公開されて感動しました。
# Dockerイメージをビルド
docker build -t asia.gcr.io/<PROJECT_ID>/<SERVICE_NAME> .
# Container Registryにpush
docker push asia.gcr.io/<PROJECT_ID>/<SERVICE_NAME>
# Cloud Runにデプロイ
gcloud run deploy <SERVICE_NAME> `
--image asia.gcr.io/<PROJECT_ID>/<SERVICE_NAME> `
--region=<REGION> `
--allow-unauthenticated
「こんな少ないコマンドで動くのか!」という驚きでした。それまで「クラウド は難しい」と思っていたのですが、こんなに簡単にURLが割り当てられ、リクエス トを受け付けてくれるんだ…と感動したのを覚えています。
ただし、「URLを知っていれば誰でもアクセスできる」状態なのはちょっと困るかも…と思い、Cloud Run の非公開(認証必須)設定を試そうとしました(--no-allow-unauthenticated を使うなど)。ところが、サービスアカウントのIAM設定やroles/run.invokerの扱いがやや複雑で、思うように「特定ユーザーだけ許可」にならず…。結局、自作の認証ラッパ(アプリレベルでOAuthやJWTチェックを行う方式)を入れたほうが早いかも、となりました。
いま振り返ると、Cloud Runの“完全プライベート”化自体は「デフォルト認証の仕組み」をしっかり把握すれば実現できるんですが、初心者の私には少しハードルが高かったです。結局、自前のOAuth(Google ログイン)をアプリに組み込み、アクセス制御を実装する方針に落ち着きました。こういう寄り道をしながらも、少しずつ仕組みを理解していく感じが楽しいです。
ハマりポイントいろいろ
「秒が無くて弾かれる」問題
Googleカレンダー API に日時を渡すとき、YYYY-MM-DDTHH:mm だけだとエラーになり「:00 を補え」と言われることがありました。
RFC3339形式を意識して、「:ss」 を補完しないと弾かれるケースが。ChatGPTが原因をすぐに指摘してくれたおかげで、速攻で直しました。
ChatGPTが出す例は多くがbash 前提。「\ で改行しろ」と言うが、PowerShell では使えない…など。
- docker build -t ... とか gcloud run deploy はそのまま動くけど、改行や環境変数 の書き方がbash と微妙に違う。
- でも慣れてくると 「CLI って意外と分かりやすいかも」 となりました。
Cloudの全貌
Google Cloud Consoleを開くと、大量のサービス が並んでいます。
「自分はそのうちのCloud RunとIAM周りしか触ってない...まだまだ広大だな」 という実感。
すべてを一度に理解しようとすると挫折しそうですが、ChatGPTに「何を使えばいいか」尋ねながら、必要なところだけ 使っていけばいいのかなと思っています。
「実際に動いた!」時の感動
一番テンション上がったのは、.icsファイルをダウンロードしてカレンダーにドラッグ&ドロップしたときに、想定通り予定が入った瞬間 ですね。
- 「うわ、本当に動いた…!」
- 自分で作った(ほぼChatGPTが生成してくれたとはいえ)仕組みで、今まで面倒だった作業がぐっと楽になる気がして、開発の醍醐味 を味わえた気分です。
今後の展望
機能面
メール本文に複数の予定が書かれている場合の対応
繰り返しイベントや参加者追加
説明にHTMLが含まれている場合の処理
UI/UXの向上
スマホ でも使いやすいデザイン
GPT解析結果をリアルタイムで表示して修正しやすくする
エラー時の分かりやすいメッセージ
セキュリティ・可用性
昔のエンジニアはどうしてたんだろう?
AIがない時代、こうしたクラウド 設定やAPI の使い方はドキュメント熟読&先輩に聞く しかなかったはず。
私の場合は、エラー内容や疑問をChatGPTに投げれば、すぐに「こうしてみては?」と提案 してもらえます。
便利だけど、「AIに頼りすぎて、仕組みをちゃんと理解してないのでは?」という不安も正直あります。
公式ドキュメントやベテランのブログを読む ことも忘れずに、少しずつ力をつけていきたいですね。
まとめ
メール本文→GPT解析→.ics生成→カレンダー登録 という一連の流れを、Node.js + ChatGPT + Cloud Run で実現
やってみたら初心者でも形になる レベルには到達できた
Function Calling があるおかげで、「メール→タイトル/日時/場所抽出」がかなりスムーズ
デプロイや認証はやや難易度高めだけど、ChatGPTと公式ドキュメントの併用で何とか前進
最初は「自分にこんなWebアプリ作れるの...?」と思っていましたが、AIを相棒に 時間をかければ意外とできる、というのが今の正直な感想です。
まだまだブラッシュアップは必要ですが、このプロジェクトを通じてWeb開発の楽しさ を少し味わえたのが大きな収穫でした。
(以上、まだ学習中&改良中のメモですが、少しでも同じような初心者の参考になれば嬉しいです!)
追記(2024年2月4日):もっとシンプルな解決策を見つけました
この記事を書いた後、「もっと簡単な方法があったのでは?」と気づきました。
Googleカレンダー には「予定作成用のURL」という機能があり、これを使えば複雑なWebアプリを作らなくても同じことができます。そこで、方針を転換してGPTs(ChatGPTのカスタムバージョン)を作成しました:
https://chatgpt.com/g/g-67a1ac0dadf08191a1df51ddd4969a5f-gkarentarinkuzuo-cheng
このGPTsは:
1. 案内文を解析してイベント情報を抽出
2. Googleカレンダー 用のURLを生成
3. クリックひとつで予定を登録できるリンクを提供
シンプルですが、当初の目的「メールの予定をカレンダーに楽に登録する」は十分に達成できています。
とはいえ、Node.jsやDocker、クラウド デプロイなど新しい技術に触れた経験は、無駄ではなかったと思います。時には「回り道」が、思わぬ学びをもたらしてくれるものですね。