import streamlit as st import pandas as pd import joblib import os import sys # 添加项目根目录到 Path 以便导入 src sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) from src.agent_app import MarketingAgent, CustomerFeatures # 配置页面 st.set_page_config( page_title="智能银行营销助手", page_icon="🤖", layout="wide" ) # 侧边栏:项目信息 with st.sidebar: st.title("🏦 智能营销系统") st.markdown("---") st.info("**Day 5 演示版**") st.markdown(""" **核心能力:** 1. 📊 **LightGBM** 客户购买预测 2. 🧠 **Agent** 策略生成 3. 📝 **Pydantic** 结构化输出 """) st.markdown("---") st.caption("由第 X 组开发") # 主界面 st.title("🤖 客户意向预测与决策系统") # 1. 模拟客户输入 st.header("1. 录入客户信息") col1, col2, col3 = st.columns(3) # 映射字典 job_map = { "management": "管理人员", "technician": "技术人员", "entrepreneur": "企业家", "blue-collar": "蓝领", "unknown": "未知", "retired": "退休人员", "admin.": "行政人员", "services": "服务业", "self-employed": "自雇人士", "unemployed": "失业", "maid": "家政", "student": "学生" } education_map = {"tertiary": "高等教育", "secondary": "中等教育", "primary": "初等教育", "unknown": "未知"} marital_map = {"married": "已婚", "single": "单身", "divorced": "离异"} binary_map = {"yes": "是", "no": "否"} contact_map = {"cellular": "手机", "telephone": "座机", "unknown": "未知"} month_map = { "jan": "1月", "feb": "2月", "mar": "3月", "apr": "4月", "may": "5月", "jun": "6月", "jul": "7月", "aug": "8月", "sep": "9月", "oct": "10月", "nov": "11月", "dec": "12月" } poutcome_map = {"unknown": "未知", "failure": "失败", "other": "其他", "success": "成功"} # 辅助函数:反向查找 key def get_key(val, my_dict): for key, value in my_dict.items(): if val == value: return key return val with col1: age = st.number_input("年龄", 18, 100, 30) job_display = st.selectbox("职业", list(job_map.values())) job = get_key(job_display, job_map) education_display = st.selectbox("教育", list(education_map.values())) education = get_key(education_display, education_map) balance = st.number_input("账户余额 (欧元)", -1000, 100000, 1500) with col2: marital_display = st.selectbox("婚姻", list(marital_map.values())) marital = get_key(marital_display, marital_map) housing_display = st.selectbox("是否有房贷", list(binary_map.values())) housing = get_key(housing_display, binary_map) loan_display = st.selectbox("是否有个人贷", list(binary_map.values())) loan = get_key(loan_display, binary_map) default_display = st.selectbox("是否有违约记录", list(binary_map.values())) default = get_key(default_display, binary_map) with col3: contact_display = st.selectbox("联系方式", list(contact_map.values())) contact = get_key(contact_display, contact_map) month_display = st.selectbox("最后联系月份", list(month_map.values())) month = get_key(month_display, month_map) day = st.slider("最后联系日", 1, 31, 15) poutcome_display = st.selectbox("上次活动结果", list(poutcome_map.values())) poutcome = get_key(poutcome_display, poutcome_map) # 隐藏的高级特征 with st.expander("高级营销特征 (可选)"): campaign = st.number_input("本次活动联系次数", 1, 50, 1) pdays = st.number_input("距离上次联系天数 (-1代表无)", -1, 999, -1) previous = st.number_input("活动前联系次数", 0, 100, 0) # 2. 触发 Agent if st.button("🚀 开始分析与决策", type="primary"): try: # 构造 Pydantic 对象 customer = CustomerFeatures( age=age, job=job, marital=marital, education=education, default=default, balance=balance, housing=housing, loan=loan, contact=contact, day=day, month=month, campaign=campaign, pdays=pdays, previous=previous, poutcome=poutcome ) # 初始化 Agent with st.spinner("Agent 正在加载模型并思考..."): agent = MarketingAgent() decision = agent.run(customer) # 3. 展示结果 st.divider() st.header("2. 智能分析报告") # 结果看板 res_col1, res_col2 = st.columns([1, 2]) with res_col1: st.metric("预测购买概率", f"{decision.risk_score:.1%}") if decision.risk_score > 0.6: st.success(f"分群:{decision.customer_segment}") elif decision.risk_score > 0.3: st.warning(f"分群:{decision.customer_segment}") else: st.error(f"分群:{decision.customer_segment}") with res_col2: st.subheader("💡 决策建议") st.info(decision.decision) st.markdown(f"**决策依据:** {decision.rationale}") # 行动清单 st.subheader("📝 执行清单") for i, action in enumerate(decision.actions, 1): st.write(f"{i}. {action}") # JSON 视图 with st.expander("查看原始 JSON 输出 (Traceable)"): st.json(decision.model_dump()) except Exception as e: st.error(f"发生错误: {str(e)}")