From 4b37364b1f5fe783ca1843a37af92b3e8003fa0d Mon Sep 17 00:00:00 2001 From: Wei GENG Date: Mon, 6 Jan 2025 01:03:42 +0100 Subject: [PATCH 1/4] Update ai-text-to-calendar extension - fix lint - custom service - [add] multiple language and custom endpoint support - Initial commit --- extensions/ai-text-to-calendar/CHANGELOG.md | 6 +++ extensions/ai-text-to-calendar/README.md | 4 ++ .../ai-text-to-calendar/package-lock.json | 4 +- extensions/ai-text-to-calendar/package.json | 45 ++++++++++++++++--- .../src/ai-text-to-calendar.ts | 17 ++++--- 5 files changed, 61 insertions(+), 15 deletions(-) diff --git a/extensions/ai-text-to-calendar/CHANGELOG.md b/extensions/ai-text-to-calendar/CHANGELOG.md index f8489134498..13ec9787132 100644 --- a/extensions/ai-text-to-calendar/CHANGELOG.md +++ b/extensions/ai-text-to-calendar/CHANGELOG.md @@ -1,3 +1,9 @@ # AI Text to Calendar Changelog +## [Bug Fix and Enhancement] - {PR_MERGE_DATE} +- 🐞 Bug fix - preference api call and author id +- 👨‍🍳 Customable service - fill your own LLM service endpoint and model name +- 💬 Multiple Language Support - Set your preferred language for events +- 🍧 Minor prompt adjustment + ## [Initial Version] - 2024-12-09 diff --git a/extensions/ai-text-to-calendar/README.md b/extensions/ai-text-to-calendar/README.md index 7caeb8c58bf..f9b86496331 100644 --- a/extensions/ai-text-to-calendar/README.md +++ b/extensions/ai-text-to-calendar/README.md @@ -18,6 +18,10 @@ Configure the extension via `Raycast Settings > Extensions > AI Text to Calendar | `openAiApiKey` | OpenAI API Key | string | true | Your personal OpenAI API key | | `language` | Language | string | true | Language of the input text (e.g., English, 日本語) | +## TODO +- [ ] User default settings (e.g., default date, time) +- [ ] With supplementary information (e.g., selected text + user input) + ## License This project is licensed under the MIT License. diff --git a/extensions/ai-text-to-calendar/package-lock.json b/extensions/ai-text-to-calendar/package-lock.json index b9dd98deaa5..3081973b9c0 100644 --- a/extensions/ai-text-to-calendar/package-lock.json +++ b/extensions/ai-text-to-calendar/package-lock.json @@ -1,10 +1,10 @@ { - "name": "run-script-sample", + "name": "ai-text-to-calendar", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "run-script-sample", + "name": "ai-text-to-calendar", "license": "MIT", "dependencies": { "@raycast/api": "^1.86.1", diff --git a/extensions/ai-text-to-calendar/package.json b/extensions/ai-text-to-calendar/package.json index 19542dddf38..cd80707d787 100644 --- a/extensions/ai-text-to-calendar/package.json +++ b/extensions/ai-text-to-calendar/package.json @@ -4,7 +4,10 @@ "title": "AI Text to Calendar", "description": "Convert selected text to Google Calendar event with OpenAI", "icon": "extension-icon.png", - "author": "tatsuhiko_imaizumi", + "author": "izm51", + "contributors": [ + "ViGeng" + ], "categories": [ "Productivity" ], @@ -17,18 +20,48 @@ "mode": "no-view", "preferences": [ { - "name": "openAiApiKey", - "title": "OpenAI API Key", - "description": "API Key is used to authenticate with OpenAI API", + "name": "apiKey", + "title": "AI Service API Key", + "description": "API Key is used to authenticate with OpenAI or other AI service", "type": "password", "required": true }, + { + "name": "endpoint", + "title": "Custom API Endpoint", + "description": "Overide the default API endpoint", + "type": "textfield", + "required": false + }, + { + "name": "model", + "title": "Model Name", + "description": "Model name to use for the AI service", + "type": "textfield", + "default": "gpt-4o-mini", + "required": false + }, { "name": "language", "title": "Language", "description": "Language of the output", - "type": "textfield", - "required": true + "type": "dropdown", + "default": "English", + "data": [ + { "title": "English","value": "English" }, + { "title": "Chinese", "value": "Chinese"}, + { "title": "Japanese", "value": "Japanese"}, + { "title": "Korean", "value": "Korean"}, + { "title": "Spanish", "value": "Spanish"}, + { "title": "French", "value": "French"}, + { "title": "German", "value": "German"}, + { "title": "Italian", "value": "Italian"}, + { "title": "Dutch", "value": "Dutch"}, + { "title": "Portuguese", "value": "Portuguese"}, + { "title": "Russian", "value": "Russian"}, + { "title": "Arabic", "value": "Arabic"} + ], + "required": false } ] } diff --git a/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts b/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts index ca3cc657926..fac8efad284 100644 --- a/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts +++ b/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts @@ -1,4 +1,4 @@ -import { showHUD, Toast, showToast, getSelectedText, getPreferenceValues, Clipboard, open } from "@raycast/api"; +import { Clipboard, getPreferenceValues, getSelectedText, open, showHUD, showToast, Toast } from "@raycast/api"; import OpenAI from "openai"; interface CalendarEvent { @@ -13,11 +13,14 @@ interface CalendarEvent { export default async function main() { try { - const { openAiApiKey, language } = getPreferenceValues(); + const apiKey = getPreferenceValues().apiKey; + const endpoint = getPreferenceValues().endpoint; + const language = getPreferenceValues().language; + const model = getPreferenceValues().model; showToast({ style: Toast.Style.Animated, title: "Extracting..." }); const selectedText = await getSelectedText(); - const json = await ai(selectedText, openAiApiKey, language); + const json = await ai(selectedText, apiKey, language, endpoint, model); if (!json) { throw new Error("Extraction failed"); } @@ -37,13 +40,13 @@ export default async function main() { } } -async function ai(text: string, openaiKey: string, language: string) { +async function ai(text: string, openaiKey: string, language: string, endpoint: string, model: string) { const systemMessage = `\ Extract schedule information from the text provided by the user. The output should be in the following JSON format. { - title: string, // Event title + title: string, // Event title, should be descriptive and very concise start_date: YYYYMMDD, // Start date start_time: hhmmss, // Start time end_date: YYYYMMDD, // End date @@ -59,9 +62,9 @@ Note: * Ensure the location is easily identifiable * If the end date and time are unknown, set it to 2 hours after the start date and time\ `; - const openai = new OpenAI({ apiKey: openaiKey }); + const openai = new OpenAI({ apiKey: openaiKey, baseURL: endpoint }); const response = await openai.chat.completions.create({ - model: "gpt-4o-mini", + model: model, response_format: { type: "json_object" }, messages: [ { role: "system", content: systemMessage }, From 62fe2954484e65fd714ecaade6e45ab6fb9d7c76 Mon Sep 17 00:00:00 2001 From: Wei GENG Date: Mon, 6 Jan 2025 01:37:32 +0100 Subject: [PATCH 2/4] Update ai-text-to-calendar extension - fix lint - minor change --- extensions/ai-text-to-calendar/README.md | 11 +++++++---- extensions/ai-text-to-calendar/package.json | 1 + .../ai-text-to-calendar/src/ai-text-to-calendar.ts | 6 +++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/extensions/ai-text-to-calendar/README.md b/extensions/ai-text-to-calendar/README.md index f9b86496331..8781c50328a 100644 --- a/extensions/ai-text-to-calendar/README.md +++ b/extensions/ai-text-to-calendar/README.md @@ -13,14 +13,17 @@ AI Text to Calendar is a [Raycast](https://raycast.com/) extension that converts Configure the extension via `Raycast Settings > Extensions > AI Text to Calendar`. -| Property | Label | Type | Required | Description | -| -------------- | -------------- | ------ | -------- | ------------------------------------------------ | -| `openAiApiKey` | OpenAI API Key | string | true | Your personal OpenAI API key | -| `language` | Language | string | true | Language of the input text (e.g., English, 日本語) | +| Property | Label | Type | Required | Description | +| -------------- | -------------- | ------ | -------- | ------------------------------------------------------------------------------------------------ | +| `openAiApiKey` | OpenAI API Key | string | true | Your personal AI service API key | +| `model` | Model | string | false | LLM model name, default is `gpt-4o-mini` | +| `language` | Language | string | false | Language of the input text, default is `English` | +| `endpoint` | Endpoint | string | false | LLM service endpoint (e.g., https://api.deepseek.com/v1), default is `https://api.openai.com/v1` | ## TODO - [ ] User default settings (e.g., default date, time) - [ ] With supplementary information (e.g., selected text + user input) +- [ ] Support for other calendar services (e.g., use Apple Script or Shortcut for Apple Calendar) ## License diff --git a/extensions/ai-text-to-calendar/package.json b/extensions/ai-text-to-calendar/package.json index cd80707d787..394291f4496 100644 --- a/extensions/ai-text-to-calendar/package.json +++ b/extensions/ai-text-to-calendar/package.json @@ -31,6 +31,7 @@ "title": "Custom API Endpoint", "description": "Overide the default API endpoint", "type": "textfield", + "default": "https://api.openai.com/v1", "required": false }, { diff --git a/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts b/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts index fac8efad284..4ad9958c612 100644 --- a/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts +++ b/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts @@ -14,9 +14,9 @@ interface CalendarEvent { export default async function main() { try { const apiKey = getPreferenceValues().apiKey; - const endpoint = getPreferenceValues().endpoint; - const language = getPreferenceValues().language; - const model = getPreferenceValues().model; + const endpoint = getPreferenceValues().endpoint || "https://api.openai.com/v1"; + const language = getPreferenceValues().language || "English"; + const model = getPreferenceValues().model || "gpt-4o-mini"; showToast({ style: Toast.Style.Animated, title: "Extracting..." }); const selectedText = await getSelectedText(); From caa0c9f370b41da5c1a74b410f79972a7cd5ec1b Mon Sep 17 00:00:00 2001 From: Wei GENG Date: Mon, 13 Jan 2025 13:00:26 +0100 Subject: [PATCH 3/4] Update ai-text-to-calendar extension - fix lint - fix url bugs - update doc --- extensions/ai-text-to-calendar/README.md | 22 ++++++++++---- .../src/ai-text-to-calendar.ts | 29 +++++++++++++++++-- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/extensions/ai-text-to-calendar/README.md b/extensions/ai-text-to-calendar/README.md index 8781c50328a..1b7b3fccb9d 100644 --- a/extensions/ai-text-to-calendar/README.md +++ b/extensions/ai-text-to-calendar/README.md @@ -13,14 +13,15 @@ AI Text to Calendar is a [Raycast](https://raycast.com/) extension that converts Configure the extension via `Raycast Settings > Extensions > AI Text to Calendar`. -| Property | Label | Type | Required | Description | -| -------------- | -------------- | ------ | -------- | ------------------------------------------------------------------------------------------------ | -| `openAiApiKey` | OpenAI API Key | string | true | Your personal AI service API key | -| `model` | Model | string | false | LLM model name, default is `gpt-4o-mini` | -| `language` | Language | string | false | Language of the input text, default is `English` | -| `endpoint` | Endpoint | string | false | LLM service endpoint (e.g., https://api.deepseek.com/v1), default is `https://api.openai.com/v1` | +| Property | Label | Type | Required | Description | +| ---------- | ------------------ | ------ | -------- | -------------------------------------------------------------------------------------------------- | +| `apiKey` | AI Service API Key | string | true | Your personal AI service API key | +| `model` | Model Name | string | false | LLM model name, default is `gpt-4o-mini` | +| `language` | Language | string | false | Language of the output text, default is `English` | +| `endpoint` | Endpoint | string | false | LLM service endpoint (e.g., ), default is `https://api.openai.com/v1` | ## TODO + - [ ] User default settings (e.g., default date, time) - [ ] With supplementary information (e.g., selected text + user input) - [ ] Support for other calendar services (e.g., use Apple Script or Shortcut for Apple Calendar) @@ -28,3 +29,12 @@ Configure the extension via `Raycast Settings > Extensions > AI Text to Calendar ## License This project is licensed under the MIT License. + +## Example Test Cases + +| Test Case | gpt-4o-mini works? | gpt-4o works? | +| ---------------------------------------------------- | ------------------ | ------------- | +| `play tennis with Mike tommorrow at 5pm in the park` | ✓ | ✓ | +| `Math class next Monday at 10am in lecture hall` | x | ✓ | + +Tips: try to use advanced LLM models for better results, especially for date reasoning. \ No newline at end of file diff --git a/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts b/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts index 4ad9958c612..f760271f46c 100644 --- a/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts +++ b/extensions/ai-text-to-calendar/src/ai-text-to-calendar.ts @@ -41,6 +41,18 @@ export default async function main() { } async function ai(text: string, openaiKey: string, language: string, endpoint: string, model: string) { + // get current date and time to string format, to let the LLM know the current date and time + // date format: YYYY-MM-DD + const date_str = new Date().toISOString().split("T")[0]; + // time format: HH:MM:SS + const time_str = new Date().toISOString().split("T")[1].split(".")[0]; + // current week day + const week_day = new Date().getDay().toString(); + + console.log("date_str:", date_str); + console.log("time_str:", time_str); + console.log("week_day:", week_day); + const systemMessage = `\ Extract schedule information from the text provided by the user. The output should be in the following JSON format. @@ -57,10 +69,11 @@ The output should be in the following JSON format. Note: * Output in ${language} +* Current date: ${date_str}, Current time: ${time_str}, Current week day: ${week_day}, try to set the event date and time based on the current date and time * Do not include any content other than JSON format in the output * If the organizer's name is known, include it in the title * Ensure the location is easily identifiable -* If the end date and time are unknown, set it to 2 hours after the start date and time\ +* If the duration is not specified, assume it is 2 hours `; const openai = new OpenAI({ apiKey: openaiKey, baseURL: endpoint }); const response = await openai.chat.completions.create({ @@ -78,6 +91,18 @@ Note: } function toURL(json: CalendarEvent) { - const url = `https://calendar.google.com/calendar/render?action=TEMPLATE&text=${json.title}&dates=${json.start_date}T${json.start_time}/${json.end_date}T${json.end_time}&details=${json.details}&location=${json.location}&trp=false`; + // Clean up and format dates/times - remove any non-numeric characters + const startDateTime = `${json.start_date.replace(/-/g, "")}T${json.start_time.replace(/:/g, "")}00`; + const endDateTime = `${json.end_date.replace(/-/g, "")}T${json.end_time.replace(/:/g, "")}00`; + + // Encode parameters for URL safety + const params = { + text: encodeURIComponent(json.title), + dates: `${startDateTime}/${endDateTime}`, + details: encodeURIComponent(json.details), + location: encodeURIComponent(json.location), + }; + + const url = `https://calendar.google.com/calendar/render?action=TEMPLATE&text=${params.text}&dates=${params.dates}&details=${params.details}&location=${params.location}&trp=false`; return url; } From 022a8a5314bfb91d863923aa904f4bd13671d980 Mon Sep 17 00:00:00 2001 From: raycastbot Date: Wed, 15 Jan 2025 10:59:47 +0000 Subject: [PATCH 4/4] Update CHANGELOG.md and optimise images --- extensions/ai-text-to-calendar/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ai-text-to-calendar/CHANGELOG.md b/extensions/ai-text-to-calendar/CHANGELOG.md index 13ec9787132..9b96c1d3c53 100644 --- a/extensions/ai-text-to-calendar/CHANGELOG.md +++ b/extensions/ai-text-to-calendar/CHANGELOG.md @@ -1,6 +1,6 @@ # AI Text to Calendar Changelog -## [Bug Fix and Enhancement] - {PR_MERGE_DATE} +## [Bug Fix and Enhancement] - 2025-01-15 - 🐞 Bug fix - preference api call and author id - 👨‍🍳 Customable service - fill your own LLM service endpoint and model name - 💬 Multiple Language Support - Set your preferred language for events