TurkishCodeMan commited on
Commit
c71c58f
·
verified ·
1 Parent(s): e4c209e

Upload folder using huggingface_hub

Browse files
__pycache__/graph.cpython-312.pyc ADDED
Binary file (9.96 kB). View file
 
__pycache__/hf_model.cpython-312.pyc ADDED
Binary file (2.67 kB). View file
 
app.py CHANGED
@@ -1,32 +1,26 @@
1
  """
2
  Fintech Multi-Agent Orchestrator - HuggingFace Spaces Demo
3
- Uses Gemma 3 27B via HuggingFace Inference API
4
  """
5
 
6
  import gradio as gr
7
- import json
8
- import re
9
  import matplotlib
10
  matplotlib.use('Agg')
11
  import matplotlib.pyplot as plt
12
  import numpy as np
13
  from io import BytesIO
14
  import base64
 
15
 
16
- from hf_model import generate_response, calculate_expression
17
 
18
 
19
- # Mock Banking Data
20
- MOCK_BANKING_DATA = {
21
- "net_worth": {"total": 87500.00, "assets": 142000.00, "liabilities": 54500.00},
22
- "assets": {"checking": 12500.00, "savings": 35000.00, "investments": 89500.00},
23
- "liabilities": {"credit_cards": 4500.00, "student_loans": 25000.00, "auto_loan": 15000.00},
24
- "portfolio": {"AAPL": 15200, "GOOGL": 12800, "MSFT": 18500, "AMZN": 9000, "bonds": 14000},
25
- }
26
-
27
-
28
- def create_chart(chart_type: str, data: dict, title: str) -> str:
29
- """Generate chart and return base64 image."""
30
  fig, ax = plt.subplots(figsize=(10, 6))
31
 
32
  if chart_type == "pie":
@@ -43,8 +37,9 @@ def create_chart(chart_type: str, data: dict, title: str) -> str:
43
  bars = ax.bar(labels, values, color=colors)
44
  ax.set_title(title, fontsize=14, fontweight='bold')
45
  ax.set_ylabel('Amount ($)')
 
46
  for bar, val in zip(bars, values):
47
- ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 500,
48
  f'${val:,.0f}', ha='center', va='bottom', fontsize=9)
49
 
50
  elif chart_type == "line":
@@ -56,148 +51,49 @@ def create_chart(chart_type: str, data: dict, title: str) -> str:
56
  ax.set_xticklabels(list(data.keys()))
57
  ax.set_title(title, fontsize=14, fontweight='bold')
58
  ax.set_ylabel('Amount ($)')
 
59
 
60
  plt.tight_layout()
61
 
62
- # Convert to base64
63
  buf = BytesIO()
64
  plt.savefig(buf, format='png', dpi=150, bbox_inches='tight')
65
  buf.seek(0)
66
  plt.close()
67
 
68
- return base64.b64encode(buf.read()).decode('utf-8')
69
-
70
-
71
- def route_query(query: str) -> dict:
72
- """Simple router to determine what actions are needed."""
73
- query_lower = query.lower()
74
-
75
- needs_banking = any(word in query_lower for word in
76
- ['balance', 'net worth', 'portfolio', 'assets', 'liabilities', 'account', 'hesap', 'bakiye'])
77
- needs_calculation = any(word in query_lower for word in
78
- ['calculate', 'compute', 'roi', 'interest', 'compound', 'hesapla', 'faiz'])
79
- needs_graph = any(word in query_lower for word in
80
- ['chart', 'graph', 'visualize', 'plot', 'pie', 'bar', 'grafik', 'görselleştir'])
81
-
82
- return {
83
- "needs_banking": needs_banking,
84
- "needs_calculation": needs_calculation,
85
- "needs_graph": needs_graph,
86
- }
87
 
88
 
89
- def process_query(query: str, history: list) -> tuple:
90
- """Main orchestrator function."""
 
 
91
 
92
- # Route the query
93
- route = route_query(query)
94
 
95
- response_parts = []
96
  chart_image = None
 
 
97
 
