[AI 自動化] 用 n8n 做刷卡消費記錄(富邦、國泰、匯豐)

上次 n8n 試用結束後,因為發現 Make 比較便宜,就跳槽過去了。後來有網友留言,推薦我試試自架 n8n,我馬上心動就也來自架了,結果真的一試上癮

目前已經把上次 Make 的流程搬過來,要拋棄 Make 了。Productivity tool 的世界真殘酷。哪個稍微更 productive,使用者馬上就跳走...

喜歡 n8n 因為:

  1. 內建 node 種類多
  2. HTTP Request 和 Webhook 非常彈性且強大,基本上等於是快速串 API 的方式
  3. 介面回饋速度更快、效能高
  4. Open Source
  5. Workflow 設定本身就是一個 json,非常容易共享
  6. 社群討論和 templates 分享還算活躍

n8n 架設真的很簡單。我架了一個在我的 AWS,使用 docker compose,教學可以看這篇。有遇到一些小卡,主要是我用 nginx 做 redirect,所以沒用到 traefik,一開始沒發現而相衝。但沒有什麼是 AI 回答不出來的,順利裝好。

後來又幫公司裝一個在 heroku,看這篇教學。也有一些 .env 設定的小卡住,但後來也解決了。如果你對於自架 n8n 有遇到問題,歡迎私訊問我。我的 IG 是 @hanamizuki。

接下來開始建立吧!

建立 Workflow

在 Make 叫做 Scenario,在 n8n 是 Workflow。下圖是原本 Make 的畫面以及 n8n 的畫面。

Make Scenario
n8n Workflow

基本邏輯一樣,

  1. Trigger: Gmail 收到交易通知
  2. Router: 根據信件類型要有不同的文字處理
  3. 請 AI 根據信件內容回傳欄位內容
  4. 送到 Google Sheet

因為已經用 Make 自動記帳兩週,有發現可以優化的地方,轉移到 n8n 的過程中又做了一些優化,如下。

  1. 調整富邦信用卡消費記錄的 search query
  2. AI prompt更完整,比如美金要到小數點後兩位,台幣不用等等
  3. 改用免費的 gemini 1.5 flash(也可以快速的自己換成其他 model)
  4. 優化了 Google Sheet 格式

建立 n8n 流程的第一步:Trigger

Trigger 選擇 Gmail,設定如下:

  • Pool Times: 我選每小時抓
  • Event: Message Recieved
  • Simplify: Off
    • 原本是希望打開的,打開的話輸出的格式比較乾淨。可是的,可恨的是,有幾家銀行的信件太過傳統,沒有 snippet、沒有純文字版本,只有落落長的 html。因此這邊還是必須打開,然後再用 parser 去整理內容。
  • Filters: 選 Search
    • 可以參考上篇 Search Query 教學

提供我的 Search Query 當參考

