👊

ChatGPTとGoogle Tasks/Calendarを連携して「スケジュールマスター」を作った話

に公開

はじめに

今日あんまり調子良くないな〜、という日はAIにタスク管理任せてお尻を叩いて欲しいなと思ったのが始まりでした。

今回、ChatGPT(GPTs)とGoogle Tasks / Calendar を連携させることで、
会話ベースでスケジュール管理ができる「スケジュールマスター」を作りました。

たとえば、

  • 「今日の予定見せて」→ カレンダー+タスクを一覧表示
  • 「テックブログ書くタスクを23:30に」→ 期限付きでタスク登録

こんな自然な対話で、スケジュールを整理してくれるパーソナルアシスタントが誕生しました。

Google Apps ScriptでAPIを自作

まずはGASでGoogleカレンダーとGoogle Tasksを操作するAPIを作成しました。

提供するエンドポイント

  • GET /exec:直近数日分のカレンダー予定と未完了タスクをまとめて取得
  • POST /exec:タスクをGoogle Tasksに追加

GASコード例

function getOAuthService() {
  return OAuth2.createService('googleTasks')
    .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
    .setTokenUrl('https://oauth2.googleapis.com/token')
    .setClientId(PropertiesService.getScriptProperties().getProperty('CLIENT_ID'))
    .setClientSecret(PropertiesService.getScriptProperties().getProperty('CLIENT_SECRET'))
    .setCallbackFunction('authCallback')
    .setPropertyStore(PropertiesService.getUserProperties())
    .setScope('https://www.googleapis.com/auth/tasks https://www.googleapis.com/auth/calendar.readonly')
    .setParam('access_type', 'offline')
    .setCache(CacheService.getUserCache());
}

function authCallback(request) {
  const service = getOAuthService();
  const authorized = service.handleCallback(request);
  return HtmlService.createHtmlOutput(authorized ? '認証に成功しました。' : '認証に失敗しました。');
}

function authorize() {
  const service = getOAuthService();
  if (!service.hasAccess()) {
    Logger.log('認証URL: ' + service.getAuthorizationUrl());
  } else {
    Logger.log('認証済み');
  }
}

function doGet(e) {
  const service = getOAuthService();
  if (!service.hasAccess()) {
    return ContentService.createTextOutput("未認証です。authorize() を実行してください。");
  }

  const now = new Date();
  const future = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
  const calendar = CalendarApp.getDefaultCalendar();
  const events = calendar.getEvents(now, future);
  const calendarEvents = events.map(ev => ({
    title: ev.getTitle(),
    start: ev.getStartTime(),
    end: ev.getEndTime(),
    description: ev.getDescription()
  }));

  const tasksUrl = "https://tasks.googleapis.com/tasks/v1/lists/@default/tasks?showCompleted=false";
  const options = {
    method: "GET",
    headers: {
      Authorization: "Bearer " + service.getAccessToken()
    }
  };
  const response = UrlFetchApp.fetch(tasksUrl, options);
  const tasks = JSON.parse(response.getContentText()).items || [];
  const taskList = tasks.map(t => ({
    title: t.title,
    due: t.due,
    notes: t.notes,
    status: t.status
  }));

  return ContentService
    .createTextOutput(JSON.stringify({ calendarEvents, tasks: taskList }, null, 2))
    .setMimeType(ContentService.MimeType.JSON);
}

function doPost(e) {
  const service = getOAuthService();
  if (!service.hasAccess()) return ContentService.createTextOutput("未認証");

  const data = JSON.parse(e.postData.contents);
  const { title, due, notes } = data;

  const payload = {
    title,
    notes: notes || ""
  };
  if (due) payload.due = new Date(due).toISOString();

  const options = {
    method: "POST",
    contentType: "application/json",
    headers: {
      Authorization: "Bearer " + service.getAccessToken()
    },
    payload: JSON.stringify(payload)
  };

  const response = UrlFetchApp.fetch("https://tasks.googleapis.com/tasks/v1/lists/@default/tasks", options);
  return ContentService.createTextOutput(response.getContentText());
}

Google Cloud Console 側の設定手順

  1. Google Cloud Console にアクセスし、新しいプロジェクトを作成

  2. 「OAuth同意画面」を設定

    • ユーザータイプ:「外部」
    • スコープ:https://www.googleapis.com/auth/taskshttps://www.googleapis.com/auth/calendar.readonly
    • テストユーザーに自分のメールアドレスを追加
  3. 「認証情報」からOAuthクライアントIDを作成(アプリケーションの種類は「ウェブアプリ」)

  4. 発行された CLIENT_IDCLIENT_SECRET をスクリプトプロパティに登録

  5. GAS エディタ > プロジェクトのプロパティ > スクリプトプロパティ に設定

CLIENT_ID = xxxxxxxx.apps.googleusercontent.com
CLIENT_SECRET = xxxxxxxx

GPTs アクションで連携

OpenAI のカスタム GPT(GPTs)では、外部APIを OpenAPI 仕様で登録することで、
ChatGPT から直接 GAS API を呼び出せるようになります。

servers:
  - url: https://script.googleusercontent.com
paths:
  /macros/s/{ID}/exec:
    get:
      operationId: getTasksAndEventsFromGAS
    post:
      operationId: postTaskToGAS
  /macros/echo:
    get:
      operationId: followRedirectEcho

GASの /exec はリダイレクトが入るため、/macros/echoservers.paths に追加して対処しました。

今後の課題と展望

  • Google Tasks API は「終日タスク」しか扱えないため、時間付きの管理が難しい
  • カレンダーAPIを併用することで補完可能(カレンダーイベントを生成)
  • 他ユーザーが使うにはプロキシやセッション管理の工夫が必要(Cloud Functions など)

実際に使ってみて感じたこと

作ってみたものの、自分のお気に入りのタスク管理アプリはKosmoTimeなんですが、
タスク管理のスピード感もそうですし、やる気の面でも自分で入力していったほうが上がるな〜と感じました。

おわりに

ChatGPTのGPT Actionsで色々自作もできるとのことで、

今回はその第一歩として、「スケジュールマスター」を自作してみました。

興味がある方はぜひ試してみてください!

ispec inc.

Discussion