98
- # Get banking data if needed
99
- banking_context = ""
100
- if route["needs_banking"]:
101
- banking_context = f"""
102
- **📊 Account Data:**
103
- - Net Worth: ${MOCK_BANKING_DATA['net_worth']['total']:,.2f}
104
- - Total Assets: ${MOCK_BANKING_DATA['net_worth']['assets']:,.2f}
105
- - Total Liabilities: ${MOCK_BANKING_DATA['net_worth']['liabilities']:,.2f}
106
-
107
- **Portfolio:**
108
- """ + "\n".join([f"- {k}: ${v:,.2f}" for k, v in MOCK_BANKING_DATA['portfolio'].items()])
109
- response_parts.append(banking_context)
110
-
111
- # Perform calculation if needed
112
- if route["needs_calculation"]:
113
- # Extract numbers from query for calculation
114
- calc_prompt = f"""You are a financial calculator. Extract the calculation from this request and provide the result.
115
-
116
- Request: {query}
117
-
118
- If there's a compound interest calculation, use the formula: A = P(1 + r)^t
119
- Where P = principal, r = annual rate (as decimal), t = years
120
-
121
- Respond with ONLY the calculation result in this format:
122
- CALCULATION: [expression]
123
- RESULT: [number]
124
- EXPLANATION: [brief explanation]"""
125
-
126
- messages = [{"role": "user", "content": calc_prompt}]
127
- calc_response = generate_response(messages, max_tokens=500)
128
- response_parts.append(f"\n**🧮 Calculation:**\n{calc_response}")
129
-
130
- # Generate chart if needed
131
- if route["needs_graph"]:
132
- query_lower = query.lower()
133
-
134
- if 'portfolio' in query_lower or 'pie' in query_lower:
135
- chart_data = MOCK_BANKING_DATA['portfolio']
136
- chart_type = 'pie'
137
- title = 'Portfolio Distribution'
138
- elif 'assets' in query_lower:
139
- chart_data = MOCK_BANKING_DATA['assets']
140
- chart_type = 'bar'
141
- title = 'Assets Breakdown'
142
- elif 'liabilities' in query_lower:
143
- chart_data = MOCK_BANKING_DATA['liabilities']
144
- chart_type = 'bar'
145
- title = 'Liabilities Breakdown'
146
- else:
147
- # Default: net worth projection
148
- initial = MOCK_BANKING_DATA['net_worth']['total']
149
- rate = 0.08
150
- chart_data = {f"Year {i}": initial * (1 + rate) ** i for i in range(6)}
151
- chart_type = 'line'
152
- title = 'Net Worth Projection (8% Growth)'
153
-
154
- chart_base64 = create_chart(chart_type, chart_data, title)
155
- response_parts.append(f"\n**📈 Chart Generated:** {title}")
156
-
157
- # Return as PIL Image for Gradio
158
- import io
159
- from PIL import Image
160
- img_bytes = base64.b64decode(chart_base64)
161
- chart_image = Image.open(io.BytesIO(img_bytes))
162
-
163
- # If no specific action, use LLM for general response
164
- if not any(route.values()):
165
- context = f"""You are a fintech assistant. Answer the user's question about finance, banking, or investments.
166
- Keep your response concise and helpful.
167
-
168
- Available account data (if needed):
169
- - Net Worth: ${MOCK_BANKING_DATA['net_worth']['total']:,.2f}
170
- - Assets: ${MOCK_BANKING_DATA['net_worth']['assets']:,.2f}
171
- - Liabilities: ${MOCK_BANKING_DATA['net_worth']['liabilities']:,.2f}
172
-
173
- User question: {query}"""
174
-
175
- messages = [{"role": "user", "content": context}]
176
- llm_response = generate_response(messages, max_tokens=800)
177
- response_parts.append(llm_response)
178
 
179
- final_response = "\n".join(response_parts)
180
-
181
- return final_response, chart_image
182
 
183
 
184
  # Gradio Interface
185
  with gr.Blocks(
186
  title="Fintech Multi-Agent Orchestrator",
187
- theme=gr.themes.Soft(
188
- primary_hue="blue",
189
- secondary_hue="slate",
190
- ),
191
- css="""
192
- .gradio-container { max-width: 1200px !important; }
193
- .main-title { text-align: center; margin-bottom: 1rem; }
194
- """
195
  ) as demo:
196
 
