iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
ChatGPT & Codex

AI 時代的輕量化開發:ChatGPT 打造 LINE 多模態記帳與續訂預警 Agent系列 第 15

[Day 15] 餵給 AI 的不只是帳單:用 Python 量化 SubWise 的消費結構

  • 分享至 

  • xImage
  •  

前言

前幾天完成訂閱管理與資料查詢後,SubWise 已經能夠「記住」使用者的消費與訂閱資料。但如果只能做到回答「我這個月花了多少錢?」,其實還不算真正的智慧管理。

比起單純把資料列出來,我更希望 SubWise 可以進一步回答「這個月到底花最多錢在哪裡?」「哪一種消費是目前最大的支出來源?」「平均每天大約花多少錢?」,甚至提醒使用者「你的餐飲支出占了本月消費的 89.2%,是目前最主要的消費來源」。

因此今天的目標,就是讓 SubWise 從「資料查詢工具」開始進化成「消費分析助手」。今天主要完成四件事:建立 analysis_service.py、計算消費總額與分類比例、找出最高支出類別與平均每日支出、將分析結果交給 LINE 顯示並產生第一版智慧消費提醒。

整體架構:

使用者 → LINE Bot → Gemini(判斷使用者意圖:analysis)
→ analysis_service.py → Google Sheets(取得消費資料)
→ Python 分析(總支出/分類統計/分類比例/最高支出類別/平均每日支出)
→ 智慧消費提醒 → LINE 回覆

這裡有一個很重要的設計概念:Gemini 負責「理解使用者想做什麼」,Python 負責「真正計算資料」,避免把所有工作都交給 AI。


今日實作實錄

一、建立 Analysis Service 的核心統計函式

新增 analysis_service.py,從 Google Sheets 取得既有消費資料,再用 Python 進行統計,主要建立了四個核心函式:

1. 計算各消費類別的金額calculate_category_totals(records),把所有消費按照 Category 分組,例如 Food: 150, Transport: 50, Food: 120, Food: 120, Transport: 50 會彙總成 Food: 390, Transport: 100

2. 計算各分類占比calculate_category_percentages(category_totals, total),例如總支出 930 元中 Food 花了 830 元,計算 830 ÷ 930 × 100 ≈ 89.2%。這個數字比單純告訴使用者「Food 花了 830 元」更有意義,因為使用者可以直接知道自己的 Food 支出已經占了將近九成。

3. 找出最高支出類別get_top_category(category_totals),透過 max() 找出金額最高的分類,以今天的測試資料來說就是 Food(NT$830,占比 89.2%),這也成為後面「智慧消費提醒」的重要依據。

4. 計算平均每日支出calculate_daily_average(total, period),今天是 8 月 16 日,本月總支出 NT$930 除以已經過的 16 天,得到「平均每日:NT$58」。比起只看到「本月花了 NT$930」,看到「平均每天約 NT$58」更容易建立對消費速度的直觀感受。

二、整合成完整分析結果

建立 get_expense_analysis(period="month"),把前面所有分析串起來:

Google Sheets → get_expenses() → filter_expenses() → calculate_expense_total()
→ calculate_category_totals() → calculate_category_percentages()
→ get_top_category() → calculate_daily_average()

最後整理成一個 Python Dictionary,今天實際測試得到:

{
    "period": "month",
    "total": 930.0,
    "category_totals": {"Food": 830.0, "Transport": 100.0},
    "category_percentages": {"Food": 89.2473, "Transport": 10.7527},
    "top_category": "Food",
    "top_amount": 830.0,
    "top_percentage": 89.2473,
    "daily_average": 58.125
}

這代表 SubWise 已經不只是「把 Google Sheets 讀出來」,而是開始對資料產生自己的分析結果。
https://ithelp.ithome.com.tw/upload/images/20260816/20178527yTqHDLjCco.png

三、把分析結果轉換成 LINE 看得懂的文字

建立 format_analysis_result(result),把 Python Dictionary 整理成適合 LINE 顯示的內容:

📊 SubWise 消費分析

📅 分析期間:month
💵 總支出:NT$930
📊 平均每日:NT$58

🔥 最高支出類別:
Food:NT$830 (89.2%)

📂 分類支出:
Food:NT$830 (89.2%)
Transport:NT$100 (10.8%)

