from googleapiclient.discovery import build from datetime import datetime, timedelta from utils.auth import authenticate_google_services class GoogleCalendar_Agent: def __init__(self, creds=None, timezone="Asia/Taipei"): if not creds: creds = authenticate_google_services() self.service = build("calendar", "v3", credentials=creds) self.timezone = timezone def list_events(self, n: int=5, queries=None) -> str: now = datetime.utcnow().isoformat() + 'Z' events_result = self.service.events().list( calendarId='primary', timeMin=now, maxResults=n, singleEvents=True, orderBy='startTime' ).execute() events = events_result.get('items', []) if not events: return "🔕 找不到即將到來的行事曆事件。" output = "📅 您接下來的行事曆事件如下:\n" for event in events: start = event['start'].get('dateTime', event['start'].get('date')) summary = event.get('summary', 'No title') output += f"• {summary} at {start}\n" return output def create_event(self, summary: str, start_time: str, end_time: str, location: str = None, description: str = None, attendees: list = None, reminder_minutes: int = None) -> str: event = { 'summary': summary, 'start': {'dateTime': start_time, 'timeZone': self.timezone}, 'end': {'dateTime': end_time, 'timeZone': self.timezone} } if location: event['location'] = location if description: event['description'] = description if attendees: event['attendees'] = [{'email': email} for email in attendees] if reminder_minutes: event['reminders'] = { 'useDefault': False, 'overrides': [{'method': 'popup', 'minutes': reminder_minutes}] } try: created_event = self.service.events().insert( calendarId='primary', sendUpdates='all', body=event ).execute() return f"""✅ 已成功建立事件:\n標題 : {summary}\n開始時間 : {start_time}\n結束時間 : {end_time}\n地點 : {location or '無'}\n說明 : {description or '無'}\n參與者 : {', '.join(attendees) if attendees else '無'}\n提醒時間 : {reminder_minutes if reminder_minutes is not None else '使用預設提醒'}\n時區 : {self.timezone}\n事件連結 : {created_event.get('htmlLink')}""" except Exception as e: return f"❌ 建立事件失敗,以下是錯誤訊息(英文): {e}" def find_event(self, query: str,) -> list: now = datetime.utcnow().isoformat() + 'Z' events_result = self.service.events().list( calendarId='primary', timeMin=now, singleEvents=True, orderBy='startTime', q=query ).execute() return events_result.get('items', []) def update_event(self, query: str, new_summary=None, new_location=None, new_description=None, new_start=None, new_end=None, new_attendees=None, reminder_minutes=None): events = self.find_event(query) if not events: return f"❌ 找不到包含「{query}」的事件" if all(arg is None for arg in [ new_summary, new_location, new_description, new_start, new_end, new_attendees, reminder_minutes ]): return f"⚠️ 沒有指定任何要更新的欄位,未執行更新。" for event in events: event_id = event['id'] try: if new_summary: event['summary'] = new_summary if new_location: event['location'] = new_location if new_description: event['description'] = new_description if new_attendees: event['attendees'] = [{'email': email} for email in new_attendees] if reminder_minutes: event['reminders'] = { 'useDefault': False, 'overrides': [{'method': 'popup', 'minutes': reminder_minutes}] } if new_start or new_end: event['start']['dateTime'] = new_start event['end']['dateTime'] = new_end event['start']['timeZone'] = 'Asia/Taipei' event['end']['timeZone'] = 'Asia/Taipei' updated_event = self.service.events().update( calendarId='primary', eventId=event_id, sendUpdates='all', body=event ).execute() return f"✅ 已成功更新事件:{updated_event['summary']}" except Exception as e: return f"❌ 更新事件失敗,以下是錯誤訊息(英文): {e}" def delete_event(self, query: str): now = datetime.utcnow().isoformat() + 'Z' event_results = self.find_event(query) if len(event_results) == 0: return f"❌ 找不到包含「{query}」的事件" for event in event_results: target_id = event["id"] try: self.service.events().delete( calendarId='primary', eventId=target_id, sendUpdates='all' ).execute() return f"🗑️ 已刪除事件:{event['summary']}(ID: {target_id})" except Exception as e: return f"❌ 刪除事件失敗(ID: {target_id}),以下是錯誤訊息(英文): {e}" def get_event_details(self, query: str): events = self.find_event(query) if not events: return f"❌ 找不到符合 '{query}' 的事件!" event = events[0] summary = event.get('summary', 'No Title') start_time = event['start'].get('dateTime', event['start'].get('date')) end_time = event['end'].get('dateTime', event['end'].get('date')) formatted_string = f"事件: {summary}\n開始時間: {start_time}\n結束時間: {end_time}" attendees = event.get('attendees', []) emails = [attendee.get('email') for attendee in attendees if attendee.get('email')] if emails: formatted_string += f"\n參與者: {', '.join(emails)}" else: formatted_string += "\n無參與者" return formatted_string def get_all_tools(self): LLM_tools = [] LLM_tools.append({ "name": "create_Calendar_event", "description": "Create a new Google Calendar event by specifying summary, start time, and end time, and optionally location, description, attendees, and reminder.", "parameters": { "type": "object", "properties": { "summary": { "type": "string", "description": "Title or summary of the event (e.g., 'Lunch with Alice')" }, "start_time": { "type": "string", "format": "date-time", "description": "Start time of the event in ISO format (e.g., '2025-07-01T14:00:00')" }, "end_time": { "type": "string", "format": "date-time", "description": "End time of the event in ISO format (e.g., '2025-07-01T15:00:00')" }, "location": { "type": "string", "description": "Location of the event (e.g., 'Taipei 101')" }, "description": { "type": "string", "description": "Detailed description of the event" }, "attendees": { "type": "array", "items": {"type": "string"}, "description": "List of email addresses to invite to the event" }, "reminder_minutes": { "type": "integer", "description": "Number of minutes before the event to trigger a popup reminder" } }, "required": ["summary", "start_time", "end_time"] }, }) LLM_tools.append({ "name": "list_Calendar_events", "description": "List your upcoming Google Calendar events.", "parameters": { "type": "object", "properties": { "n": { "type": "integer", "default": 5, "description": "Number of upcoming events to list (default: 5)" } } } }) LLM_tools.append({ "name": "update_Calendar_event", "description": "Update a Google Calendar event using a keyword query to find it. You can update summary, location, description, start/end time, attendees, or reminders.", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "Keyword to find the event to update (e.g., 'meeting with Bob')" }, "new_summary": { "type": "string", "description": "New summary/title for the event" }, "new_location": { "type": "string", "description": "New location for the event" }, "new_description": { "type": "string", "description": "New description for the event" }, "new_start": { "type": "string", "format": "date-time", "description": "New start time in ISO format" }, "new_end": { "type": "string", "format": "date-time", "description": "New end time in ISO format" }, "new_attendees": { "type": "array", "items": {"type": "string"}, "description": "New list of attendees (email addresses)" }, "reminder_minutes": { "type": "integer", "description": "Updated popup reminder time in minutes" } }, "required": ["query"] } }) LLM_tools.append({ "name": "delete_Calendar_event", "description": "Delete a Google Calendar event using a keyword query to find it.", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "Keyword to find the event to delete (e.g., 'meeting with Bob')" } }, "required": ["query"] } }) LLM_tools.append({ "name": "get_event_details", "description": "Find the attendee email addresses and the summary of a specific event, based on a keyword.", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "Keyword to find the event and extract attendees and summary of that event." } }, "required": ["query"] } }) return LLM_tools