197
  gr.Markdown("""
198
  # 🏦 Fintech Multi-Agent Orchestrator
199
 
200
- **Powered by Gemma 3 27B via HuggingFace Inference API**
201
 
202
  Ask questions about your finances, request calculations, or generate charts!
203
 
@@ -206,6 +102,7 @@ with gr.Blocks(
206
  - "Show my portfolio as a pie chart"
207
  - "Calculate compound interest on $10000 at 8% for 5 years"
208
  - "Show my assets breakdown"
 
209
  """)
210
 
211
  with gr.Row():
@@ -213,7 +110,6 @@ with gr.Blocks(
213
  chatbot = gr.Chatbot(
214
  label="Chat",
215
  height=400,
216
- type="messages",
217
  )
218
 
219
  with gr.Row():
@@ -233,15 +129,6 @@ with gr.Blocks(
233
  with gr.Row():
234
  clear_btn = gr.Button("Clear Chat")
235
 
236
- def respond(query, history):
237
- if not query.strip():
238
- return history, None
239
-
240
- response, chart = process_query(query, history)
241
- history.append({"role": "user", "content": query})
242
- history.append({"role": "assistant", "content": response})
243
- return history, chart
244
-
245
  submit_btn.click(
246
  respond,
247
  inputs=[query_input, chatbot],
 
1
  """
2
  Fintech Multi-Agent Orchestrator - HuggingFace Spaces Demo
3
+ Uses Gemma 3 via HuggingFace Inference API
4
  """
5
 
6
  import gradio as gr
 
 
7
  import matplotlib
8
  matplotlib.use('Agg')
9
  import matplotlib.pyplot as plt
10
  import numpy as np
11
  from io import BytesIO
12
  import base64
13
+ from PIL import Image
14
 
15
+ from graph import run_orchestrator
16
 
17
 
18
+ def create_chart(chart_data: dict) -> Image.Image:
19
+ """Generate chart from chart_data dict."""
20
+ chart_type = chart_data.get("type", "bar")
21
+ title = chart_data.get("title", "Chart")
22
+ data = chart_data.get("data", {})
23
+
 
 
 
 
 
24
  fig, ax = plt.subplots(figsize=(10, 6))
25
 
26
  if chart_type == "pie":
 
37
  bars = ax.bar(labels, values, color=colors)
38
  ax.set_title(title, fontsize=14, fontweight='bold')
39
  ax.set_ylabel('Amount ($)')
40
+ plt.xticks(rotation=45, ha='right')
41
  for bar, val in zip(bars, values):
42
+ ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + max(values)*0.02,
43
  f'${val:,.0f}', ha='center', va='bottom', fontsize=9)
44
 
45
  elif chart_type == "line":
 
51
  ax.set_xticklabels(list(data.keys()))
52
  ax.set_title(title, fontsize=14, fontweight='bold')
53
  ax.set_ylabel('Amount ($)')
54
+ ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'${x:,.0f}'))
55
 
56
  plt.tight_layout()
57
 
58
+ # Convert to PIL Image
59
  buf = BytesIO()
60
  plt.savefig(buf, format='png', dpi=150, bbox_inches='tight')
61
  buf.seek(0)
62
  plt.close()
63
 
64
+ return Image.open(buf)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
 
67
+ def respond(query: str, history: list):
68
+ """Main chat handler."""
69
+ if not query.strip():
70
+ return history, None
71
 
72
+ # Run orchestrator
73
+ response, chart_data = run_orchestrator(query)
74
 
75
+ # Create chart if needed
76
  chart_image = None
77
+ if chart_data:
78
+ chart_image = create_chart(chart_data)
79
 
80
+ # Update history (Gradio 6.x messages format)
81
+ history = history or []
82
+ history.append({"role": "user", "content": query})
83
+ history.append({"role": "assistant", "content": response})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
+ return history, chart_image
 
 
86
 
87
 
88
  # Gradio Interface
89
  with gr.Blocks(
90
  title="Fintech Multi-Agent Orchestrator",
 
 
 
 
 
 
 
 
91
  ) as demo:
92
 
93
  gr.Markdown("""
94
  # 🏦 Fintech Multi-Agent Orchestrator
95
 
96
+ **Powered by Gemma 3 via HuggingFace Inference API**
97
 
98
  Ask questions about your finances, request calculations, or generate charts!
99
 
 
102
  - "Show my portfolio as a pie chart"
103
  - "Calculate compound interest on $10000 at 8% for 5 years"
104
  - "Show my assets breakdown"
105
+ - "Show net worth projection"
106
  """)
