Skip to content

Commit a961133

Browse files
committed
feat: support multiple events extraction and creation
1 parent 071103c commit a961133

File tree

4 files changed

+30
-22
lines changed

4 files changed

+30
-22
lines changed

projects/packages/ai-calendar-assistant/info.plist

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
<key>modifiersubtext</key>
1717
<string></string>
1818
<key>vitoclose</key>
19-
<false></false>
19+
<true></true>
2020
</dict>
2121
</array>
2222
</dict>
2323
<key>createdby</key>
2424
<string>Aviv Ben Shahar</string>
2525
<key>description</key>
26-
<string>TODO</string>
26+
<string>Effortlessly create calendar events using natural language with AI Calendar Assistant ✨</string>
2727
<key>disabled</key>
2828
<false></false>
2929
<key>name</key>
@@ -110,11 +110,16 @@ This workflow has been created using Fast Alfred, a user-friendly workflow build
110110
111111
## Features
112112
113-
// TODO
113+
- **Natural Language Processing:** Create events using everyday language.
114+
- **Automatic Detail Extraction:** Intelligently extracts the event title, date, time, and duration.
115+
- **Timezone Correction:** Automatically adjusts for your local timezone.
116+
- **Flexible Time Input:** Understands relative dates like "next Monday" or "tomorrow morning."
114117
115118
## Usage
116119
117-
// TODO
120+
1. Type `ca` in Alfred to activate the workflow (configurable in the workflow settings).
121+
2. Enter the event details in natural language (e.g., "Meeting with John next Friday at 2pm for like 2-3 hours").
122+
3. Press Enter to create the event in your calendar.
118123
119124
To view the workflow codebase, click here:
120125
https://github.com/Avivbens/alfredo</string>

projects/packages/ai-calendar-assistant/src/common/prompts/extract-event-name.prompt.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,37 @@ import { PromptTemplate } from '@langchain/core/prompts';
33
export const EXTRACT_EVENT_SYSTEM_PROMPT = new PromptTemplate({
44
inputVariables: ['currentDate'],
55
template: `You are an AI assistant that extracts calendar event details from text.
6-
Your task is to analyze the user's input and generate a valid JSON object containing the extracted information.
6+
Your task is to analyze the user's input and generate a list of events.
77
Pay close attention to the context to determine the correct date and time, especially for relative dates like "next Monday" or "tomorrow".
88
The current date is: {currentDate}. Use this for relative dates.
9-
109
If no end time is specified, assume a 1-hour duration.
1110
If a general time of day is mentioned (e.g., 'morning', 'afternoon', 'evening'), use a reasonable time (e.g., 9am for morning, 3pm for afternoon, 7pm for evening).
12-
Your response must be ONLY the JSON object.
11+
Your response must be ONLY the list of events.
1312
1413
---
1514
Here are some examples of the expected key-value pairs.
1615
17-
Input: "I have a dentist appointment at 10:30 AM next Monday."
16+
Input: "I have a dentist appointment at 10:30 AM next Monday and a meeting with the team at 3pm."
1817
Expected key-values:
18+
Event 1:
1919
summary: "Dentist appointment"
2020
startDate: "2025-06-30T10:30:00"
21-
endDate: "2025-06-30T11:30:00"
21+
endDate: "2025-06-30T11:30:00
22+
23+
Event 2:
24+
summary: "Meeting with the team"
25+
startDate: "2025-06-30T15:00:00"
26+
endDate: "2025-06-30T16:00:00"
2227
2328
---
2429
Input: "Book a meeting with the marketing team for this Friday from 2 to 3pm to review the new campaign. It will be on Google Meet."
2530
Expected key-values:
31+
Event 1:
2632
summary: "Meeting with the marketing team"
2733
startDate: "2025-06-27T14:00:00"
2834
endDate: "2025-06-27T15:00:00"
2935
description: "Review the new campaign."
30-
location: "Google Meet"
36+
location: Google Meet
3137
32-
---
33-
Input: "Let's have a quick sync tomorrow morning."
34-
Expected key-values:
35-
summary: "Quick sync"
36-
startDate: "2025-06-26T09:00:00"
37-
endDate: "2025-06-26T10:00:00"
3838
`,
3939
});

projects/packages/ai-calendar-assistant/src/main/extract-event.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { AvailableModels, callModelWithStructuredResponse } from '@alfredo/llm';
44
import { DEFAULT_DEBOUNCE_TIME } from '../common/defaults.constants';
55
import { EXTRACT_EVENT_SYSTEM_PROMPT } from '../common/prompts/extract-event-name.prompt';
66
import { Variables } from '../common/variables.enum';
7-
import { GeminiCalendarEventSchema, OpenAICalendarEventSchema } from '../models/calendar-event.model';
7+
import { GeminiCalendarEventsSchema, OpenAICalendarEventsSchema } from '../models/calendar-event.model';
88
import { adjustForTimezone, beautifyDate } from '../services/date.service';
99

1010
(async () => {
@@ -37,18 +37,16 @@ import { adjustForTimezone, beautifyDate } from '../services/date.service';
3737
/**
3838
* Select schema based on the model
3939
*/
40-
const calendarEventSchema = model.includes('gemini') ? GeminiCalendarEventSchema : OpenAICalendarEventSchema;
40+
const calendarEventsSchema = model.includes('gemini') ? GeminiCalendarEventsSchema : OpenAICalendarEventsSchema;
4141

4242
const system = await EXTRACT_EVENT_SYSTEM_PROMPT.format({ currentDate: new Date().toISOString() });
43-
const event = await callModelWithStructuredResponse(
43+
const events = await callModelWithStructuredResponse(
4444
token,
4545
model,
4646
{ system, user: alfredClient.input },
47-
calendarEventSchema,
47+
calendarEventsSchema,
4848
);
4949

50-
const events = [event];
51-
5250
const items: AlfredListItem[] = events.map((currEvent) => {
5351
const { allDayEvent, endDate, startDate, summary, description, location, url } = currEvent;
5452

projects/packages/ai-calendar-assistant/src/models/calendar-event.model.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ export const OpenAICalendarEventSchema = z
5050
})
5151
.transform(eventTransform);
5252

53+
export const OpenAICalendarEventsSchema = z.array(OpenAICalendarEventSchema);
54+
5355
// Schema for Gemini models: uses .optional() for optional fields
5456
export const GeminiCalendarEventSchema = z
5557
.object({
@@ -63,4 +65,7 @@ export const GeminiCalendarEventSchema = z
6365
})
6466
.transform(eventTransform);
6567

68+
export const GeminiCalendarEventsSchema = z.array(GeminiCalendarEventSchema);
69+
6670
export type CalendarEvent = z.infer<typeof GeminiCalendarEventSchema>;
71+
export type CalendarEvents = z.infer<typeof GeminiCalendarEventsSchema>;

0 commit comments

Comments
 (0)