Merge pull request #68 from Dayanfreitas/main

Feat: add cookbook google calendar
This commit is contained in:
Zachary Huang 2025-05-23 16:27:56 -07:00 committed by GitHub
commit 1fc2f66127
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 372 additions and 0 deletions

View File

@ -0,0 +1,6 @@
# Google Calendar API Configuration
GOOGLE_CALENDAR_ID=your_calendar_id@group.calendar.google.com
GOOGLE_APPLICATION_CREDENTIALS=credentials.json
# Application Configuration
TIMEZONE=America/Sao_Paulo # or your preferred timezone

View File

@ -0,0 +1,4 @@
.env
Pipfile.lock
credentials.json
token.pickle

View File

@ -0,0 +1,16 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
python-dotenv = ">=0.19.0"
pocketflow = ">=0.0.2"
google-auth-oauthlib = ">=1.0.0"
google-auth-httplib2 = ">=0.1.0"
google-api-python-client = ">=2.0.0"
[dev-packages]
[requires]
python_version = "3.13"

View File

@ -0,0 +1,118 @@
# Pocket Google Calendar
An application based on the Pocket Flow framework for Google Calendar integration.
## 📋 Description
This project implements a Google Calendar integration using the Pocket Flow framework, allowing efficient management of events and appointments through a simple and intuitive interface.
## 🚀 Features
- Google Calendar API Integration
- Event Management
- Appointment Viewing
- Flow-based Interface using Pocket Flow
## 🛠️ Technologies Used
- Python
- Pocket Flow Framework
- Google Calendar API
- Pipenv for dependency management
## 📦 Installation
1. Clone the repository:
```bash
git clone [REPOSITORY_URL]
cd pocket-google-calendar
```
2. Install dependencies using Pipenv:
```bash
pipenv install
```
## 🔑 Credentials Setup
1. Go to the [Google Cloud Console](https://console.cloud.google.com/)
2. Create a new project or select an existing one
3. Enable the Google Calendar API for your project
4. Create credentials:
- Go to "APIs & Services" > "Credentials"
- Click "Create Credentials" > "OAuth client ID"
- Choose "Desktop application" as the application type
- Download the credentials file
- Rename it to `credentials.json`
- Place it in the root directory of the project
## 🌍 Environment Variables
Create a `.env` file in the root directory with the following variables:
```env
# Google Calendar API Configuration
GOOGLE_CALENDAR_ID=your_calendar_id@group.calendar.google.com
GOOGLE_APPLICATION_CREDENTIALS=credentials.json
# Application Configuration
TIMEZONE=America/Sao_Paulo # or your preferred timezone
```
## 🔧 Configuration
1. Activate the virtual environment:
```bash
pipenv shell
```
2. Run the application:
```bash
python main.py
```
## Expected Output
When running the example, you'll see an output similar to this:
```
=== Listing your calendars ===
- Primary Calendar
- Work
- Personal
=== Creating an example event ===
Event created successfully!
Event ID: abc123xyz
```
## 📁 Project Structure
```
pocket-google-calendar/
├── main.py # Application entry point
├── nodes.py # Pocket Flow node definitions
├── utils/ # Utilities and helper functions
├── Pipfile # Pipenv configuration
├── credentials.json # Google Calendar API credentials
├── .env # Environment variables
└── token.pickle # Google Calendar authentication token
```
## 🤝 Contributing
1. Fork the project
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the Branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request
## 📝 License
This project is under the MIT License. See the [LICENSE](LICENSE) file for more details.
## ✨ Acknowledgments
- [Pocket Flow](https://github.com/the-pocket/PocketFlow) - Framework used
- [Google Calendar API](https://developers.google.com/calendar) - Integration API

View File

@ -0,0 +1,53 @@
from pocketflow import Flow
from nodes import CreateCalendarEventNode, ListCalendarEventsNode, ListCalendarsNode
from datetime import datetime, timedelta
def create_calendar_flow():
"""Creates a flow to manage calendar events."""
# Create nodes
create_event_node = CreateCalendarEventNode()
list_events_node = ListCalendarEventsNode()
# Connect nodes
create_event_node - "success" >> list_events_node
create_event_node - "error" >> None
# Create flow
return Flow(start=create_event_node)
def list_calendars_flow():
"""Creates a flow to list all user calendars."""
list_calendars_node = ListCalendarsNode()
return Flow(start=list_calendars_node)
def main():
# Example: List all calendars
print("=== Listing your calendars ===")
flow = list_calendars_flow()
shared = {}
flow.run(shared)
if 'available_calendars' in shared:
for cal in shared['available_calendars']:
print(f"- {cal.get('summary')}")
# Example: Create a simple event
print("\n=== Creating an example event ===")
flow = create_calendar_flow()
shared = {
'event_summary': 'Example Meeting',
'event_description': 'An example meeting created by PocketFlow',
'event_start_time': datetime.now() + timedelta(days=1),
'event_end_time': datetime.now() + timedelta(days=1, hours=1),
'days_to_list': 7
}
flow.run(shared)
if 'last_created_event' in shared:
print("Event created successfully!")
print(f"Event ID: {shared['last_created_event']['id']}")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,81 @@
from pocketflow import Node
from utils.google_calendar import create_event, list_events, list_calendar_lists
from datetime import datetime, timedelta
class CreateCalendarEventNode(Node):
def prep(self, shared):
"""Prepares the necessary data to create an event."""
return {
'summary': shared.get('event_summary'),
'description': shared.get('event_description'),
'start_time': shared.get('event_start_time'),
'end_time': shared.get('event_end_time')
}
def exec(self, event_data):
"""Creates a new calendar event."""
try:
event = create_event(
summary=event_data['summary'],
description=event_data['description'],
start_time=event_data['start_time'],
end_time=event_data['end_time']
)
return {'success': True, 'event': event}
except Exception as e:
return {'success': False, 'error': str(e)}
def post(self, shared, prep_res, exec_res):
"""Stores the event creation result."""
if exec_res['success']:
shared['last_created_event'] = exec_res['event']
return 'success'
else:
shared['error'] = exec_res['error']
return 'error'
class ListCalendarEventsNode(Node):
def prep(self, shared):
"""Prepares parameters to list events."""
return {
'days': shared.get('days_to_list', 7)
}
def exec(self, params):
"""Lists calendar events."""
try:
events = list_events(days=params['days'])
return {'success': True, 'events': events}
except Exception as e:
return {'success': False, 'error': str(e)}
def post(self, shared, prep_res, exec_res):
"""Stores the list of events."""
if exec_res['success']:
shared['calendar_events'] = exec_res['events']
return 'success'
else:
shared['error'] = exec_res['error']
return 'error'
class ListCalendarsNode(Node):
def prep(self, shared):
"""No special preparation needed to list calendars."""
return {}
def exec(self, params):
"""Lists all available calendars for the user."""
try:
calendars = list_calendar_lists()
return {'success': True, 'calendars': calendars}
except Exception as e:
return {'success': False, 'error': str(e)}
def post(self, shared, prep_res, exec_res):
"""Stores the list of calendars in the shared store."""
if exec_res['success']:
shared['available_calendars'] = exec_res['calendars']
return 'success'
else:
shared['error'] = exec_res['error']
return 'error'

View File

@ -0,0 +1,94 @@
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
import os.path
import os
import pickle
from datetime import datetime, timedelta
from dotenv import load_dotenv
load_dotenv()
CALENDAR_ID = os.getenv('GOOGLE_CALENDAR_ID')
GOOGLE_APPLICATION_CREDENTIALS = os.getenv('GOOGLE_APPLICATION_CREDENTIALS')
TIMEZONE = os.getenv('TIMEZONE')
SCOPES = ['https://www.googleapis.com/auth/calendar']
def get_calendar_service():
"""Gets the authenticated Google Calendar service."""
creds = None
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
GOOGLE_APPLICATION_CREDENTIALS, SCOPES)
creds = flow.run_local_server(port=0)
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
return build('calendar', 'v3', credentials=creds)
def create_event(summary, description, start_time, end_time, timezone=TIMEZONE):
"""Creates a new event in Google Calendar."""
service = get_calendar_service()
event = {
'summary': summary,
'description': description,
'start': {
'dateTime': start_time.isoformat(),
'timeZone': timezone,
},
'end': {
'dateTime': end_time.isoformat(),
'timeZone': timezone,
},
}
event = service.events().insert(calendarId=CALENDAR_ID, body=event).execute()
return event
def list_events(days=7):
"""Lists events for the next X days."""
service = get_calendar_service()
now = datetime.utcnow()
time_min = now.isoformat() + 'Z'
time_max = (now + timedelta(days=days)).isoformat() + 'Z'
events_result = service.events().list(
calendarId=CALENDAR_ID,
timeMin=time_min,
timeMax=time_max,
singleEvents=True,
orderBy='startTime'
).execute()
return events_result.get('items', [])
def create_custom_calendar(calendar_name, description=""):
"""Creates a new custom calendar in Google Calendar."""
service = get_calendar_service()
calendar = {
'summary': calendar_name,
'description': description,
'timeZone': TIMEZONE
}
created_calendar = service.calendars().insert(body=calendar).execute()
return created_calendar
def list_calendar_lists():
"""Lists all available calendars for the user."""
service = get_calendar_service()
calendar_list = service.calendarList().list().execute()
return calendar_list.get('items', [])