見出し画像

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のプロジェクト作成

  1. Googleドライブにアクセスし、「新規」 > 「その他」 > 「Google Apps Script」を選択します。

  2. 新規プロジェクトが開いたら、先ほどのコードをコピー&ペーストします。

  3. 「保存」をクリックし、プロジェクトに名前を付けます。

4.2 カレンダーAPIの有効化

  1. 左側の「サービス」> 「GoogleカレンダーAPI」をクリックし、APIを有効化します。

4.3 Webアプリケーションとしてデプロイ

  1. 画面右上の「デプロイ」> 「新しいデプロイ」をクリック。

  2. 種類を選択」「ウェブアプリケーション」を選択し、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. 設定手順

  1. GASプロジェクトの作成:Googleドライブに移動し、新規作成からGoogle Apps Scriptを選び、コードを追加。

  2. GoogleカレンダーAPIの有効化:左側メニューからカレンダーAPIを有効にする。

  3. デプロイ:プロジェクトをウェブアプリケーションとしてデプロイし、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"
        ]
      }
    }
  }
}