使用 Groq AI、GAS 與 LINE Bot 自動管理行程:Google 行事曆整合全攻略
前言
在工作的時候常常會有各種的會議或行程,如果沒有馬上booking很容易就會忘記,因此我想藉由大語言模型製作一個行程紀錄小幫手,能夠萃取文字內容自動記錄行程,以下就用幾個步驟一步一步完成吧
步驟一.註冊groq
Groq有提供開源大語言模型(例如:llama3.3)的免費api可以使用,透過groq所提供的免費api就可以做為解析文字並輸出特定格式的大腦。
選擇free api key

我是直接用google帳號連動

建立API Key

也可以像chatgpt一樣可以直接在groq上面做提問

步驟二.取得LineToken
登入line 開發者

建立line bot 帳號

選擇messageAPI

建立完line bot 帳號後選擇messaging api即可以取得剛剛所建立的帳號token,可用於程式取得訊息與推送訊息,

步驟三.取得google行事曆ID
因為要用程式自動加入行程,因此需要取得行事曆的id,讓程式可以知道要加入行程的是哪一個行事曆,以下為取得行事曆id的步驟
到google 行事曆中的設定

新增一個日曆後(也可以使用既有的日曆),即可找到行事曆的id

步驟四.在google apps scripts 建立服務
從google 雲端硬碟中開啟google apps scripts,如下圖所示

將以下程式貼到google apps scripts並建立服務
程式如下
const LINE_ACCESS_TOKEN = "你的 LINE Channel Access Token";
const CALENDAR_ID = "你的 Google 行事曆 ID";
const GROQ_API_KEY = "你的 GROQ API Key";
const GROQ_MODEL = "llama-3.3-70b-versatile";//"mixtral-8x7b-32768"; // 可以選擇不同的模型
const MAX_RETRIES = 5; // 最多重試 5 次
// 解析 LINE Bot 傳入的訊息,並嘗試新增行程
function doPost(e) {
const event = JSON.parse(e.postData.contents);
event.events.forEach(e => {
if (e.type === "message" && e.message.type === "text") {
const userMessage = e.message.text;
const replyToken = e.replyToken;
const now_date = new Date().toISOString().split("T")[0]; // 取得 YYYY-MM-DD
let eventDetails = null;
let attempt = 0;
let llmOutput = ""; // 存放 LLM 嘗試的結果
while (attempt < MAX_RETRIES) {
let response = parseEventWithGROQ(userMessage, now_date);
if (response.raw) {
llmOutput = response.raw; // 儲存 LLM 嘗試解析的內容
}
if (response.parsed && isValidEvent(response.parsed)) {
eventDetails = response.parsed;
break; // 成功解析,跳出迴圈
}
attempt++;
}
// 如果 5 次都解析失敗,回覆錯誤訊息並提供 LLM 嘗試的結果
if (!eventDetails || !isValidEvent(eventDetails)) {
replyToUser(replyToken, `⚠️ 無法解析行程,請用以下格式輸入:
『會議 2025-02-10 14:00』
或
『2/15 10:00 和小明吃飯』
🛠 LLM 嘗試解析的結果:\\n\\n${llmOutput || "⚠️ LLM 無法提供有效結果"}`
);
return;
}
addEventToCalendar(eventDetails);
replyToUser(replyToken, `✅ 行程已新增:${eventDetails.title}\\n🕒 時間:${eventDetails.startTime}\\n🔔 已設置 30 分鐘前提醒`);
}
});
return ContentService.createTextOutput("OK");
}
// 透過 GROQ 大語言模型解析文字
function parseEventWithGROQ(text, now_date) {
const prompt = `
你是一個 AI 助理,專門解析行程資訊。請從以下文字提取行程資訊,請將民國轉為西元(例如:114年轉為2025年),
你需要先判斷現在日期,行程之時間必定大於現在日期,因此如果缺少年份資訊請補充
(例如:現在日期2025-03-01,使用者輸入03/05應為2025-03-05)
格式如下:
{
"title": "活動名稱",
"startTime": "YYYY-MM-DDTHH:MM:SS"
}
如果無法解析,請返回 null。
現在日期:${now_date}
使用者輸入:${text}
輸出(僅需輸出格式,其他無關之文字一定不能輸出):
`;
const url = "<https://api.groq.com/openai/v1/chat/completions>";
const payload = {
model: GROQ_MODEL,
messages: [{ role: "user", content: prompt }],
max_tokens: 100
};
const options = {
method: "post",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + GROQ_API_KEY
},
payload: JSON.stringify(payload)
};
try {
const response = UrlFetchApp.fetch(url, options);
const json = JSON.parse(response.getContentText());
const extractedText = json.choices[0].message.content;
let parsedJSON = null;
try {
parsedJSON = JSON.parse(extractedText); // 安全解析 JSON
} catch (error) {
Logger.log("JSON 解析錯誤: " + error);
}
return {
raw: extractedText, // LLM 回傳的原始內容
parsed: parsedJSON // 嘗試解析成 JSON(如果成功則使用)
};
} catch (error) {
Logger.log("GROQ API Error: " + error);
return { raw: "解析失敗", parsed: null };
}
}
// 檢查解析出的行程是否符合格式
function isValidEvent(eventDetails) {
if (!eventDetails || !eventDetails.title || !eventDetails.startTime) {
return false;
}
const datePattern = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$/;
return datePattern.test(eventDetails.startTime);
}
// 將行程新增到 Google 行事曆,並加入提醒
function addEventToCalendar(eventDetails) {
const calendar = CalendarApp.getCalendarById(CALENDAR_ID);
const startTime = new Date(eventDetails.startTime);
const endTime = new Date(startTime.getTime() + 60 * 60 * 1000); // 預設 1 小時後結束
// 創建行程並添加提醒
const event = calendar.createEvent(eventDetails.title, startTime, endTime);
// 設定提醒:
event.addPopupReminder(30); // 在行程開始前 30 分鐘彈出提醒
// event.addEmailReminder(60); // 在行程開始前 60 分鐘發送 Email 提醒
}
// 回覆使用者訊息
function replyToUser(replyToken, message) {
const url = "<https://api.line.me/v2/bot/message/reply>";
const payload = {
replyToken: replyToken,
messages: [{ type: "text", text: message }]
};
const options = {
method: "post",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + LINE_ACCESS_TOKEN
},
payload: JSON.stringify(payload)
};
UrlFetchApp.fetch(url, options);
}
會在上述程式中加入while (attempt < MAX_RETRIES)迴圈,而不是直接執行parseEventWithGROQ函式,是因為透過groq上所建立的llama3.3:70b模型,解析文字並輸出成特定格式的過程可能會輸出不合格式的情形,為了確保程式的穩定性因此做5次的遞迴,確保輸出格式正確,能夠加入google 行事曆。
將上述程式貼入google apps script (如下圖)。

點選新增部屬,部屬成網頁應用程式

部屬完成可以得到一串網址。

步驟五.部屬到line bot
將得到之網頁應用程式連結貼到line 中的webhook

完成可以開始使用
