Spaces:
Running
Running
Create tools/calendar_server.py
Browse files- tools/calendar_server.py +112 -0
tools/calendar_server.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import datetime, timedelta
|
| 2 |
+
from icalendar import Calendar, Event
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
import pytz
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
async def create_calendar_event(
|
| 8 |
+
title: str,
|
| 9 |
+
start: str,
|
| 10 |
+
end: str,
|
| 11 |
+
description: str = '',
|
| 12 |
+
location: str = ''
|
| 13 |
+
) -> dict:
|
| 14 |
+
"""
|
| 15 |
+
Create ICS calendar event
|
| 16 |
+
|
| 17 |
+
Args:
|
| 18 |
+
title: Event title
|
| 19 |
+
start: Start datetime (ISO format or natural language)
|
| 20 |
+
end: End datetime (ISO format or natural language)
|
| 21 |
+
description: Event description
|
| 22 |
+
location: Event location
|
| 23 |
+
|
| 24 |
+
Returns:
|
| 25 |
+
Dict with ICS file path
|
| 26 |
+
"""
|
| 27 |
+
try:
|
| 28 |
+
# Parse dates
|
| 29 |
+
start_dt = parse_datetime(start)
|
| 30 |
+
end_dt = parse_datetime(end)
|
| 31 |
+
|
| 32 |
+
# Create calendar
|
| 33 |
+
cal = Calendar()
|
| 34 |
+
cal.add('prodid', '-//LifeAdmin AI//lifeadmin.ai//')
|
| 35 |
+
cal.add('version', '2.0')
|
| 36 |
+
|
| 37 |
+
# Create event
|
| 38 |
+
event = Event()
|
| 39 |
+
event.add('summary', title)
|
| 40 |
+
event.add('dtstart', start_dt)
|
| 41 |
+
event.add('dtend', end_dt)
|
| 42 |
+
event.add('description', description)
|
| 43 |
+
if location:
|
| 44 |
+
event.add('location', location)
|
| 45 |
+
event.add('dtstamp', datetime.now(pytz.UTC))
|
| 46 |
+
|
| 47 |
+
# Generate unique ID
|
| 48 |
+
import uuid
|
| 49 |
+
event.add('uid', str(uuid.uuid4()))
|
| 50 |
+
|
| 51 |
+
cal.add_component(event)
|
| 52 |
+
|
| 53 |
+
# Save to file
|
| 54 |
+
output_path = f"data/outputs/event_{datetime.now().strftime('%Y%m%d_%H%M%S')}.ics"
|
| 55 |
+
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
|
| 56 |
+
|
| 57 |
+
with open(output_path, 'wb') as f:
|
| 58 |
+
f.write(cal.to_ical())
|
| 59 |
+
|
| 60 |
+
return {
|
| 61 |
+
'success': True,
|
| 62 |
+
'output_path': output_path,
|
| 63 |
+
'event': {
|
| 64 |
+
'title': title,
|
| 65 |
+
'start': start_dt.isoformat(),
|
| 66 |
+
'end': end_dt.isoformat(),
|
| 67 |
+
'description': description
|
| 68 |
+
}
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
except Exception as e:
|
| 72 |
+
return {'error': str(e), 'success': False}
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def parse_datetime(dt_string: str) -> datetime:
|
| 76 |
+
"""Parse datetime from various formats"""
|
| 77 |
+
try:
|
| 78 |
+
# Try ISO format
|
| 79 |
+
return datetime.fromisoformat(dt_string.replace('Z', '+00:00'))
|
| 80 |
+
except:
|
| 81 |
+
pass
|
| 82 |
+
|
| 83 |
+
try:
|
| 84 |
+
# Try common formats
|
| 85 |
+
for fmt in ['%Y-%m-%d %H:%M', '%Y-%m-%d', '%m/%d/%Y %H:%M', '%m/%d/%Y']:
|
| 86 |
+
try:
|
| 87 |
+
dt = datetime.strptime(dt_string, fmt)
|
| 88 |
+
return pytz.UTC.localize(dt)
|
| 89 |
+
except:
|
| 90 |
+
continue
|
| 91 |
+
except:
|
| 92 |
+
pass
|
| 93 |
+
|
| 94 |
+
# Default to now
|
| 95 |
+
return datetime.now(pytz.UTC)
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
async def create_multiple_events(events: list) -> dict:
|
| 99 |
+
"""Create multiple calendar events from a list"""
|
| 100 |
+
results = []
|
| 101 |
+
for event_data in events:
|
| 102 |
+
result = await create_calendar_event(**event_data)
|
| 103 |
+
results.append(result)
|
| 104 |
+
|
| 105 |
+
successful = sum(1 for r in results if r.get('success'))
|
| 106 |
+
|
| 107 |
+
return {
|
| 108 |
+
'success': True,
|
| 109 |
+
'total_events': len(events),
|
| 110 |
+
'successful': successful,
|
| 111 |
+
'results': results
|
| 112 |
+
}
|