SubWise 第一次算出真正的消費統計。從 Google Sheets 讀出來的原始資料,經過 Python 計算後,變成總支出、每日平均、分類占比這些對使用者有意義的數字,而不只是一筆一筆的流水帳:
https://ithelp.ithome.com.tw/upload/images/20260816/20178527KuZLlScU1k.png

四、加入第一版「智慧消費提醒」

今天最有趣的功能是 generate_spending_insight(result),讓 SubWise 開始不只是「報告數字」,而是嘗試對數字做出簡單的解讀,目前設定了三個層級:

  • 占比 ≥ 80%:「Food 類別占本月支出的 89.2%,是目前最主要的消費來源。」
  • 占比 ≥ 50%:「目前是你的主要支出類別。」
  • 其他情況:「目前最高支出類別為 Food,占本月支出的 xx.x%。」

雖然還不是複雜的 AI 理財模型,但已經具備一個很重要的概念:從資料 → 分析 → 解讀,這是 SubWise 從「記帳工具」往「智慧助理」發展的第一步。

五、讓 Gemini 學會辨識「分析」意圖

光有 analysis_service.py 還不夠,因為使用者輸入「幫我分析這個月的消費」時,Gemini 必須判斷這既不是新增消費、也不是查詢明細,而是「進行消費分析」。因此把 SubWise 的資料類型擴充成五種:expensesubscriptionqueryanalysischat

測試「幫我分析這個月的消費」,Gemini 成功回傳:

{
    "type": "analysis",
    "target": "expense",
    "period": "month"
}

Gemini 沒有直接去讀 Google Sheets,只負責回答「使用者想分析什麼?」,真正的資料處理還是交給 Python,讓 AI 與程式邏輯保持清楚的分工。
https://ithelp.ithome.com.tw/upload/images/20260816/20178527Jx91sr7tyF.png

六、在 app.py 接上 Analysis Service

app.py 加入 from analysis_service import analyze_expenses,並在 process_ai_message() 新增 elif data_type == "analysis" 分支,讓 SubWise 收到 Gemini 的 analysis 意圖後,呼叫 analyze_expenses(data),最後將分析結果回傳給 LINE。


今天踩到的坑:Service 層函式名稱沒對上

一開始測試時遇到 ImportError: cannot import name 'analyze_expenses' from 'analysis_service'。這個錯誤其實很有價值——當時 analysis_service.py 裡已經有 get_expense_analysis()format_analysis_result(),但還沒有真正提供 analyze_expenses()app.py 使用。問題不是 Google Sheets,也不是 Gemini API,而是 Service 層的函式名稱與 app.py 的呼叫名稱沒有對上,補齊函式後重新測試就成功了。

修正後重新測試「幫我分析這個月的消費」,成功看到完整流程:Gemini 判斷為消費分析 → analysis_service 分析 Google Sheets → 取得總支出 930、Food 830、Transport 100 → 產生完整的分析結果與智慧消費提醒,代表整條流程已經成功打通。


今日完成

  • 建立 analysis_service.py,完成消費總額、分類統計、分類百分比、最高支出類別、平均每日支出五項計算
  • 完成 LINE 分析結果格式化(format_analysis_result
  • 加入第一版智慧消費提醒(generate_spending_insight,三層級判斷)
  • Gemini 新增 analysis 意圖,資料類型擴充為 expense / subscription / query / analysis / chat
  • app.py 串接 Analysis Service,完成 AI → Service → Sheets 完整分析流程

明日預告

目前 SubWise 的消費分析只能看到「這個月花了多少」,但沒辦法回答「跟上個月比起來,我是花得比較多還是比較少?」。明天 Day 16,我將在 analysis_service.py 加入月份比較功能,讓 SubWise 能夠橫向比對不同月份的消費資料,找出支出的趨勢變化,讓消費分析從「單月快照」進化成「跨月趨勢」。我們明天見!


上一篇
[Day 14] Smart Default:當使用者沒說清楚該怎麼辦?SubWise 訂閱扣款日的智慧補全機制
下一篇
[Day 16] 消費數據不再只是數字:SubWise 加入月度比較分析
系列文
AI 時代的輕量化開發:ChatGPT 打造 LINE 多模態記帳與續訂預警 Agent16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言