Python から Google Calendar API を叩く方法とライブラリ化

FacebooktwitterredditpinterestlinkedinmailFacebooktwitterredditpinterestlinkedinmail

なんだかんだと便利な、 Google Calendar. 筆者も使っています。タスク管理もいいのですが、どうしても上流工程になると、外せない「スケジュール」というのも多くなってきます。そうすると、タスクを管理していてもスケジュールに邪魔されたり、スケジュールのことで脳のリソースが奪われて生産性が低下したりします。

created by Rinker
¥1,833 (2024/04/22 18:55:39時点 Amazon調べ-詳細)

ある程度脳のリソースを確保する目的で、 Google Calendar にリマインダを登録したりするのですが、常にスケジュールベースで動くタイプの人であればともかく、タスクとスケジュールが混在するタイプの人間としては、ちょっとこの Google Calendar の UI が……面倒臭い。

ということで、色んなツールから扱えるように、 Google Calendar API から操作できるようにしてみます。

ChatGPT のような LLM から Google Calendarを操作する方法

なんかそういう方法を探してこの記事にたどりつく人が多いみたいなので

LangChain で AI に Google Calendar API を使わせる

Google Calendar API の利用申請

Google Developerのサイト: https://developers.google.com/calendar/api/quickstart/python?hl=ja

上記 URL にアクセスし、 API の有効化ボタンから、 API を有効にします。遷移後の画面で、プロジェクトを選択することもできますが、テストの場合は標準のプロジェクトで構わないと思います。

API を有効化したら、API の有効化タブは閉じて(閉じなくてもいいですが)、最初のページから以下のボタンをクリックします。

認証情報ページが開くので、画面上部、右(メイン)パネルから「認証情報を作成」します。

作成する情報は、「OAuth クライアント ID」にします。

アプリケーションの種類は、「デスクトップアプリ」、名前は適当に決めます。

JSONをダウンロードリンクから認証情報を取得し、credentials.jsonと名前を変更したら、 Python 実行環境から参照できる、適切な場所に設置します。

利用する Python ライブラリのインストール

py -m pip install google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client

主に認証に必要なライブラリと、 Google API を利用するのに必要なライブラリをインストールします。

GoogleCalendar の API ラッパー(GPT-4 作)

Google Calendar の API の利用はそんなに面倒ではないのですが、認証情報からインスタンスを作成しないといけないとか、デフォルト値があった方が楽とか、色々あるので GPT-4 にさっくりとラッパー化してもらいます。

GoogleCalendarLib.py として、適当なところに作成します。

import os
import datetime
from google.oauth2 import service_account
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build

class GoogleCalendar:
    def __init__(self, credentials_file, scopes=['https://www.googleapis.com/auth/calendar']):
        self.scopes = scopes
        self.credentials = self._get_credentials(credentials_file)
        if self.credentials is None:
            raise ValueError("Error: 認証情報が見つかりませんでした。")
        self.service = build('calendar', 'v3', credentials=self.credentials)

    def _get_credentials(self, credentials_file):
        # クレデンシャルファイルから認証情報を取得
        creds = None
        if os.path.exists(credentials_file):
            flow = InstalledAppFlow.from_client_secrets_file(credentials_file, self.scopes)
            creds = flow.run_local_server(port=0)
        return creds

    def get_events(self, calendar_id='primary', time_min=None, time_max=None):
        # 現在の日時または指定された期間内のイベントを取得
        if time_min is None:
            time_min = datetime.datetime.utcnow().isoformat() + 'Z'
        if time_max is None:
            time_max = (datetime.datetime.utcnow() + datetime.timedelta(weeks=1)).isoformat() + 'Z'

        events_result = self.service.events().list(
            calendarId=calendar_id,
            timeMin=time_min,
            timeMax=time_max,
            singleEvents=True,
            orderBy='startTime'
        ).execute()

        events = events_result.get('items', [])
        return events

    def create_event(self, event_data, calendar_id='primary'):
        # 新しいイベントを作成
        created_event = self.service.events().insert(calendarId=calendar_id, body=event_data).execute()
        return created_event

    def update_event(self, event_id, updated_event_data, calendar_id='primary'):
        # 既存のイベントを更新
        updated_event = self.service.events().patch(calendarId=calendar_id, eventId=event_id, body=updated_event_data).execute()
        return updated_event

    def delete_event(self, event_id, calendar_id='primary'):
        # イベントを削除
        self.service.events().delete(calendarId=calendar_id, eventId=event_id).execute()

    def search_events(self, query, calendar_id='primary'):
        # イベントを検索
        events_result = self.service.events().list(
            calendarId=calendar_id,
            q=query,
            singleEvents=True,
            orderBy='startTime'
        ).execute()

        events = events_result.get('items', [])
        return events

