• n8n + Line Bot + Google Sheets 自動化記帳機器人完整教學:整合 GPT 與 Gemini 辨識圖片記帳流程

補 : 上了官方模版 https://n8n.io/workflows/6264-auto-expense-tracker-from-line-messages-with-gpt-4-and-google-sheets/

一開始在 threads 看到有人分享 n8n藥單辨識 Extract Structured Data from Medical Documents with Google Gemini AI 的模板

好像可以把裡面的圖片辨識節點拿來用?

自己常常忘記記帳,月底想不起來刷卡外的花費,於是萌生了做一個可以口述文字/圖片辨識記帳機器人的想法

因為是要隨時回傳的,這次部署在 Zeabur

參考模板:藥單辨識

先用 postman 測試 Zeabur 能不能收到圖片
找了張圖片上傳 Postimages

Webhook
點 listen for event
截圖 2025-07-18 15.35.41

到 Postman,選 POST + 貼上 test url
Header
截圖 2025-07-18 15.34.49

Body
截圖 2025-07-18 15.34.53

Send -> 回到 Webhook
確定有收到
截圖 2025-07-18 15.35.49

Line Bot 個人記帳助理

截圖 2025-07-21 17.36.10

1. 設置 Line Bot

登入 Line Developers

創一個 provider -> create new channel 選 Messaging API -> 填寫 Channel 資訊
截圖 2025-06-10 00.47.48
1752924144889

截圖 2025-06-10 00.48.45

截圖 2025-07-18 15.44.04

1752924178587

Line 有更新,現在需要進到 LINE Official Account Manager 啟用 API

點進設好的 Provider -> 右上角齒輪 設定 -> Messaging API -> 啟用

1752924210081

1752924228171

1752937988384

1752924293036

創建成功
1752825662365

回到 line,會看到設好的 line bot
1752938064241

現在再回到 Line Developers 重整
剛才的 Provider 就會有資料了

1752924391240

2. n8n Webhook

n9n 新增第一個節點

test 的網址複製下來 -> 按 listen for the test event
1752938180511

回到 Line Developers
點 Messaging API settings
把 n8n Webhook test-url 貼上 -> verify
出現 success 代表有成功收到
PS 下方 use Webhook 要打開
1752924424667

點選 Listen for the test event (接下來都是在測試環境,傳任何訊息都要先點一次) -> line bot 發送訊息
Webhook 就會出現了

line bot 回覆的訊息先不管它,最後再來改
截圖 2025-07-18 16.34.33

回到 n8n Webhook 節點有收到資料就可以繼續
1752938153624

3. Swift message/image 分流處理資料

新增分流節點
分出收到的訊息是文字 text / 圖片 image
1752936195768

– text_openai

截圖 2025-07-21 17.51.10

設一個 set 提取 text
1752936230799

接 AI Agent
prompt

