於 MacOS 中,整合自然語言,自動化添加行事曆事件

這是一個嘗試更快添加行事曆安排的功能,主打一個透過自然語言 + 問答流程來添加想到的行事曆。

主要的應用流程:

  1. 工作到一半想到排程和順序。
  2. 在 LM UI 介面、IDE、瀏覽器網址列或是文字編輯上把會議排程描述出來。
  3. 選取文字按右鍵,選擇執行服務(或是快捷建,記得住嗎?)
  4. 服務運作,系統詢問/補足必要時間、地點等。
  5. 服務紀錄日曆排程。

* 如果是會議中,與人討論敲定的時間,描述的自然語言可以再傳給對方。

適用對象:

  1. 適用於腦袋比較跳躍,或是想要避免開門效應,不想要切換螢幕畫面的用戶。
  2. 不喜歡講話,也就是 SIRI 常年關閉的用戶。
  3. 使用 MacOS 的用戶。這是必須的。

附上說明:

操作上使用 Automator 建立整個 MacOS 的服務功能。

  1. 打開「Automator」應用程式
  2. 建立新的「快速動作」(Quick Action)
  3. 設定:
    • 工作流程接收目前:文字
    • 於:任何應用程式
  1. 拖入「執行 AppleScript」
  2. 將原始碼貼上 / 修改 calendarName:添加 / 修改自己的日曆名稱
  3. 儲存為「建立日曆事件」

使用方法:

  1. 在任何 App 中選取文字
  2. 點右鍵 → 服務 → 建立日曆事件

行程就會透過 MacOS 的服務功能,添加至日曆裡面。

再看看有沒有更方便的作法,其中可以再添加「行程邀請其他用戶」的功能,不過自己比較不用 mac 內建 mail 服務,也不太習慣寄行程給人就先不用。有興趣的朋友可以自己添加一下來跑。

在Mac 中,服務這機制應該是可以利用的模式,應該目標是可以使用自然語言一鍵呼叫讓他自動判斷要做什麼。
終極的想像還是預測啊,那個仰望的聖杯。
不過這如果無法做到離線運作的話有些太可怕了,看有沒有辦法做到最小主動意圖就能精準動作的操作流程。

最後備份一下原始碼:

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

property calendarName : "自動化生成" -- 請添加 / 修改為你自己的日曆名稱

on run {input, parameters}
	set theQuery to input as text
	set theString to current application's NSString's stringWithString:theQuery
	
	-- 偵測時間
	set dateDetector to current application's NSDataDetector's dataDetectorWithTypes:(current application's NSTextCheckingTypeDate) |error|:(missing value)
	set theRange to current application's NSMakeRange(0, theString's |length|())
	set dateMatch to dateDetector's firstMatchInString:theString options:0 range:theRange
	
	if dateMatch ≠ missing value then
		set startDate to dateMatch's |date|() as date
		if startDate < (current date) then set startDate to startDate + 1 * days
		set endDate to startDate + (1 * hours)
		
		set dateRange to dateMatch's range()
		set matchString to theString's substringWithRange:dateRange
		set cleanedTitleNSString to theString's stringByReplacingCharactersInRange:dateRange withString:""
		set eventTitle to cleanedTitleNSString as string
	else
		set validInput to false
		repeat until validInput is true
			display dialog "⚠️ 未能自動偵測時間,請手動輸入(格式:2025/06/10 15:30):" default answer ""
			set userInput to text returned of result
			try
				set startDate to date userInput
				set validInput to true
			on error
				display dialog "❌ 格式錯誤,請重新輸入(範例:2025/06/10 15:30)" buttons {"OK"} default button 1
			end try
		end repeat
		set endDate to startDate + (1 * hours)
		set eventTitle to theQuery
	end if
	
	-- 偵測地點
	set addressDetector to current application's NSDataDetector's dataDetectorWithTypes:(current application's NSTextCheckingTypeAddress) |error|:(missing value)
	set addressMatch to addressDetector's firstMatchInString:theString options:0 range:theRange
	
	if addressMatch ≠ missing value then
		set addressDict to addressMatch's addressComponents()
		set locationString to (addressDict's objectForKey:"Name") as string
		if locationString is missing value or locationString is "" then
			set locationString to (theString's substringWithRange:(addressMatch's range())) as string
		end if
	else
		display dialog "未偵測到地點,請手動輸入地點(可留空):" default answer ""
		set locationString to text returned of result
	end if
	
	-- 請使用者輸入附註
	display dialog "請輸入附註內容(可留空):" default answer ""
	set notesContent to text returned of result
	
	-- 建立事件
	tell application "Calendar"
		activate
		set theCalendar to first calendar whose name is calendarName
		set newEvent to make new event at end of events of theCalendar with properties {summary:eventTitle, start date:startDate, end date:endDate, location:locationString, description:notesContent}
		
		-- 加入提醒
		tell newEvent
			make new display alarm at end with properties {trigger interval:-60} -- 1 小時前
			make new display alarm at end with properties {trigger interval:-30} -- 30 分鐘前
			
			-- 若活動超過一天後,加入 1 天前提醒
			set nowDate to current date
			if (startDate - nowDate) > (1 * days) then
				make new display alarm at end with properties {trigger interval:-1440}
			end if
		end tell
	end tell
end run