微信扫码
添加专属顾问
2024年上半年已过,我决定整理我的财务状况,减少开支,并制定更好的理财计划。
直接使用类似ChatGPT这样的工具,会泄漏我的个人财务数据,我并不想这么做。
所以,我创建了一个可以在电脑本地运行的AI财务分析助手。
完全在本地运行,无需网络连接,免费。
本地AI财务助手首先导入我的财务数据,然后分析我的财务状况,包括收入和支出,并且提供个性化的财务规划,以适应我的生活目标。
下面,我将演示如何从0到1搭建本地AI财务助手。
免责声明:本文仅用于学习,不作为个人财务、投资建议。所有观点仅代表作者个人。
该应用程序使用Streamlit构建用户界面,核心部分使用LangChain与Ollama中的本地开源大模型。
在这个应用程序中,我使用了一些最先进的开源大模型,如Mistral和LLAVA,以实现多模态功能。
通过提示词,我将大模型设置为一个“专业财务规划师”,可以为个人提供财务建议。
我设定这个项目的目标是:处理和分类财务数据数据;根据财务数据数据分析总收入、支出和节余,同时可视化收入、支出等变化趋势;利用多模态功能理解图表,发现财务变化规律;最后,根据我的生活方式,生成个性化的投资建议。
(注:本文需要一些编程基础,已经学习过AI线下工作坊二期的同学,可以使用我们提供的方法,操作更丝滑)
下面先介绍下需要使用的工具。
Ollama:目前最好、最简单地运行开源大模型的工具之一。
支持Llama 2、Mistral、LLAVA等在内的开源大模型,你可以在ollama.ai/library上找到所有可以下载使用的开源大模型。Ollama开源在MacOS、Windows和Linux系统上安装。
LangChain:LangChain是围绕大模型构建的开源框架。它极大简化了AI应用程序的设计和开发,并围绕大模型创建更高级的用例。
它与Ollama中的开源模型有很好的集成。
Streamlit:Streamlit是一个开源框架,开发者能够快速创建和共享数据,只需要使用少量Python代码,即可开发基于Web的用户界面。
Streamlit可用于快速进行原型设计和开发复杂的数据仪表盘项目。
访问Ollama下载页面,选择与你的操作系统匹配的版本,下载并安装。
终端、windows用户搜索cmd),输入以下命令。这些命令将把开源大模型下载到你的计算机上。在这个项目中,我们下载Mistral和LLAVA。
ollama serveollama pull mistralollama pull llavaollama run mistralollama run llava
我将使用合成数据代替我的个人财务数据数据。我用ChatGPT生成了1000笔财务数据数据,你可以直接使用自己真实财务数据。
以下是你可以用来生成测试数据的提示词。
生成一个年轻金融专业人士在欧洲生活的财务财务数据数据集,涵盖2022年1月至2023年12月的1000笔财务数据。确保收入和支出在各个类别中均衡分布。数据集应包括以下四列:日期:财务数据日期(格式:YYYY-MM-DD)名称/描述:每笔财务数据的独特详细描述(例如:"工资存款","每月房租支付","与朋友的餐馆晚餐")支出/收入:明确标明财务数据是支出(例如:"支出")还是收入(例如:"收入")金额(欧元):财务数据金额(单位:欧元)
生成的数据集应包括以下四列:
• 日期:财务数据日期
• 名称/描述:财务数据的简短描述,用于大模型根据财务数据性质进行分类。
• 支出/收入:标明是收入还是支出
• 金额(欧元):财务数据金额(单位:欧元)。
生成的财务数据
现在,我们需要安装Langchain和Streamlit的相关依赖项。
pip install langchain-communitypip install streamlit
创建一个新的Python文件“Upload.py”并添加以下代码。
步骤如下:
• 导入必要的库
• 初始化用于分类财务数据的大模型
• 定义类别:涵盖各种收入和支出类型,帮助大模型准确分类财务数据。
import streamlit as stimport pandas as pdfrom langchain_community.llms import Ollamallm = Ollama(model="mistral")categories = ["Salary/Wages", "Investment Income", "Freelance Income", "Business Revenue","Rental Income","Housing", "Utilities","Groceries","Transportation","Insurance","Healthcare","Entertainment","Personal Care","Education","Savings/Investments","Loans/Debt","Taxes","Childcare","Gifts/Donations","Dining Out","Travel","Shopping","Subscriptions","Pet Care", "Home Improvement","Clothing","Tech/Gadgets", "Fitness/Sports",]categories_string = ",".join(categories)
1. 分类财务数据
编写一个categorize_transactions函数,该函数接收财务数据名称。我们将使用提示工程技术引导大模型的输出。在提示中包含财务数据名称,并要求大模型根据预定义的类别进行分类。
收到大模型的输出后,我们将这些数据组织并转换为结构化的pandas DataFrame。
def categorize_transactions(transaction_names, llm):
prompt = f"""把以下费用分到适当的类别中。
请记住,类别应从以下列表中选择一个,根据它们的主要目的或性质选择最相关的类别:{categories_string}。\n
输出格式应始终为:transaction name - category。例如:Spotify #2 - Entertainment, Basic Fit Amsterdam Nld #3 - Fitness/Sports \n
以下是待分类的交易:{transaction_names} \n"""
print(prompt)
filtered_response = []
# retry is the LLM output is not consistent
while len(filtered_response) < 2:
response = llm.invoke(prompt).split("\n")
print(response)
# Remove items that do not contain "transaction: category" pairs
filtered_response = [item for item in response if '-' in item]
print(filtered_response)
# Put in dataframe
categories_df = pd.DataFrame({"Transaction vs category": filtered_response})
size_dif = len(categories_df) - len(transaction_names.split(","))
if size_dif >= 0:
categories_df["Transaction"] = transaction_names.split(",") + [None] * size_dif
else:
categories_df["Transaction"] = transaction_names.split(",")[:len(categories_df)]
categories_df["Category"] = categories_df["Transaction vs category"].str.split("-", expand=True)[1]
return categories_df
2. 创建数据处理函数
创建一个process_data函数,处理上传的数据文件,使用categorize_transactions对财务数据进行分类,并将分类后的数据合并到用于进一步分析的全局DataFrame中。
def hop(start, stop, step):
for i in range(start, stop, step):
yield i
yield stop
def process_data(df: pd.DataFrame):
unique_transactions = df["Name/Description"].unique()
index_list = list(hop(0, len(unique_transactions), 30))
# Intialise the categories_df_all dataframe
categories_df_all = pd.DataFrame()
# Loop through the index_list
for i in range(0, len(index_list) - 1):
print(f"Looping: {i}")
transaction_names = unique_transactions[index_list[i] : index_list[i + 1]]
transaction_names = ",".join(transaction_names)
categories_df = categorize_transactions(transaction_names, llm)
categories_df_all = pd.concat(
[categories_df_all, categories_df], ignore_index=True
)
# futher clean data:
# Drop NA values
categories_df_all = categories_df_all.dropna()
# Remove the numbering eg "1. " from Transaction column
categories_df_all["Transaction"] = categories_df_all["Transaction"].str.replace(
r"\d+\.\s?", "", regex=True
).str.strip()
new_df = pd.merge(
df,
categories_df_all,
left_on="Name/Description",
right_on="Transaction",
how="left",
)
new_df.to_csv(f"data/{uploaded_file.name}_categorized.csv", index=False)
return new_df
3. 创建Streamlit Web应用程序
首先设置Web应用程序的标题,并添加一个文件上传小部件。这样用户就可以上传他们的财务数据。
st.title("? Load your financial data here")uploaded_file = st.file_uploader("Upload your financial data", type=("txt", "csv", "pdf"))4. 处理上传的数据
文件上传后,读取到pandas DataFrame中,并调用process_data函数进行财务数据分类。
if uploaded_file:with st.spinner("Processing data..."):file_details = {"FileName": uploaded_file.name, "FileType": uploaded_file.type}df = pd.read_csv(uploaded_file)df = process_data(df)st.markdown("Data processed : OK")5. 运行Streamlit应用程序
你将看到一个类似这样的界面。
所有财务数据都已通过大模型Mistral分类后,你可以进行财务分析了。
包括下三个步骤:
1、定量分析:为了全面了解你的财务状况,你需要首先计算收入和支出,确定资金的主要流向。
2、可视化展示:绘制财务数据数据图表,发现趋势。
3、定性分析:将收集到的主要财务指标等信息(包括图表)反馈给Mistral。通过精心设计的提示词,让大模型对你的财务状况进行定性分析。
首先,创建一个新的Python文件“Finance_Dashboard.py”,导入必要的Python库并初始化Ollama。
import osimport streamlit as stimport pandas as pdimport matplotlib.pyplot as pltfrom langchain_community.llms import Ollamallm_llava = Ollama(model="llava")llm = Ollama(model="mistral")
然后,创建一个名为financial_analysis的函数来分析财务数据。
def financial_analysis(data:pd.DataFrame):
key_figures = {}
# Calculate yearly total income and total expenses
yearly_income = data.loc[data['Expense/Income'] == 'Income'].groupby('Year')['Amount(EUR)'].sum().mean()
yearly_expenses = data.loc[data['Expense/Income'] == 'Expense'].groupby('Year')['Amount(EUR)'].sum().mean()
# Identify the top expense categories
top_expenses = data.loc[data['Expense/Income'] == 'Expense'].groupby('Category')['Amount(EUR)'].sum().sort_values(
ascending=False)
# Calculate average monthly income and expenses
monthly_income = data.loc[data['Expense/Income'] == 'Income'].groupby(data['Date'].dt.to_period('M'))[
'Amount(EUR)'].sum().mean()
monthly_expenses = data.loc[data['Expense/Income'] == 'Expense'].groupby(data['Date'].dt.to_period('M'))[
'Amount(EUR)'].sum().mean()
# Determine the savings rate
savings = yearly_income - yearly_expenses
savings_rate = (savings / yearly_income) * 100 if yearly_income > 0 else 0
key_figures['Average Annual Income'] = f"€{yearly_income:,.2f}"
key_figures['Average Annual Expenses'] = f"€{yearly_expenses:,.2f}"
key_figures['Annual Savings Rate'] = f" {savings_rate:.2f}%"
key_figures['Top Expense Categories'] = {category: f"€{amount:,.2f}" for category, amount in
top_expenses.head().items()}
key_figures['Average Monthly Income'] = f"€{monthly_income:,.2f}"
key_figures['Average Monthly Expenses'] = f"€{monthly_expenses:,.2f}"
return key_figures
这个函数计算年度和月度的收入与支出、储蓄率,并识别主要的支出类别。
在这里,我们将可视化财务数据,包括收入与支出随时间变化图、每月存款、收入来源图、支出类别。
def plot_income_vs_expense_over_time(df):
# Income vs Expense Over time
st.markdown("1. Income vs Expense Over time")
income_expense_summary = (
df.groupby(["YearMonth", "Expense/Income"])["Amount(EUR)"]
.sum()
.unstack()
.fillna(0)
)
income_expense_summary.plot(kind="bar", figsize=(10, 8))
plt.title("Income vs Expenses Over Time")
plt.ylabel("Amount (EUR)")
plt.xlabel("Month")
plt.savefig("data/income_vs_expense_over_time.png", bbox_inches="tight")
st.pyplot(plt)
def plot_saving_rate_trend(data: pd.DataFrame):
st.markdown("2. Monthly Saving Rate Trend")
monthly_data = data.groupby(['YearMonth', 'Expense/Income'])['Amount(EUR)'].sum().unstack().fillna(0)
monthly_data['Savings Rate'] = (monthly_data['Income'] - monthly_data['Expense']) / monthly_data['Income'] * 100
fig, ax = plt.subplots()
monthly_data['Savings Rate'].plot(ax=ax)
ax.set_xlabel('Month')
ax.set_ylabel('Savings Rate (%)')
plt.savefig("data/saving_rate_over_time.png", bbox_inches="tight")
st.pyplot(fig)
def plot_income_source_analysis(data: pd.DataFrame):
st.markdown("3. Income Sources Analysis")
income_sources = data[data['Expense/Income'] == 'Income'].groupby('Category')['Amount(EUR)'].sum()
income_sources.plot(kind="pie", figsize=(10, 8), autopct="%1.1f%%", startangle=140)
plt.title("Income Sources Analysis")
plt.ylabel("") # Hide the y-label as it's unnecessary for pie charts
plt.savefig("data/income_source_analysis.png", bbox_inches="tight")
st.pyplot(plt)
def plot_category_wise_spending_analysis(data: pd.DataFrame):
st.markdown("4. Category-wise Spending Analysis")
expenses_by_category = data[data['Expense/Income'] == 'Expense'].groupby('Category')['Amount(EUR)'].sum()
expenses_by_category.plot(kind="pie", figsize=(10, 8), autopct="%1.1f%%", startangle=140)
plt.title("Expenses Analysis")
plt.ylabel("") # Hide the y-label as it's unnecessary for pie charts
plt.savefig("data/expense_category_analysis.png", bbox_inches="tight")
st.pyplot(plt)
加载财务数据
total_df = pd.DataFrame()for root, dirs, files in os.walk("data"):for file in files:if file.endswith(".csv"):df = pd.read_csv(os.path.join(root, file))total_df = pd.concat([total_df, df], ignore_index=True)total_df["Date"] = pd.to_datetime(total_df["Date"])total_df["YearMonth"] = total_df["Date"].dt.to_period("M")total_df["Year"] = total_df["Date"].dt.year
从CSV文件读取财务数据,处理数据并准备进行分析。
设置Streamlit仪表盘
st.title("My Local AI Finance Insighter")
st.markdown(
"**A personalized and secure approach to analyzing financial data, providing insights and recommendations tailored to individual needs.**"
)
analysis_results = financial_analysis(total_df)
results_str = ""
# Loop through the dictionary
for key, value in analysis_results.items():
if isinstance(value, dict):
# If the value is another dictionary, further iterate to get sub-keys and values
sub_results = ', '.join([f"{sub_key}: {sub_value}" for sub_key, sub_value in value.items()])
results_str += f"{key}: {sub_results}\n"
else:
# For direct key-value pairs, simply concatenate
results_str += f"{key}: {value}\n"
st.subheader("Yearly Figures")
col1, col2, col3 = st.columns(3)
col1.metric(label="Average Annual Income", value=analysis_results['Average Annual Income'])
col2.metric(label="Average Annual Expenses", value=analysis_results['Average Annual Expenses'])
col3.metric(label="Savings Rate", value=analysis_results['Annual Savings Rate'])
# Display average monthly figures
st.subheader("Average Monthly Figures")
col1, col2 = st.columns(2)
col1.metric(label="Average Monthly Income", value=analysis_results['Average Monthly Income'])
col2.metric(label="Average Monthly Expenses", value=analysis_results['Average Monthly Expenses'])
# Display top expense categories in a table
st.subheader("Top Expense Categories")
expenses_df = pd.DataFrame(list(analysis_results['Top Expense Categories'].items()), columns=['Category', 'Amount'])
st.table(expenses_df)
with st.container():
col1, col2 = st.columns(2)
with col1:
plot_income_vs_expense_over_time(total_df)
with col2:
plot_saving_rate_trend(total_df)
with st.container():
col3, col4 = st.columns(2)
with col3:
plot_income_source_analysis(total_df)
with col4:
plot_category_wise_spending_analysis(total_df)
使用Streamlit为仪表盘创建标题,显示分析结果,并整合绘图函数。
运行Streamlit时,你应该会看到一个类似这样的仪表盘:
最后,我们将之前生成的定量和定性分析结果提供给Mistral,生成个性化财务建议!
with st.container():
col3, col4 = st.columns(2)
with col3:
plot_income_source_analysis(total_df)
with col4:
plot_category_wise_spending_analysis(total_df)
with st.spinner("Generating reports ..."):
total_response = ""
for root, dirs, files in os.walk("data"):
for file in files:
if file.endswith(".png"):
response = llm_llava.invoke(
f"Act as an expert finance planner and analyse the image : {os.path.join(root, file)}. You should give your insights extracted from the image and key figures you see from the image "
)
total_response += response
total_response += f"\nHere are the user key financial figures : {results_str}"
st.write("---------------")
st.markdown("**Finance analysis and budget planner**")
summary = llm.invoke(
f"You are a helpful and expert finance planner. Base on the following analysis: {total_response}, make a summary of the financial status of the user and suggest tips on savings. Highlight categories where the user can potentially reduce expenses and suggest an ideal savings rate based on their income and goals. Tailor these suggestions to fit the user’s lifestyle and financial objectives. Use a friendly tone. "
)
st.write(summary)
st.write("---------------")
st.markdown("**Investment tips**")
if "user_answers_str" in st.session_state:
user_investment_answer = st.session_state.user_answers_str
else:
user_investment_answer = ""
investment_tips = llm.invoke(
f"You are a helpful and expert finance planner. Based on the user's risk tolerance and investment goals, provide an overview of suitable investment options. Discuss the basics of stocks, bonds, mutual funds, ETFs, and other investment vehicles that align with their profile. Explain the importance of diversification and the role of risk management in investing. Offer to guide them through setting up a diversified investment portfolio, suggesting steps to get started based on their current financial situation. Use a friendly tone. Below are the user´s investment objective and risk tolerance : {user_investment_answer}"
)
st.write(investment_tips)
报告结构良好且连贯,但长度超过了我的预期。为了获得更简洁的输出,我们可以进一步优化提示。
这就是我们一起构建的本地AI驱动的财务洞察工具,用于更好地了解我们的财务状况。
我们利用生成式AI的力量,为你量身定制了高度个性化的建议。
本项目等亮点:你的财务数据始终安全地保存在你的电脑上。
希望你喜欢这个项目!
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2026-07-01
实测腾讯开源的 BrowserSkill:让 AI 直接用你登录好的浏览器
2026-07-01
阶跃开源JetSpec,大模型推测解码提速近10倍
2026-06-30
花叔的这个神器直接让你的AI Agent出高保真原型、PPT和动画,20k stars不是盖的
2026-06-30
阿里达摩院开源语音识别:比Whisper快170倍还免费,CPU就能跑
2026-06-30
MiniMax M3 实测:第一流的模型,已经对执行层动手了
2026-06-30
DSpark:DeepSeek 如何让大模型推理提速 85%
2026-06-30
告别云端付费!3秒克隆你的声音,这款开源AI不用GPU,手机CPU就能实时跑
2026-06-30
阿里开源 ReMe:像写双链笔记一样给 AI Agent 做长期记忆
2026-04-09
2026-04-03
2026-04-18
2026-04-18
2026-06-22
2026-04-02
2026-05-10
2026-05-06
2026-05-20
2026-05-31
2026-06-16
2026-05-30
2026-05-16
2026-04-22
2026-04-21
2026-04-15
2026-04-09
2026-04-01
欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。
在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。
一、 定义
本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。
会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。
知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。
二、 账号注册与登录
登录方式:本网站支持以下登录方式,您可根据实际情况选择:
微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。
手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。
账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。
实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。
未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。
三、 服务内容与规范
知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。
服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。
禁止行为:您在使用服务时不得实施以下行为:
利用技术手段批量爬取、下载、转存知识库内容;
将知识库内容用于商业目的或未经授权地向第三方传播;
干扰本网站正常运行或侵犯其他用户合法权益;
发布违法违规信息或从事违反公序良俗的活动。
四、 知识产权声明
权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。
有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。
侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。
五、 个人信息保护
我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。
您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。
您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。
六、 免责声明
内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。
不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。
第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。
七、 违约责任
如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。
如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。
八、 法律适用与争议解决
本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。
因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。
九、 其他
本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。
本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。
我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。