107
 
108
  with gr.Row():
 
110
  chatbot = gr.Chatbot(
111
  label="Chat",
112
  height=400,
 
113
  )
114
 
115
  with gr.Row():
 
129
  with gr.Row():
130
  clear_btn = gr.Button("Clear Chat")
131
 
 
 
 
 
 
 
 
 
 
132
  submit_btn.click(
133
  respond,
134
  inputs=[query_input, chatbot],
graph.py ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Fintech Orchestrator Graph — HuggingFace Version
4
+
5
+ Adapted from orchestrator_v3.py for HuggingFace Spaces deployment.
6
+ Uses HF Inference API (Gemma 3) instead of local Qwen.
7
+ Uses mocked banking data instead of A2A remote agent.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import Optional
13
+ from pydantic import BaseModel, Field
14
+
15
+ from hf_model import generate_response
16
+
17
+
18
+ # ---------------------------------------------------------------------------
19
+ # Mock Banking Data (replaces A2A agent)
20
+ # ---------------------------------------------------------------------------
21
+
22
+ MOCK_BANKING_DATA = {
23
+ "net_worth": {
24
+ "total": 87500.00,
25
+ "assets": 142000.00,
26
+ "liabilities": 54500.00,
27
+ "currency": "USD",
28
+ },
29
+ "assets": {
30
+ "checking": 12500.00,
31
+ "savings": 35000.00,
32
+ "investments": 89500.00,
33
+ "other": 5000.00,
34
+ },
35
+ "liabilities": {
36
+ "credit_cards": 4500.00,
37
+ "student_loans": 25000.00,
38
+ "auto_loan": 15000.00,
39
+ "other": 10000.00,
40
+ },
41
+ "portfolio": {
42
+ "AAPL": 15200,
43
+ "GOOGL": 12800,
44
+ "MSFT": 18500,
45
+ "AMZN": 9000,
46
+ "bonds": 14000,
47
+ "ETFs": 18000,
48
+ },
49
+ "transactions": [
50
+ {"date": "2026-02-08", "description": "Salary Deposit", "amount": 5200.00},
51
+ {"date": "2026-02-07", "description": "Grocery Store", "amount": -127.43},
52
+ {"date": "2026-02-06", "description": "Electric Bill", "amount": -145.00},
53
+ {"date": "2026-02-05", "description": "Restaurant", "amount": -68.50},
54
+ {"date": "2026-02-04", "description": "Gas Station", "amount": -52.30},
55
+ ],
56
+ }
57
+
58
+
59
+ def get_banking_data(query: str) -> str:
60
+ """Mock banking query - returns relevant data based on query."""
61
+ query_lower = query.lower()
62
+
63
+ if "net worth" in query_lower or "toplam" in query_lower:
64
+ data = MOCK_BANKING_DATA["net_worth"]
65
+ return f"""Net Worth Summary:
66
+ - Total Net Worth: ${data['total']:,.2f}
67
+ - Total Assets: ${data['assets']:,.2f}
68
+ - Total Liabilities: ${data['liabilities']:,.2f}"""
69
+
70
+ elif "portfolio" in query_lower or "stocks" in query_lower:
71
+ portfolio = MOCK_BANKING_DATA["portfolio"]
72
+ lines = [f"- {k}: ${v:,.2f}" for k, v in portfolio.items()]
73
+ total = sum(portfolio.values())
74
+ return f"Portfolio (Total: ${total:,.2f}):\n" + "\n".join(lines)
75
+
76
+ elif "assets" in query_lower or "varlık" in query_lower:
77
+ assets = MOCK_BANKING_DATA["assets"]
78
+ lines = [f"- {k.title()}: ${v:,.2f}" for k, v in assets.items()]
79
+ total = sum(assets.values())
80
+ return f"Assets (Total: ${total:,.2f}):\n" + "\n".join(lines)
81
+
82
+ elif "liabilities" in query_lower or "borç" in query_lower:
83
+ liabilities = MOCK_BANKING_DATA["liabilities"]
84
+ lines = [f"- {k.replace('_', ' ').title()}: ${v:,.2f}" for k, v in liabilities.items()]
85
+ total = sum(liabilities.values())
86
+ return f"Liabilities (Total: ${total:,.2f}):\n" + "\n".join(lines)
87
+
88
+ elif "transaction" in query_lower or "işlem" in query_lower:
89
+ transactions = MOCK_BANKING_DATA["transactions"]
90
+ lines = [f"- {t['date']}: {t['description']} (${t['amount']:+,.2f})" for t in transactions]
91
+ return "Recent Transactions:\n" + "\n".join(lines)
92
+
93
+ else:
94
+ return f"""Account Summary:
95
+ - Net Worth: ${MOCK_BANKING_DATA['net_worth']['total']:,.2f}
96
+ - Checking: ${MOCK_BANKING_DATA['assets']['checking']:,.2f}
97
+ - Savings: ${MOCK_BANKING_DATA['assets']['savings']:,.2f}
98
+ - Investments: ${MOCK_BANKING_DATA['assets']['investments']:,.2f}"""
99
+
100
+
101
+ # ---------------------------------------------------------------------------
102
+ # Router Decision Schema
103
+ # ---------------------------------------------------------------------------
104
+
105
+ class RouterDecision(BaseModel):
106
+ """Router decision with multi-step planning"""
107
+ needs_banking: bool = Field(
108
+ default=False,
109
+ description="True if real account data is needed"
110
+ )
111
+ needs_calculation: bool = Field(
112
+ default=False,
113
+ description="True if financial calculation is needed"
114
+ )
115
+ needs_graph: bool = Field(
116
+ default=False,
117
+ description="True if visualization/chart is needed"
118
+ )
119
+ task_description: str = Field(
120
+ default="",
121
+ description="Description of what needs to be done"
122
+ )
123
+
124
+
125
+ def route_query(query: str) -> RouterDecision:
126
+ """Simple keyword-based router (fast, no LLM call)."""
127
+ query_lower = query.lower()
128
+
129
+ needs_banking = any(word in query_lower for word in [
130
+ 'balance', 'net worth', 'portfolio', 'assets', 'liabilities',
131
+ 'account', 'transaction', 'hesap', 'bakiye', 'varlık', 'borç'
132
+ ])
133
+
134
+ needs_calculation = any(word in query_lower for word in [
135
+ 'calculate', 'compute', 'roi', 'interest', 'compound', 'projection',
136
+ 'hesapla', 'faiz', 'getiri'
137
+ ])
138
+
139
+ needs_graph = any(word in query_lower for word in [
140
+ 'chart', 'graph', 'visualize', 'plot', 'pie', 'bar', 'line',
141
+ 'grafik', 'görselleştir', 'çiz'
142
+ ])
143
+
144
+ return RouterDecision(
145
+ needs_banking=needs_banking,
146
+ needs_calculation=needs_calculation,
147
+ needs_graph=needs_graph,
148
+ task_description=query
149
+ )
150
+
151
+
152
+ # ---------------------------------------------------------------------------
153
+ # Calculator
154
+ # ---------------------------------------------------------------------------
155
+
156
+ def calculate(expression: str, banking_data: str = "") -> str:
157
+ """Perform financial calculation using LLM."""
158
+ prompt = f"""You are a financial calculator. Perform the calculation requested.
159
+
160
+ Request: {expression}
161
+
162
+ {"Available account data:\n" + banking_data if banking_data else ""}
163
+
164
+ Provide:
165
+ 1. The calculation formula used
166
+ 2. Step-by-step calculation
167
+ 3. Final result
168
+
169
+ For compound interest: A = P(1 + r)^t
170
+ For ROI: ((Final - Initial) / Initial) * 100
171
+ """
172
+
173
+ messages = [{"role": "user", "content": prompt}]
174
+ return generate_response(messages, max_tokens=600)
175
+
176
+
177
+ # ---------------------------------------------------------------------------
178
+ # Orchestrator State
179
+ # ---------------------------------------------------------------------------
180
+
181
+ class OrchestratorState:
182
+ """State container for orchestrator."""
183
+ def __init__(self):
184
+ self.banking_data: Optional[str] = None
185
+ self.calculation_result: Optional[str] = None
186
+ self.graph_data: Optional[dict] = None
187
+ self.output: str = ""
188
+
189
+
190
+ # ---------------------------------------------------------------------------
191
+ # Main Orchestrator Function
192
+ # ---------------------------------------------------------------------------
193
+
194
+ def run_orchestrator(query: str) -> tuple[str, Optional[dict]]:
195
+ """
196
+ Main entry point for the orchestrator.
197
+
198
+ Args:
199
+ query: User's query string
200
+
201
+ Returns:
202
+ Tuple of (response_text, chart_data_dict_or_none)
203
+ """
204
+ # Route the query
205
+ decision = route_query(query)
206
+ state = OrchestratorState()
207
+ response_parts = []
208
+ chart_data = None
209
+
210
+ # Step 1: Get banking data if needed
211
+ if decision.needs_banking:
212
+ state.banking_data = get_banking_data(query)
213
+ response_parts.append(f"📊 **Account Data:**\n{state.banking_data}")
214
+
215
+ # Step 2: Perform calculation if needed
216
+ if decision.needs_calculation:
217
+ state.calculation_result = calculate(query, state.banking_data or "")
218
+ response_parts.append(f"\n🧮 **Calculation:**\n{state.calculation_result}")
219
+
220
+ # Step 3: Prepare chart data if needed
221
+ if decision.needs_graph:
222
+ query_lower = query.lower()
223
+
224
+ if 'portfolio' in query_lower or 'pie' in query_lower:
225
+ chart_data = {
226
+ "type": "pie",
227
+ "title": "Portfolio Distribution",
228
+ "data": MOCK_BANKING_DATA["portfolio"]
229
+ }
230
+ elif 'assets' in query_lower:
231
+ chart_data = {
232
+ "type": "bar",
233
+ "title": "Assets Breakdown",
234
+ "data": MOCK_BANKING_DATA["assets"]
235
+ }
236
+ elif 'liabilities' in query_lower:
237
+ chart_data = {
238
+ "type": "bar",
239
+ "title": "Liabilities Breakdown",
240
+ "data": MOCK_BANKING_DATA["liabilities"]
241
+ }
242
+ else:
243
+ # Default: net worth projection
244
+ initial = MOCK_BANKING_DATA["net_worth"]["total"]
245
+ rate = 0.08
246
+ chart_data = {
247
+ "type": "line",
248
+ "title": "Net Worth Projection (8% Annual Growth)",
249
+ "data": {f"Year {i}": initial * (1 + rate) ** i for i in range(6)}
250
+ }
251
+
252
+ response_parts.append(f"\n📈 **Chart:** {chart_data['title']}")
253
+
254
+ # Step 4: If no specific action, use LLM for general response
255
+ if not any([decision.needs_banking, decision.needs_calculation, decision.needs_graph]):
256
+ context = f"""You are a fintech assistant. Answer the user's question about finance.
257
+
258
+ Available account data:
259
+ - Net Worth: ${MOCK_BANKING_DATA['net_worth']['total']:,.2f}
260
+ - Assets: ${MOCK_BANKING_DATA['net_worth']['assets']:,.2f}
261
+ - Liabilities: ${MOCK_BANKING_DATA['net_worth']['liabilities']:,.2f}
262
+
263
+ User question: {query}
264
+
265
+ Provide a helpful, concise response."""
266
+
267
+ messages = [{"role": "user", "content": context}]
268
+ llm_response = generate_response(messages, max_tokens=800)
269
+ response_parts.append(llm_response)
270
+
271
+ # Combine response
272
+ state.output = "\n\n".join(response_parts)
273
+
274
+ return state.output, chart_data
hf_model.py CHANGED
@@ -8,7 +8,7 @@ from huggingface_hub import InferenceClient
8
 
9
  # Initialize client
10
  HF_TOKEN = os.getenv("HF_TOKEN")
11
- MODEL_ID = "google/gemma-3-270m-it" # Gemma 3 27B Instruct
12
 
13
  client = InferenceClient(token=HF_TOKEN)
14
 
 
8
 
9
  # Initialize client
10
  HF_TOKEN = os.getenv("HF_TOKEN")
11
+ MODEL_ID = "google/gemma-3-4b-it" # Gemma 3 27B Instruct
12
 
13
  client = InferenceClient(token=HF_TOKEN)
14