Rahul2298 commited on
Commit
cf59f7f
Β·
verified Β·
1 Parent(s): 7c2007f

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +244 -86
src/streamlit_app.py CHANGED
@@ -1,90 +1,248 @@
1
- import os
2
  import streamlit as st
 
 
 
 
3
  import pandas as pd
4
-
5
- # βœ… OpenAI client
6
- from openai import OpenAI
7
-
8
- # -------------------------------------------------------------------
9
- # Load API Key securely
10
- # -------------------------------------------------------------------
11
- api_key = os.getenv("OPENAI_API_KEY")
12
-
13
- def mask_key(key: str) -> str:
14
- """Return a masked version of the API key (safe for logs)."""
15
- if not key:
16
- return "❌ No Key Found"
17
- return key[:6] + "..." + key[-4:]
18
-
19
- if not api_key:
20
- st.error("❌ OPENAI_API_KEY is not set. Please add it in Hugging Face β†’ Settings β†’ Variables and secrets.")
21
- st.stop()
22
- else:
23
- st.sidebar.success(f"πŸ”‘ API key loaded: {mask_key(api_key)}")
24
-
25
- # Initialize OpenAI client
26
- client = OpenAI(api_key=api_key)
27
-
28
- # -------------------------------------------------------------------
29
- # Streamlit App UI
30
- # -------------------------------------------------------------------
31
- st.set_page_config(page_title="πŸ’° Personal Finance Chatbot", page_icon="πŸ’¬", layout="wide")
32
-
33
- st.title("πŸ’¬ Personal Finance Chatbot")
34
- st.write("Get intelligent guidance for **savings, taxes, and investments** using OpenAI.")
35
-
36
- # Store chat history
37
- if "messages" not in st.session_state:
38
- st.session_state["messages"] = []
39
-
40
- # -------------------------------------------------------------------
41
- # Finance transaction tracker
42
- # -------------------------------------------------------------------
43
- if "transactions" not in st.session_state:
44
- st.session_state["transactions"] = []
45
-
46
- st.sidebar.header("πŸ“Š Add Transaction")
47
- amount = st.sidebar.number_input("Amount", min_value=0.0, format="%.2f")
48
- category = st.sidebar.selectbox("Category", ["Savings", "Investment", "Tax", "Expense"])
49
- if st.sidebar.button("Add Transaction"):
50
- st.session_state["transactions"].append({"Amount": amount, "Category": category})
51
- st.sidebar.success("βœ… Transaction added!")
52
-
53
- if st.session_state["transactions"]:
54
- df = pd.DataFrame(st.session_state["transactions"])
55
- st.sidebar.subheader("πŸ’΅ Transactions")
56
- st.sidebar.dataframe(df)
57
-
58
- # -------------------------------------------------------------------
59
- # Chatbot interaction
60
- # -------------------------------------------------------------------
61
- st.subheader("πŸ’‘ Ask me anything about your finances")
62
-
63
- user_input = st.text_input("Type your question here:")
64
- if st.button("Send") and user_input:
65
- # Store user message
66
- st.session_state["messages"].append({"role": "user", "content": user_input})
67
-
68
- # Call OpenAI API
69
- try:
70
- response = client.chat.completions.create(
71
- model="gpt-4o-mini",
72
- messages=st.session_state["messages"],
73
- max_tokens=500,
74
- temperature=0.7,
 
 
 
 
 
 
 
 
 
 
 
75
  )
76
 
