把前面做的 expense.csv、tx_log.csv、amortization.csv、premium_quote.csv、customers_sanitized.csv、claims_sim.csv 等檔案整合成可互動的儀表板,能快速展示報表、圖表與下載功能,方便放作品集或面試 Demo。
說明:程式會自動檢查常用 CSV,若不存在會產生示範資料。
# day29_dashboard.py
import os
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
plt.rcParams['font.family'] = 'Heiti TC'
st.set_page_config(page_title="FinTech Mini Dashboard", layout="wide")
st.title("FinTech Mini Dashboard(迷你儀表板)")
st.markdown("展示:記帳、交易紀錄、貸款攤還、保險報價、KYC 掃描與理賠模擬。")
# ---------- helper: load or create demo data ----------
def ensure_expense():
path = "expense.csv"
if not os.path.exists(path):
demo = pd.DataFrame({
"日期": pd.to_datetime(["2025-08-01","2025-08-02","2025-08-03","2025-08-06","2025-08-07"]),
"類別": ["早餐","午餐","購物","交通","咖啡"],
"金額": [60,120,900,35,75]
})
demo.to_csv(path, index=False)
df = pd.read_csv(path)
if "日期" in df.columns:
try:
df["日期"] = pd.to_datetime(df["日期"])
except:
pass
return df
def ensure_txlog():
path = "tx_log.csv"
if not os.path.exists(path):
demo = pd.DataFrame([
{"id":"tx1","ts":datetime.now().isoformat(),"from":"Alice","to":"Bob","amount":120,"ccy":"TWD","memo":"午餐","status":"SUCCESS"},
{"id":"tx2","ts":datetime.now().isoformat(),"from":"Bob","to":"Alice","amount":50,"ccy":"TWD","memo":"咖啡","status":"SUCCESS"},
])
demo.to_csv(path, index=False)
return pd.read_csv(path)
def ensure_amort():
path = "amortization.csv"
if not os.path.exists(path):
demo = pd.DataFrame([
{"期數":1, "每期應繳":5100, "利息":1666.67, "本金":3433.33, "剩餘本金":996566.67},
{"期數":2, "每期應繳":5100, "利息":1664.28, "本金":3435.72, "剩餘本金":993130.95},
])
demo.to_csv(path, index=False)
return pd.read_csv(path)
def ensure_premium():
path = "premium_quote.csv"
if not os.path.exists(path):
demo = pd.DataFrame([
{"name":"Alice","age":29,"BMI":20.6,"年保費_估":6000},
{"name":"Bob","age":43,"BMI":28.7,"年保費_估":11700},
])
demo.to_csv(path, index=False)
return pd.read_csv(path)
def ensure_customers():
path = "customers_sanitized.csv"
if not os.path.exists(path):
demo = pd.DataFrame([
{"cust_id":"cust_a1","name_masked":"王*","email_masked":"m***@example.com","phone_masked":"***45678","card_masked":"411111******1111","is_email_valid":1,"is_card_valid":1,"issues":""},
])
demo.to_csv(path, index=False)
return pd.read_csv(path)
def ensure_claims():
path = "claims_sim.csv"
if not os.path.exists(path):
demo = pd.DataFrame([
{"policy_id":1,"claim_no":1,"gross":50000,"payout":45000},
{"policy_id":2,"claim_no":1,"gross":12000,"payout":7000},
])
demo.to_csv(path, index=False)
return pd.read_csv(path)
# load data
expense_df = ensure_expense()
tx_df = ensure_txlog()
amort_df = ensure_amort()
premium_df = ensure_premium()
cust_df = ensure_customers()
claims_df = ensure_claims()
# ---------- Layout: three columns of KPIs ----------
c1, c2, c3 = st.columns(3)
c1.metric("總支出(筆數)", expense_df.shape[0])
c2.metric("交易筆數", tx_df.shape[0])
c3.metric("理賠案件", claims_df.shape[0])
# ---------- 消費板塊 ----------
st.subheader("消費記錄(expense.csv)")
st.dataframe(expense_df)
with st.expander("消費圖表"):
try:
cat_sum = expense_df.groupby("類別")["金額"].sum().sort_values(ascending=False)
fig, ax = plt.subplots(figsize=(6,3))
cat_sum.plot(kind="bar", ax=ax)
ax.set_ylabel("金額")
st.pyplot(fig)
except Exception as e:
st.write("無法繪圖:", e)
st.download_button("下載 expense.csv", expense_df.to_csv(index=False).encode('utf-8'), file_name="expense.csv", mime="text/csv")
# ---------- 交易紀錄 ----------
st.subheader("交易紀錄(tx_log.csv)")
st.dataframe(tx_df)
st.download_button("下載 tx_log.csv", tx_df.to_csv(index=False).encode('utf-8'), file_name="tx_log.csv")
# ---------- 貸款攤還 ----------
st.subheader("貸款攤還表(amortization.csv)")
st.dataframe(amort_df.head(10))
st.markdown(f"每期應繳(示例,前一筆): {amort_df.loc[0,'每期應繳'] if not amort_df.empty else 'N/A'}")
st.download_button("下載 amortization.csv", amort_df.to_csv(index=False).encode('utf-8'), file_name="amortization.csv")
# ---------- 保費估算 ----------
st.subheader("保費估算(premium_quote.csv)")
st.dataframe(premium_df)
st.download_button("下載 premium_quote.csv", premium_df.to_csv(index=False).encode('utf-8'), file_name="premium_quote.csv")
# ---------- KYC / 客戶資料 ----------
st.subheader("KYC 去識別化(customers_sanitized.csv)")
st.dataframe(cust_df)
st.download_button("下載 customers_sanitized.csv", cust_df.to_csv(index=False).encode('utf-8'), file_name="customers_sanitized.csv")
# ---------- 理賠模擬 ----------
st.subheader("理賠模擬明細(claims_sim.csv)")
st.dataframe(claims_df.head(20))
st.download_button("下載 claims_sim.csv", claims_df.to_csv(index=False).encode('utf-8'), file_name="claims_sim.csv")
st.markdown("---")
st.info("提示:把你在前面日子產出的 CSV(expense.csv、tx_log.csv、amortization.csv、...)放到同一資料夾,重新整理頁面就能直接看到真實資料。")