{from:(noreply@messaging.hsbc.com.tw) AND subject:(匯豐(台灣) "刷卡消費通知”)} OR {from:(hello@crypto.com) AND subject:(purchase complete)} OR {from:(@taipeifubon.com.tw) AND subject:(富邦 即時消費通知)} OR {from:(service@pxbillrc01.cathaybk.com.tw) AND subject:(國泰世華銀行消費彙整通知)} OR {from:(noreply@uber.com) AND {subject:(透過 Uber Eats 系統送出的訂單) OR subject:(在 Uber 平台上搭乘的行程)}} OR {from:(no_reply@email.apple.com) AND subject:(Your invoice)}
OR {from:(bot@heroku.com) AND subject:([billing] Heroku Invoice)}
OR {from:(invoice+statements) AND subject:receipt}
OR {from:(@stripe.com) AND subject:receipt}

這個範例可以記帳的範圍包含:

  1. 信用卡刷卡記錄:匯豐、富邦、國泰、crypto.com
  2. 消費記錄:Uber、Uber Eats、Apple、Stripe、Heroku

記帳時,「2. 消費記錄」純粹是為了補充「1. 信用卡刷卡記錄」的資訊,因為刷卡記錄通常沒有細項。

使用 Switch

Switch 是一個 router,能根據前面 node(也就是 trigger)傳過來的資訊,開出多條後續流程。因為每種資料要整理的方式可能不同。我的案例:

  • 國泰世華的通知是一天一封,並且只有肥大 html,裡面還有多筆消費,會需要從信件拆多筆出來
  • 其他信用卡交易通知都是一個交易一封
  • 消費記錄(像是 uber)算第三種,送到 google sheet 時要有不同處理,以免 double accounnting

設定如下:

  • Mode: Rules
  • Routing Rules:
    • 寄件者({{ $json.from.value[0].address }}) = service@pxbillrc01.cathaybk.com.tw 時,是國泰刷卡記錄
    • 寄件者是 \b(?:noreply@messaging\.hsbc\.com\.tw|hello@crypto\.com|taipeifubon\.com\.tw)\b 時,是其他信用卡刷卡記錄(匯豐、富邦、crypto.com)
    • 寄件者「不是」以上者些時,則是消費記錄

處理國泰消費彙整通知信

這部份我處理起來其實有點意興闌珊,要不是最近愛著 n8n ~~,國泰這樣的信件(和越來越爛又麻煩的優惠 ~~... 每次都忘記切換。對我就是用 Cube)看著看著我就想剪卡。

國泰的信件長這樣:

而這是一大包 table,如果直接 strip html 也不太行,因為輸出的格式會變得很亂,即使有四種 AI model,我還是不想給他們這麼大的閱讀挑戰。

好在看起來這包 table 每一筆資料都有一個 .spend_table,料想他們工程師應該不會一直改這個名稱,就這樣用了。

💡
如果你正在著手進行操作,這邊有個方便測試的小撇步。你可以先找出你想測試的那封信,然後用只有那封信有的關鍵字,比如我想找出上圖那封,我用了「Google CLOUD XRGQKv」在 Trigger 的 Search Query,然後測試 Trigger Node 即可。

如果你的 Trigger Node 已經試跑過而且有成功抓到你想測試的內容,可以按一下 pin。這樣即使之後重新整理,這個 node 不用重跑也會有資料可以測試。(不過全部完成要 enable 這個 workflow 時記得要 unpin)

如果你想直接在 gmail 裡面看信件的 html 長怎樣,也可以在 gmail 介面使用 Inspect ​選擇「Show Original 」​。

回到 n8n 設定,我們可以使用 n8n 內建的 HTML node。

  • Operation: Extract HTML Content
  • Source Data:JSON
  • JSON property: html
  • Extraction Values:
    • Key: spend
    • CSS selector: .spend-table
    • Return value: Text
    • Return array: True

這樣就可以把雜亂的 html 變成乾淨的兩筆資料。

接下來還有一個步驟,因為剛才回傳的是一筆裡面有 array 的資料,但 node 執行的是 line item,所以要用 split 把他變成兩筆資料。

我們用內建的 Split Out Node 即可。
Field to split out: spend

再來試跑,就會看到他變成右邊那樣兩筆資料。雖然這串文字很亂,但我們就丟給 AI 吧!

整理資料

在丟給 AI 前,我們先把我們要的資料整理好。可以用內建的 Set data node。

(2024/10/6 更新如下,主要是三種狀況的資料可能不同,要先整理好,不能只用一個 Set Data)

Set Data 0

  • Mode: Manual Mapping
  • Fields to Set:
    • email_date: {{ $('Switch').item.json.date }} 這邊抓信件的日期給 AI 當參考,因為信件內容有可能沒有日期
    • email_subject: {{ $('Switch').item.json.subject }} 這邊抓信件標題,一樣是給 AI 當參考,讓他知道他在閱讀的是這封信
    • email_content: {{ $ifEmpty($json.spend, $ifEmpty( $json.text, $json.html)) }} 這邊抓國泰資料,如果不是國泰的,就直接抓信件的 text,若是也沒有 text,就抓 html。
    • email_type: 0 從 router 出去目前有三條路,給個編號,後面會用到。

Set Data 1

  • Mode: Manual Mapping
  • Fields to Set:
    • email_date: {{ $json.date }}
    • email_subject: {{ $json.subject }}
    • email_content: {{ $ifEmpty( $json.text, $json.html) }} 直接抓信件的 text,若是也沒有 text,就抓 html。
    • email_type: 1

Set Data 2

  • Mode: Manual Mapping
  • Fields to Set:
    • email_date: {{ $json.date }}
    • email_subject: {{ $json.subject }}
    • email_content: {{ $ifEmpty( $json.text, $json.html) }} 直接抓信件的 text,若是也沒有 text,就抓 html。
    • email_type: 2

請 AI 閱讀信件並回傳帳務資訊

(2024/10/6 更新:需要新增 Merge 步驟,並把上面三個 Merge Data 分別透過 Input 1~3 整合進去)

資料都整理好,就可以給 AI 看了。可以用 n8n 的 Basic LLM Chain node,可以取名叫做「Extract details」。然後選擇 model。n8n 也已經幫大家串好很多 ai model 了。

目前我用過這幾種:

  1. OpenAI: 記得一定要用 4o-mini,4o 和最新的 o1 都超貴,上次選錯,一天就噴好多錢,真的要小心
  2. Gemini: 免費
  3. Claude: 最近幾個月開始訂閱的,覺得還不錯
  4. Groq: 剛開始用

至少以上四種都很好串,OpenAI 和 Claude 需要先支付一筆錢購買 credit,Gemini 和 Groq 則是免費的。一樣都是取的 API key 就可以 plug and play。大家可以自己考量看看。

我現在用 Gemini 是因為免費。

接下來進入設定。

  • Prompt: Define below
  • Text: 這是我的消費明細信件中的單筆消費內容,請幫我擷取內容來記帳。其中信件來源有 0, 1, 2 三種選項。0 是國泰卡明細,1 是其他信用卡明細,2 是消費記錄。如果是 2,card 欄位回傳 null。 這部份大家可以自己調整成你要的,就跟和 ChatGPT 說話一樣。
  • Require Specific Output Format: True
  • Chat Message:
    • Type Name or ID: User
    • Message Type: Text(也許之後可以試試截圖給他看?但目前先用文字)
    • Message:
      信件日期:{{ $json.email_date }}
      信件標題:{{ $json.email_subject }}
      信件內容:
      {{ $json.email_content }}
      信件來源:{{ $json.email_type }}
      

因為我們希望有輸出固定欄位,所以要加上一個 Output Parser。

  • Schema Type: define below
  • Input Schema:
{
  "title": "消費記錄 Schema",
  "description": "用於解析消費記錄信件的 Schema,包括日期、服務名稱、交易詳情、金額、類別、貨幣和卡片。",
  "type": "object",
  "properties": {
    "date": {
      "type": "string",
      "description": "交易日期,可參考信件日期或內容內的消費日期。若有多個日期,以最早的日期為主。格式為 'YYYY-MM-DD',例如 '2024-09-02'。",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "examples": ["2024-09-02"]
    },
    "service": {
      "type": ["string", "null"],
      "description": "服務或商店的名稱,例如 'GOOGLE'、'Uber' 等。",
      "examples": ["GOOGLE", "Uber Eats", "Uber", "CLAUDE.AI"]
    },
    "details": {
      "type": ["string", "null"],
      "description": "交易的詳細訊息,如海外刷卡、網路刷卡、餐廳名稱或消費細節。若無可留空或為 null。",
      "examples": ["Uber:從復興北路到民權東路", "餐廳名稱", null]
    },
    "amount": {
      "type": "number",
      "description": "交易金額。若為美元,保留小數點後兩位(如 50.12);若為台幣則使用整數(如 550)。",
      "examples": [50.12, 550]
    },
    "category": {
      "type": "string",
      "description": "交易類別",
      "enum": ["飲食", "交通", "日用品", "居住", "3C", "美容妝髮",
      "examples": ["飲食", "交通"]
    },
    "currency": {
      "type": "string",
      "description": "交易使用的貨幣代碼,如果金額是 NT$ 開頭,curreny 就是 TWD。",
      "enum": ["TWD", "USD", "JPY", "EUR", "SGD"],
      "examples": ["USD", "TWD"]
    },
    "card": {
      "type": ["string", "null"],
      "description": "交易使用的信用卡。",
      "enum": ["匯豐", "富邦", "Crypto.com Card", "國泰", null],
      "examples": ["匯豐", "國泰"]
    }
  },
  "required": ["date", "amount", "category", "currency"]
}

交易類別的部分可以自訂。

送到 Google Sheet

這部份相對單純,先準備好 Google Sheet。我這邊有一個範本。
https://docs.google.com/spreadsheets/d/1_IhdHj8bxtsfH2MRqKuU2LzJuzm4DaeKSw46eFcyYts/edit?gid=1617968863#gid=1617968863

是長這樣的:

在 n8n 建立一個 Google Sheet node。設定如下:

  • Credential to connect with: 選一個
  • Resource: Sheet Within Document
  • Operation: Append Row
  • Document: 貼上 Google Sheet 網址
  • Sheet: from list 選擇 raw data
  • Mapping Column Mode: Map Each Column Manually(如果選自動的話,他會去找 n8n 資料的欄位名稱和 Google 第一個 row 的名稱做比對,也是一種選擇,但我怕我腦殘去改 Google Sheet,所以這邊先手動寫死)
  • Value to send: 選擇剛才的欄位名稱,如 {{ $json.output.date }}

哇啦!這樣就完成啦!

其實如果你有興趣,上面這些步驟都可以省略直接複製下面這段 JSON 貼到 Workflow,就可以把上面提到的設定都一次匯入。這也是我很喜歡 n8n 的地方。把分享做的這麼方便,大家還不狂分享嗎? 那我為何不直接貼下面的 JSON?還要打這麼長的內容?

最後可以來 Test 一下,看看資料有沒有出現在你的 Google Sheet 上。沒有的話,可以到 Executions 看錯誤資訊,貼給 AI 看,通常很快可以獲得答案。如果有卡住也歡迎跟我說。

對帳方式

上面的流程基本把這些信用卡的紀錄都包含進去了,若 n8n 跑的順利,你每天進來 Google Sheet,什麼都不用做,直接在「book」這個 sheet 可以看到今天的交易記錄,是已經整合刷卡記錄和消費記錄的資訊放一起的。

有個 check 欄位則是方便大家確認這筆消費沒問題可以打勾的,Note 則是手動寫個筆記。像這樣:

點這邊看範例

結語

可以用 n8n 做 AI 自動化真的是很幸福的事情,打開了很多可能性。我現在還有用 n8n + AI 做 Twitter 分析、Segment、Amplitude、Databricks、Asana ... 等自動化,節省了不少時間,實在太快樂了!