77
- bot_reply = response.choices[0].message.content
78
- st.session_state["messages"].append({"role": "assistant", "content": bot_reply})
79
-
80
- except Exception as e:
81
- st.error(f"⚠️ Error: {str(e)}")
82
-
83
- # -------------------------------------------------------------------
84
- # Display conversation
85
- # -------------------------------------------------------------------
86
- for msg in st.session_state["messages"]:
87
- if msg["role"] == "user":
88
- st.markdown(f"**πŸ§‘ You:** {msg['content']}")
89
- else:
90
- st.markdown(f"**πŸ€– Bot:** {msg['content']}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # personal_finance_chatbot.py
2
  import streamlit as st
3
+ from transformers import AutoModelForSeq2SeqLM, AutoTokenizer, pipeline
4
+ import json
5
+ from datetime import datetime
6
+ import random
7
  import pandas as pd
8
+ import numpy as np
9
+
10
+ # Configuration
11
+ MODEL_NAME = "ibm/granite-7b-base" # Using IBM Granite model via HuggingFace
12
+ USER_TYPES = ["student", "professional"]
13
+ FINANCE_CATEGORIES = ["savings", "taxes", "investments", "budget", "spending"]
14
+
15
+ # Initialize NLP pipeline
16
+ @st.cache_resource
17
+ def load_model():
18
+ """Load and cache the language model"""
19
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
20
+ model = AutoModelForSeq2SeqLM.from_pretrained(MODEL_NAME)
21
+ return pipeline("text2text-generation", model=model, tokenizer=tokenizer)
22
+
23
+ # User profile management
24
+ class UserProfile:
25
+ def __init__(self, user_type, financial_goals=None, income=0, expenses=None):
26
+ self.user_type = user_type
27
+ self.financial_goals = financial_goals or []
28
+ self.income = income
29
+ self.expenses = expenses or {}
30
+ self.transaction_history = []
31
+
32
+ def add_transaction(self, amount, category, description=""):
33
+ """Record a financial transaction"""
34
+ self.transaction_history.append({
35
+ "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
36
+ "amount": amount,
37
+ "category": category,
38
+ "description": description
39
+ })
40
+
41
+ def get_budget_summary(self):
42
+ """Generate a budget summary"""
43
+ total_expenses = sum(t["amount"] for t in self.transaction_history
44
+ if t["amount"] < 0)
45
+ total_income = sum(t["amount"] for t in self.transaction_history
46
+ if t["amount"] > 0)
47
+
48
+ return {
49
+ "total_income": total_income,
50
+ "total_expenses": abs(total_expenses),
51
+ "net_savings": total_income + total_expenses,
52
+ "category_breakdown": self._get_category_breakdown()
53
+ }
54
+
55
+ def _get_category_breakdown(self):
56
+ """Get expense breakdown by category"""
57
+ breakdown = {}
58
+ for t in self.transaction_history:
59
+ if t["amount"] < 0:
60
+ cat = t["category"]
61
+ breakdown[cat] = breakdown.get(cat, 0) + abs(t["amount"])
62
+ return breakdown
63
+
64
+ # Chatbot core functionality
65
+ class FinanceChatbot:
66
+ def __init__(self):
67
+ self.nlp = load_model()
68
+ self.user_profiles = {}
69
+ self.current_user = None
70
+
71
+ def set_user(self, user_id, user_type):
72
+ """Initialize or switch user profile"""
73
+ if user_id not in self.user_profiles:
74
+ self.user_profiles[user_id] = UserProfile(user_type=user_type)
75
+ self.current_user = user_id
76
+
77
+ def generate_response(self, query):
78
+ """Generate context-aware response to user query"""
79
+ if not self.current_user:
80
+ return "Please identify yourself first. Are you a student or professional?"
81
+
82
+ profile = self.user_profiles[self.current_user]
83
+ context = self._build_context(profile)
84
+
85
+ # Adjust tone based on user type
86
+ tone_instruction = (
87
+ "Use simple, encouraging language suitable for a student."
88
+ if profile.user_type == "student" else
89
+ "Use professional, concise language suitable for a financial professional."
90
  )
91
 
92
+ prompt = f"""
93
+ You are a helpful financial assistant. {tone_instruction}
94
+ User profile context: {context}
95
+ Current query: {query}
96
+
97
+ Provide a helpful response that:
98
+ 1. Directly answers the financial question
99
+ 2. Offers 1-2 specific actionable suggestions when appropriate
100
+ 3. Maintains a {profile.user_type}-appropriate tone
101
+ 4. Is concise (3 sentences or less unless more detail is requested)
102
+ """
103
+
104
+ try:
105
+ result = self.nlp(prompt, max_length=200, num_return_sequences=1)
106
+ response = result[0]['generated_text'].strip()
107
+
108
+ # Post-process to extract clean response
109
+ if "Response:" in response:
110
+ response = response.split("Response:")[-1].strip()
111
+ return response
112
+ except Exception as e:
113
+ return f"Sorry, I encountered an error processing your request. {str(e)}"
114
+
115
+ def _build_context(self, profile):
116
+ """Build context string from user profile"""
117
+ budget = profile.get_budget_summary()
118
+ return json.dumps({
119
+ "user_type": profile.user_type,
120
+ "income": profile.income,
121
+ "net_savings": budget["net_savings"],
122
+ "top_expenses": sorted(budget["category_breakdown"].items(),
123
+ key=lambda x: x[1], reverse=True)[:3],
124
+ "recent_transactions": profile.transaction_history[-3:] if profile.transaction_history else []
125
+ })
126
+
127
+ def analyze_spending(self):
128
+ """Generate spending insights"""
129
+ if not self.current_user:
130
+ return "No user profile selected"
131
+
132
+ profile = self.user_profiles[self.current_user]
133
+ budget = profile.get_budget_summary()
134
+
135
+ if not budget["category_breakdown"]:
136
+ return "No spending data available for analysis"
137
+
138
+ prompt = f"""
139
+ Analyze this spending data and provide insights:
140
+ {json.dumps(budget['category_breakdown'])}
141
+
142
+ User type: {profile.user_type}
143
+ Income: {profile.income}
144
+
145
+ Provide:
146
+ 1. 1 key insight about spending patterns
147
+ 2. 1 specific suggestion for optimization
148
+ 3. Formatted for {profile.user_type} audience
149
+ """
150
+
151
+ try:
152
+ result = self.nlp(prompt, max_length=150)
153
+ return result[0]['generated_text'].strip()
154
+ except Exception as e:
155
+ return f"Error generating insights: {str(e)}"
156
+
157
+ # Streamlit UI
158
+ def main():
159
+ st.set_page_config(page_title="Personal Finance Chatbot", layout="wide")
160
+
161
+ # Initialize chatbot
162
+ if 'chatbot' not in st.session_state:
163
+ st.session_state.chatbot = FinanceChatbot()
164
+ if 'user_id' not in st.session_state:
165
+ st.session_state.user_id = None
166
+ if 'messages' not in st.session_state:
167
+ st.session_state.messages = []
168
+
169
+ # Sidebar for user setup
170
+ with st.sidebar:
171
+ st.title("User Profile")
172
+ user_id = st.text_input("Your ID (any name)", value=st.session_state.get('user_id', ''))
173
+ user_type = st.selectbox("I am a:", USER_TYPES)
174
+
175
+ if st.button("Save Profile"):
176
+ st.session_state.user_id = user_id
177
+ st.session_state.chatbot.set_user(user_id, user_type)
178
+ st.success(f"Profile saved as {user_type}")
179
+
180
+ st.divider()
181
+ st.subheader("Quick Actions")
182
+
183
+ if st.session_state.user_id:
184
+ col1, col2 = st.columns(2)
185
+ with col1:
186
+ if st.button("Budget Summary"):
187
+ profile = st.session_state.chatbot.user_profiles[st.session_state.user_id]
188
+ summary = profile.get_budget_summary()
189
+ st.session_state.messages.append(
190
+ {"role": "assistant", "content": f"### Your Budget Summary\n\n"
191
+ f"- **Income**: ${summary['total_income']:.2f}\n"
192
+ f"- **Expenses**: ${summary['total_expenses']:.2f}\n"
193
+ f"- **Net Savings**: ${summary['net_savings']:.2f}\n\n"
194
+ f"Top Expenses: {', '.join([f'{k}(${v:.2f})' for k,v in summary['category_breakdown'].items()])}"
195
+ )
196
+ with col2:
197
+ if st.button("Spending Insights"):
198
+ insights = st.session_state.chatbot.analyze_spending()
199
+ st.session_state.messages.append(
200
+ {"role": "assistant", "content": f"### Spending Insights\n\n{insights}"}
201
+ )
202
+
203
+ # Main chat interface
204
+ st.title("πŸ’° Personal Finance Chatbot")
205
+ st.write("Ask me about savings, taxes, investments, or budgeting!")
206
+
207
+ # Display chat messages
208
+ for message in st.session_state.messages:
209
+ with st.chat_message(message["role"]):
210
+ st.markdown(message["content"])
211
+
212
+ # Chat input
213
+ if prompt := st.chat_input("What would you like to know about your finances?"):
214
+ if not st.session_state.user_id:
215
+ st.error("Please set up your profile first!")
216
+ else:
217
+ # Add user message to chat history
218
+ st.session_state.messages.append({"role": "user", "content": prompt})
219
+ with st.chat_message("user"):
220
+ st.markdown(prompt)
221
+
222
+ # Generate and display assistant response
223
+ with st.spinner("Thinking..."):
224
+ response = st.session_state.chatbot.generate_response(prompt)
225
+ with st.chat_message("assistant"):
226
+ st.markdown(response)
227
+ st.session_state.messages.append({"role": "assistant", "content": response})
228
+
229
+ # Sample transactions for demo
230
+ if st.session_state.user_id and st.checkbox("Load sample data (demo only)"):
231
+ profile = st.session_state.chatbot.user_profiles[st.session_state.user_id]
232
+ sample_data = [
233
+ (1200, "income", "Monthly salary"),
234
+ (-400, "housing", "Rent payment"),
235
+ (-200, "food", "Groceries"),
236
+ (-150, "transportation", "Public transport"),
237
+ (-100, "entertainment", "Movies"),
238
+ (50, "investments", "Stock purchase"),
239
+ (-80, "utilities", "Electricity bill")
240
+ ]
241
+
242
+ for amount, category, desc in sample_data:
243
+ profile.add_transaction(amount, category, desc)
244
+
245
+ st.success("Loaded sample transactions! Try asking about your budget or spending.")
246
+
247
+ if __name__ == "__main__":
248
+ main()