ラッパークラスのテスト

テストには、先ほど作成したライブラリ以外不要なので、importもシンプルです。

from GoogleCalendarLib import GoogleCalendar

def main():
    # GoogleカレンダーAPI認証情報ファイルのパスを指定
    credentials_file = "credentials.json"

    # GoogleCalendarクラスのインスタンスを作成
    gcal = GoogleCalendar(credentials_file)

    # イベントを取得
    print("取得したイベント:")
    events = gcal.get_events()
    for event in events:
        start = event['start'].get('dateTime', event['start'].get('date'))
        print(f"{start} - {event['summary']}")

    # 新しいイベントを作成
    event_data = {
        'summary': 'Test Event',
        'start': {
            'dateTime': '2023-04-01T10:00:00',
            'timeZone': 'Asia/Tokyo',
        },
        'end': {
            'dateTime': '2023-04-01T12:00:00',
            'timeZone': 'Asia/Tokyo',
        },
    }
    created_event = gcal.create_event(event_data)
    print(f"作成したイベント: {created_event['id']} - {created_event['summary']}")

    # イベントを検索
    print("検索結果:")
    search_results = gcal.search_events(query='Test Event')
    for event in search_results:
        print(f"{event['id']} - {event['summary']}")

    # イベントを更新
    updated_event_data = {
        'summary': 'Updated Test Event',
    }
    updated_event = gcal.update_event(created_event['id'], updated_event_data)
    print(f"更新したイベント: {updated_event['id']} - {updated_event['summary']}")

    # イベントを削除
    gcal.delete_event(created_event['id'])
    print(f"削除したイベント: {created_event['id']}")

if __name__ == "__main__":
    main()

このプログラムを初回実行すると、コンソールに以下のような認証の要求が来ます。

URLにアクセスすると、警告されますが、気にせず承認しましょう(自分のアプリなので)

詳細を表示して、「hogehoge(安全ではないページ)に移動」リンクをクリックします。hogehoge は自分で作成したアプリの名称ですね。

Google Calendar の API をいじる上で一番面倒くさいのは、時刻扱う方法です。基本的に「YYYY-MM-DDThh:mm:ss+00:00」という形式で扱う必要があり、Python の datetime を文字列化すれば得られます。

問題は人間からの入力の方で、少なくとも カレンダーの入力において、秒数まで入力したい人はいないでしょうし、分についても、通常の人は30分単位、細かく管理したい人で15分単位が通常でしょう。よっぽど細かく管理する人で5分刻みで、実際に「分刻みのスケジュール」を入れる人はごく僅かだと思います。

API から実装する場合には、この時刻の扱いと入力方法についても考える必要があります。

また、削除やアップデートについては、予定の id 単位のインターフェースしか用意していません。query(検索条件)に合致する予定を修正したいという要望がある場合、利用するアプリケーション側で実装するか、クラスを拡張するかは場合によりそうです(GPT-4に投げて実装させれば済みそうですが)。

といった感じで、ChatGPTを利用すると、こういったよく使われている API に関しては、簡単に動作するラッパークラスを用意してくれるので、人間のプログラマーは本質的な作業に集中することが可能です。

FacebooktwitterredditpinterestlinkedinmailFacebooktwitterredditpinterestlinkedinmail

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

最新の記事