ChatGPTにGoogleカレンダーを管理してもらおう!
1. はじめに
こんにちは!今日は、Google Apps Script (GAS)とChatGPTのGPTs機能を使って、簡単な秘書アプリを作る方法を説明します。このアプリでは、Googleカレンダーに予定を追加したり、カレンダーの予定を取得したりすることができます。
2. 必要な準備
このプロジェクトでは以下のツールを使用します:
Google Apps Script (GAS):Googleのクラウド上で動くJavaScriptのようなプログラミング言語
Google カレンダー API:Googleカレンダーを操作するためのAPI
ChatGPT API:AIを活用した応答のためのAPI
2.1 Google Apps Script (GAS) とは?
Google Apps Scriptは、Googleサービス(例:スプレッドシート、カレンダー)をプログラムで操作できるツールです。簡単なコードを書くことで、手作業を自動化したり、他のGoogleアプリと連携させたりできます。
3. コードの説明
次に、必要なコードを説明します。
3.1 日付を指定のタイムゾーンに変換する関数
function convertToTimeZone(dateString, timeZone) {
var date = new Date(dateString); // 1. ISOフォーマットの文字列をDateオブジェクトに変換
var formattedDate = Utilities.formatDate(date, timeZone, "yyyy-MM-dd'T'HH:mm:ss"); // 2. 指定のタイムゾーンでフォーマット
return new Date(formattedDate); // 3. フォーマットした文字列を再度Dateオブジェクトに変換して返す
}
説明:
`convertToTimeZone`は、指定したタイムゾーン(例えば「Asia/Tokyo」)に従って日付を変換する関数です。
`dateString`に日付、`timeZone`にタイムゾーンを渡して使います。
3.2 POSTリクエストでカレンダーに予定を追加する
function doPost(e) {
var requestData = JSON.parse(e.postData.contents); // 1. POSTされたデータをパース
var title = requestData.title; // 2. イベントタイトル取得
var startTime = convertToTimeZone(requestData.startTime, "Asia/Tokyo"); // 3. 開始時間を日本時間に変換
var endTime = convertToTimeZone(requestData.endTime, "Asia/Tokyo"); // 4. 終了時間を日本時間に変換
var calendarId = requestData.calendarId; // 5. カレンダーIDを取得
var description = requestData.description; // 6. イベントの説明
var calendar = CalendarApp.getCalendarById(calendarId); // 7. カレンダーを取得
var event = calendar.createEvent(title, startTime, endTime, {description: description}); // 8. イベントを作成
var response = {
status: "success", // 9. 成功した場合のステータス
eventId: event.getId() // 10. 作成されたイベントのID
};
return ContentService.createTextOutput(JSON.stringify(response))
.setMimeType(ContentService.MimeType.JSON); // 11. 結果をJSONで返す
}
説明:
このコードは、POSTリクエストで送られたデータを使ってGoogleカレンダーに新しい予定を追加します。
カレンダーIDを指定することで、どのカレンダーに追加するかをコントロールできます。
3.3 GETリクエストでカレンダーの予定を取得する
function doGet(e) {
try {
if (!e.parameter.date) {
throw new Error('Date parameter is missing'); // 1. 日付パラメータがない場合にエラーを投げる
}
var date = e.parameter.date; // 2. パラメータから日付を取得
var events = getEventsForDate(date); // 3. 日付に対応するイベントを取得
return ContentService.createTextOutput(JSON.stringify(events))
.setMimeType(ContentService.MimeType.JSON); // 4. 結果をJSONで返す
} catch (error) {
return ContentService.createTextOutput(JSON.stringify({ error: error.message }))
.setMimeType(ContentService.MimeType.JSON); // 5. エラーが発生した場合の処理
}
}
説明:
GETリクエストを受け取った際に、その日に対応するカレンダーイベントを取得して返す関数です。
指定した日付にイベントがあれば、その情報をJSON形式で返します。
4. 設定方法
4.1 Google Apps Scriptのプロジェクト作成
Googleドライブにアクセスし、「新規」 > 「その他」 > 「Google Apps Script」を選択します。
新規プロジェクトが開いたら、先ほどのコードをコピー&ペーストします。
「保存」をクリックし、プロジェクトに名前を付けます。
4.2 カレンダーAPIの有効化
左側の「サービス」> 「GoogleカレンダーAPI」をクリックし、APIを有効化します。
4.3 Webアプリケーションとしてデプロイ
画面右上の「デプロイ」> 「新しいデプロイ」をクリック。
「種類を選択」で「ウェブアプリケーション」を選択し、URLを発行します。
4.4. テストと応用
発行されたURLにGETまたはPOSTリクエストを送信して、アプリをテストします。
例えば、POSTリクエストを使って「予定の追加」、GETリクエストを使って「予定の取得」を行います。
5. 完成版コード
5.1. 日付を指定のタイムゾーンに変換する関数
function convertToTimeZone(dateString, timeZone) {
var date = new Date(dateString); // ISOフォーマットの文字列をDateオブジェクトに変換
var formattedDate = Utilities.formatDate(date, timeZone, "yyyy-MM-dd'T'HH:mm:ss");
return new Date(formattedDate); // フォーマットした文字列を再度Dateオブジェクトに変換
}
5.2. POSTリクエストでカレンダーに予定を追加する関数
function doPost(e) {
var requestData = JSON.parse(e.postData.contents); // POSTリクエストからデータを取得
var title = requestData.title; // イベントのタイトル
var startTime = convertToTimeZone(requestData.startTime, "Asia/Tokyo"); // 開始時間を日本時間に変換
var endTime = convertToTimeZone(requestData.endTime, "Asia/Tokyo"); // 終了時間を日本時間に変換
var calendarId = requestData.calendarId; // カレンダーIDを取得
var description = requestData.description; // イベントの説明
// カレンダーにイベントを追加
var calendar = CalendarApp.getCalendarById(calendarId);
var event = calendar.createEvent(title, startTime, endTime, {description: description});
// イベント作成の確認メッセージを返す
var response = {
status: "success", // 成功した場合のステータス
eventId: event.getId() // 作成されたイベントのID
};
return ContentService.createTextOutput(JSON.stringify(response))
.setMimeType(ContentService.MimeType.JSON);
}
5.3. GETリクエストでカレンダーの予定を取得する関数
function doGet(e) {
try {
if (!e.parameter.date) {
throw new Error('Date parameter is missing'); // 日付パラメータがない場合はエラー
}
var date = e.parameter.date; // パラメータから日付を取得
Logger.log('Received request for date: ' + date);
var events = getEventsForDate(date); // 指定された日付のイベントを取得
return ContentService.createTextOutput(JSON.stringify(events))
.setMimeType(ContentService.MimeType.JSON);
} catch (error) {
Logger.log('Error in doGet: ' + error.message);
return ContentService.createTextOutput(JSON.stringify({ error: error.message }))
.setMimeType(ContentService.MimeType.JSON);
}
}
5.4. 日付に対応するカレンダーイベントを取得する関数
var calendarDescriptions = {
'primary': '個人カレンダー',
'xxxx@group.calendar.google.com': 'XX',
};
var calendarIds = Object.keys(calendarDescriptions);
function getEventsForDate(date) {
try {
var timeZone = "Asia/Tokyo"; // JSTタイムゾーン
var startDate = new Date(date);
var endDate = new Date(startDate);
endDate.setDate(endDate.getDate() + 1); // 終了日は開始日+1日
Logger.log('Fetching events for date range: ' + startDate + ' to ' + endDate);
var allEvents = [];
calendarIds.forEach(function(calendarId) {
var calendar = CalendarApp.getCalendarById(calendarId);
if (calendar) {
var events = calendar.getEvents(startDate, endDate);
var eventsData = events.map(function(event) {
return {
'calendarDescription': calendarDescriptions[calendarId],
'summary': event.getTitle(),
'start': Utilities.formatDate(event.getStartTime(), timeZone, "yyyy-MM-dd'T'HH:mm:ss'Z'"),
'end': Utilities.formatDate(event.getEndTime(), timeZone, "yyyy-MM-dd'T'HH:mm:ss'Z'"),
'description': event.getDescription()
};
});
allEvents = allEvents.concat(eventsData);
Logger.log('Events fetched from calendar: ' + calendarId + ' - ' + JSON.stringify(eventsData));
} else {
Logger.log('Calendar not found for ID: ' + calendarId);
}
});
return allEvents;
} catch (error) {
Logger.log('Error in getEventsForDate: ' + error.message);
return [];
}
}
5.5. リクエストのログを記録する関数
function logRequest(date, events) {
try {
var spreadsheetUrl = 'https://docs.google.com/spreadsheets/d/xxxx'; // スプレッドシートURL
var sheet = SpreadsheetApp.openByUrl(spreadsheetUrl).getActiveSheet();
var timestamp = new Date();
var logData = [timestamp, date, JSON.stringify(events)];
sheet.appendRow(logData);
Logger.log('Request logged successfully: ' + JSON.stringify(logData));
} catch (error) {
Logger.log('Error in logRequest: ' + error.message);
}
}
5.6. テスト用関数
function testGetEventsForDate() {
var testDate = '2024-09-06'; // テスト日付
var events = getEventsForDate(testDate);
Logger.log(JSON.stringify(events)); // 結果をログに表示
}
5.7. 設定手順
GASプロジェクトの作成:Googleドライブに移動し、新規作成からGoogle Apps Scriptを選び、コードを追加。
GoogleカレンダーAPIの有効化:左側メニューからカレンダーAPIを有効にする。
デプロイ:プロジェクトをウェブアプリケーションとしてデプロイし、URLを取得。
5.8. テスト
GETリクエストでカレンダーイベントを取得、POSTリクエストで新しいイベントを追加してみましょう。
以下はChatGPTのMYGPT設定に関する設定例です。指示内容に基づき、ChatGPTが秘書として振る舞うように構成されています。
6. GPTsの設定
Role (役割):
説明: あなたは秘書です。ChatGPTとして、カレンダーのスケジュール管理や予定の追加、カレンダーAPIとの連携を行います。
Conversation Instructions (会話指示):
短文で簡潔に答えることを重視する。
「空いている時間」を聞かれた際、指定のルールに従って応答する。
カレンダーに予定を追加する場合、指定されたカレンダーIDを使用し、具体的に適切なカレンダーを選んで予定を追加する。
時系列を整理して、計画や予定に関する会話を進める。
Hidden Details (明示しない指示):
必要に応じて、インデントや箇条書きを使って論理構造を示す。
メールの文体では丁寧な表現を使う。相手を気遣う表現(例:「お忙しいところ恐縮ですが」)を多用する。
API Integration (API連携):
カレンダーAPI: GET/POSTリクエストを介して、カレンダーの予定を取得したり、予定を追加したりできる。
例: ?date=YYYY-MM-DDの形式でリクエストを送信する。
カレンダーID (カレンダーの例):
'primary': '個人カレンダー',
'xx@group.calendar.google.com':'作業',
その他、カレンダーに基づいた予定の管理と追加が可能。
Usage Example (会話例):
Q: 「〇月〇日の空いている時間を教えてください。」
A: 「〇月〇日:12時以降空いています。」または「〇月〇日:全日空いています。」
この設定により、MYGPTは指定のキャラクターとして行動し、カレンダー管理や予定のスケジュール調整を効果的に行います。
{
"openapi": "3.1.0",
"info": {
"title": "Get and Add Calendar Events",
"description": "Retrieves events for a specified date from Google Calendar and adds new events to the calendar.",
"version": "v1.1.0"
},
"servers": [
{
"url": "https://script.google.com"
}
],
"paths": {
"/macros/s/xxx/exec": {
"get": {
"description": "Get events for a specific date.",
"operationId": "GetCalendarEvents",
"parameters": [
{
"name": "date",
"in": "query",
"description": "The date to retrieve events for in YYYY-MM-DD format",
"required": true,
"schema": {
"type": "string",
"format": "date"
}
}
],
"responses": {
"200": {
"description": "A list of calendar events",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Event"
}
}
}
}
}
},
"deprecated": false
},
"post": {
"description": "Add a new event to the calendar.",
"operationId": "AddCalendarEvent",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NewEvent"
}
}
}
},
"responses": {
"200": {
"description": "Confirmation of event creation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EventCreationResponse"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Event": {
"type": "object",
"properties": {
"calendarDescription": {
"type": "string",
"description": "Description of the calendar the event belongs to"
},
"summary": {
"type": "string",
"description": "Summary or title of the event"
},
"start": {
"type": "string",
"format": "date-time",
"description": "Start time of the event"
},
"end": {
"type": "string",
"format": "date-time",
"description": "End time of the event"
},
"description": {
"type": "string",
"description": "Description or notes associated with the event"
}
},
"required": [
"calendarDescription",
"summary",
"start",
"end",
"description"
]
},
"NewEvent": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "Title of the event"
},
"startTime": {
"type": "string",
"format": "date-time",
"description": "Start time of the event"
},
"endTime": {
"type": "string",
"format": "date-time",
"description": "End time of the event"
},
"calendarId": {
"type": "string",
"description": "ID of the calendar to add the event to"
},
"description": {
"type": "string",
"description": "Description or notes for the event"
}
},
"required": [
"title",
"startTime",
"endTime",
"calendarId",
"description"
]
},
"EventCreationResponse": {
"type": "object",
"properties": {
"status": {
"type": "string",
"description": "Status of the event creation"
},
"eventId": {
"type": "string",
"description": "ID of the created event"
}
},
"required": [
"status",
"eventId"
]
}
}
}
}