分析出資訊:
先判斷是否為記帳相關明細、發票,若不是則不需要處理,直接停止所有流程。若是記帳相關,分析出六個資訊:
1. 日期(如果只提到'今天',用{{ $now.format('YYYY-MM-DD') }} ) 2. 通路 3. 通路類型(只能為:便利商店、個人用品店、量販超市、傳統市場、網路購物、藥局、五金百貨、餐廳小吃店、醫療院所、3C商場、航空客運、軟體儲值、加油交通儲值、線上課程、電信公司)4. 花費明細 5. 金額 6. 類別(只能為:家用、正餐飲食、飲料甜點、生活用品、美妝、衣服飾品、交通、娛樂、電信、醫療、3C、軟體、學習、旅遊)。若通路類型判斷為航空客運,類別一定為旅遊。若無法判斷或沒資訊,請填入'DN',每格都要有資料。請輸出為 JSON 格式,例如:{\"日期\": \"...\", \"通路\": \"...\", \"通路類型\": \"...\", \"花費明細\": \"...\", \"金額\": \"...\", \"類別\": \"...\"}"

下面 Chat Model 點開,放 api key + 選模型
截圖 2025-07-19 15.04.32

截圖 2025-07-19 15.34.33

設一個 Structured Output Parser,指定輸出格式
截圖 2025-07-21 18.01.32

– image_openai

截圖 2025-07-21 17.51.10

設一個 Https
回到 Line Developers
點 Messaging API settings
滑到下面,產生一個 Channel access token 複製下來

Send Headers 打開
Name: Authorization
Value: Bearer Channel access token

1752828770753

1752936295331

之後一樣接 AI Agent

– image_gemini

PS 這裡只是想試試藥單辨識模板的做法,如果不想用 gemini,可以直接跳過這段,最後我的模板只接 AI Agent

截圖 2025-07-19 16.08.02

設一個 Https
這裡改用 gemini
回到 Line Developers
點 Messaging API settings
滑到下面,產生一個 Channel access token 複製下來

Send Headers 打開
Name: Authorization
Value: Bearer Channel access token

1752828770753

1752936295331

設一個 Extract from File
從檔案中擷取出特定的資料內
截圖 2025-07-19 15.23.08

設一個 set (prepare for AI)
只提取裡面的 data
截圖 2025-07-19 15.23.35

設一個 Https
image post 到gemini

https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent

截圖 2025-07-19 16.08.34

設一個 code 整理
請 gpt 幫我寫的

return items.map(item => {
  // 1. 提取 JSON 數據
  if (item.json.candidates?.[0]?.content?.parts?.[0]?.text) {
    const textContent = item.json.candidates[0].content.parts[0].text;

    // 移除 Markdown 的 ```json\n 和 \n``` 標記
    const jsonString = textContent.replace(/^```json\n/, '').replace(/\n```$/, '');

    try {
      const parsedData = JSON.parse(jsonString);
      // 將解析後的數據合併到 item.json 中
      item.json = { ...item.json, ...parsedData };
      // 可選:刪除原始的 Gemini API 響應結構,如果你不再需要它
      delete item.json.candidates;
      delete item.json.usageMetadata;
      delete item.json.modelVersion;
      delete item.json.responseId;

    } catch (e) {
      console.error("Error parsing JSON from Gemini text content:", e);
      // 處理解析錯誤,例如設置一個錯誤標誌或保留原始數據
    }
  }

  // 2. 提取 replyToken (如果 Gemini API 的輸出中也包含 LINE 的 body/events 結構)
  // 這通常發生在 Line Trigger 直接連接到 Gemini 節點時
  if (item.json.body?.events?.[0]?.replyToken) {
    item.json.replyToken = item.json.body.events[0].replyToken;
    delete item.json.body; // 刪除原始的 body 結構
  }

  return item; // 返回處理後的項目
});

截圖 2025-07-19 16.08.34

4. 提取去重使用欄位

為了防止自己重複紀錄,這裡提取去重使用欄位,之後用來比對
截圖 2025-07-21 18.24.43

5. 比對資料是否已存在

截圖 2025-07-21 18.26.10

寫入資料前,比對 google 去重使用欄位是不是一樣
一樣 -> 不寫入
不一樣 -> 寫入

設一個 google sheet
截圖 2025-07-22 09.49.43

設一個 get rows in sheet
假設有資料,output 會讀到
截圖 2025-07-19 21.10.37

接著要判斷,這次新資料的去重使用欄位,是否存在於 get rows in sheet 的去重使用欄位
一開始我直接用 if 判斷,發現不能這樣做,就先提取到 list,再做比對
之後 Darrell 教我使用了 Aggregate

設一個 Aggregate
截圖 2025-07-22 10.36.34

設一個 merge_all 把要比對的兩份資料合起來

選 combine position
截圖 2025-07-22 10.37.36

6. Switch 判斷

我希望不管寫入或不寫入,都要回傳訊息,Line Bot 使用當個會話的 replytoken 來 reply

一開始我用 if 判斷,要回傳資料發現 Line Bot 的 replyToken 只能使用一次,但 n8n 會每個分支都跑過一遍,就改成用 userId POST, Darrell review 幫我改成 Switch,方便很多

截圖 2025-07-22 10.40.28

邏輯是

去重使用欄位沒有重複 -> 寫入,回傳"✅ 記帳成功 <明細> "

去重使用欄位 = 'DN-DN-DN-DN' -> 不寫入,回傳"不相關明細或圖片,不會計入"
(前面下的prompt,判斷不出來,所有欄位會是DN,去重使用欄會出現'DN-DN-DN-DN')

去重使用欄位 正則表達配對 '^.*-DN-DN-DN

截圖 2025-07-22 10.48.27

截圖 2025-07-22 10.58.09

– ✅ 記帳成功 <明細>

設一個 google sheet
截圖 2025-07-22 11.27.52

設一個 Https
url = https://api.line.me/v2/bot/message/reply
Send Headers 打開
Name: Authorization
Value: Bearer Channel access token
Name: Content-Type
Value: application/json

Body json

{
  "replyToken": "{{ $('Webhook').item.json.body.events[0].replyToken }}",
  "messages": [
    {
      "type": "text",
      "text": "✅ 記帳成功: {{ $('Merge_all').item.json['去重使用'] }}"
    }
  ]
}

截圖 2025-07-22 11.29.58
截圖 2025-07-22 11.33.28

– 不相關明細或圖片,不會計入

設一個 Https
url = https://api.line.me/v2/bot/message/reply

Send Headers 打開

Name: Authorization
Value: Bearer Channel access token
Name: Content-Type
Value: application/json

Body json

{
  "replyToken": "{{ $('Webhook').item.json.body.events[0].replyToken }}",
  "messages": [
    {
      "type": "text",
      "text": "不相關明細或圖片,不會計入"
    }
  ]
}

截圖 2025-07-22 11.24.02

截圖 2025-07-22 11.33.59

– ⚠️ 此筆資料已記錄過,不會重複記帳

設一個 Https
url = https://api.line.me/v2/bot/message/reply
Send Headers 打開

Name: Authorization
Value: Bearer Channel access token
Name: Content-Type
Value: application/json

Body json

{
  "replyToken": "{{ $('Webhook').item.json.body.events[0].replyToken }}",
  "messages": [
    {
      "type": "text",
      "text": "⚠️ 此筆資料已記錄過,不會重複記帳"
    }
  ]
}

截圖 2025-07-22 11.25.30

截圖 2025-07-22 11.32.48

7.改自動回應訊息/圖片

進到 LINE Official Account Manager

點頭像可以直接改
截圖 2025-07-19 22.27.57

截圖 2025-07-19 22.27.34

自動回應訊息
截圖 2025-07-19 21.59.44
截圖 2025-07-19 22.28.24

基本檔案 -> 改背景圖
截圖 2025-07-19 22.01.16

截圖 2025-07-19 22.26.32

8. 正式部署

回到 n8n
上面的 Active 打開
截圖 2025-07-22 11.36.57

Webhook,複製 Production URL
1752936963480

回到 Line Developers
點 Messaging API settings
改 n8n Webhook url -> verify
出現 success 代表有成功收到,部署成功

1752935431325

月底拉個樞紐分析圖表,就會很清楚花費佔比了
截圖 2025-07-19 22.59.05

-> 不寫入,回傳"不相關明細或圖片,不會計入" (我有時候手殘,打到一半就按到送出,去重使用欄會出現'2025-01-01-DN-DN-DN) 去重使用欄位 = '---' ->不寫入,回傳"不相關明細或圖片,不會計入" (傳不相關照片時,有可能會全空值,去重使用欄會出現'---') 去重使用欄位重複 -> 不寫入,回傳"⚠️ 此筆資料已記錄過,不會重複記帳" 

截圖 2025-07-22 10.48.27

截圖 2025-07-22 10.58.09

– ✅ 記帳成功 <明細>

設一個 google sheet
截圖 2025-07-22 11.27.52

設一個 Https
url = https://api.line.me/v2/bot/message/reply
Send Headers 打開
Name: Authorization
Value: Bearer Channel access token
Name: Content-Type
Value: application/json

Body json

 

截圖 2025-07-22 11.29.58
截圖 2025-07-22 11.33.28

– 不相關明細或圖片,不會計入

設一個 Https
url = https://api.line.me/v2/bot/message/reply

Send Headers 打開

Name: Authorization
Value: Bearer Channel access token
Name: Content-Type
Value: application/json

Body json

 

截圖 2025-07-22 11.24.02

截圖 2025-07-22 11.33.59

– ⚠️ 此筆資料已記錄過,不會重複記帳

設一個 Https
url = https://api.line.me/v2/bot/message/reply
Send Headers 打開

Name: Authorization
Value: Bearer Channel access token
Name: Content-Type
Value: application/json

Body json

 

截圖 2025-07-22 11.25.30

截圖 2025-07-22 11.32.48

7.改自動回應訊息/圖片

進到 LINE Official Account Manager

點頭像可以直接改
截圖 2025-07-19 22.27.57

截圖 2025-07-19 22.27.34

自動回應訊息
截圖 2025-07-19 21.59.44
截圖 2025-07-19 22.28.24

基本檔案 -> 改背景圖
截圖 2025-07-19 22.01.16

截圖 2025-07-19 22.26.32

8. 正式部署

回到 n8n
上面的 Active 打開
截圖 2025-07-22 11.36.57

Webhook,複製 Production URL
1752936963480

回到 Line Developers
點 Messaging API settings
改 n8n Webhook url -> verify
出現 success 代表有成功收到,部署成功

1752935431325

月底拉個樞紐分析圖表,就會很清楚花費佔比了
截圖 2025-07-19 22.59.05

Catalina
Catalina

Hi, I’m Catalina!
原本在西語市場做開發業務,2023 年正式轉職資料領域。
目前努力補齊計算機組織、微積分、線性代數與機率論,忙碌中做點筆記提醒自己 🤲

文章: 43

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *