Abid Ali Awan commited on
Commit
563fd53
Β·
1 Parent(s): ea3677f

Refactor financial tools: removed expense tracker functionality, updated budget planner keywords, and improved README with new tags and demo video link.

Browse files
Files changed (4) hide show
  1. README.md +10 -7
  2. agents/financial_agent.py +2 -4
  3. agents/tools.py +15 -169
  4. app.py +6 -12
README.md CHANGED
@@ -6,6 +6,11 @@ colorTo: blue
6
  sdk: gradio
7
  sdk_version: 5.33.0
8
  app_file: app.py
 
 
 
 
 
9
  pinned: false
10
  license: apache-2.0
11
  short_description: Financial analysis, investments, budget planning, and more.
@@ -16,6 +21,11 @@ short_description: Financial analysis, investments, budget planning, and more.
16
 
17
  An intelligent financial advisory agent powered by OpenAI's GPT-4.1 and specialized financial tools. This agent provides comprehensive financial analysis, investment recommendations, budget planning, and market insights through an intuitive web interface.
18
 
 
 
 
 
 
19
  ## πŸš€ Features
20
 
21
  ### Core Financial Tools
@@ -92,13 +102,6 @@ python app.py
92
  "Detailed portfolio analysis for my current investments"
93
  ```
94
 
95
- #### Expense Tracker
96
- ```
97
- "Track my expenses: [{'category': 'food', 'amount': 150}, {'category': 'gas', 'amount': 80}]"
98
- "Analyze my spending patterns from last month"
99
- "Help me categorize and analyze my expenses"
100
- ```
101
-
102
  ### Response Type Control
103
 
104
  #### Short Responses (Under 200 words)
 
6
  sdk: gradio
7
  sdk_version: 5.33.0
8
  app_file: app.py
9
+ tags:
10
+ - mcp-server-track
11
+ - financial-analysis
12
+ - openai
13
+ - tavily
14
  pinned: false
15
  license: apache-2.0
16
  short_description: Financial analysis, investments, budget planning, and more.
 
21
 
22
  An intelligent financial advisory agent powered by OpenAI's GPT-4.1 and specialized financial tools. This agent provides comprehensive financial analysis, investment recommendations, budget planning, and market insights through an intuitive web interface.
23
 
24
+ <!-- **Watch the demo video:** [Code Analysis MCP Demo (Agents MCP Hackathon)](https://www.youtube.com/watch?v=A4YWMMyJRsA)
25
+
26
+
27
+ [![Watch the demo on YouTube](image.png)](https://youtu.be/A4YWMMyJRsA) -->
28
+
29
  ## πŸš€ Features
30
 
31
  ### Core Financial Tools
 
102
  "Detailed portfolio analysis for my current investments"
103
  ```
104
 
 
 
 
 
 
 
 
105
  ### Response Type Control
106
 
107
  #### Short Responses (Under 200 words)
agents/financial_agent.py CHANGED
@@ -29,7 +29,6 @@ class FinancialAdvisorAgent:
29
  Available tools:
30
  - budget_planner: Use when users ask about budgeting, income allocation, or expense planning. Input should be JSON with 'income' and 'expenses' keys.
31
  - investment_analyzer: Use when users ask about specific stocks or investments. Input should be a stock symbol (e.g., AAPL).
32
- - expense_tracker: Use when users want to track or analyze expenses. Input should be JSON with 'expenses' array.
33
  - market_trends: Use when users ask about market trends or financial news. Input should be a search query.
34
  - portfolio_analyzer: Use when users want to analyze their portfolio. Input should be JSON with 'holdings' array.
35
 
@@ -134,11 +133,10 @@ When a user asks a question:
134
  # Check if this is a multi-tool query (contains keywords for multiple tools)
135
  message_lower = message.lower()
136
  tool_keywords = {
137
- "budget_planner": ["budget", "income", "expense", "spending", "allocat"],
138
  "investment_analyzer": ["stock", "invest", "buy", "sell", "analyze"],
139
  "portfolio_analyzer": ["portfolio", "holdings", "allocation", "diversif"],
140
- "market_trends": ["market", "trend", "news", "sector", "economic"],
141
- "expense_tracker": ["track", "expense", "spending", "categoriz"]
142
  }
143
 
144
  detected_tools = []
 
29
  Available tools:
30
  - budget_planner: Use when users ask about budgeting, income allocation, or expense planning. Input should be JSON with 'income' and 'expenses' keys.
31
  - investment_analyzer: Use when users ask about specific stocks or investments. Input should be a stock symbol (e.g., AAPL).
 
32
  - market_trends: Use when users ask about market trends or financial news. Input should be a search query.
33
  - portfolio_analyzer: Use when users want to analyze their portfolio. Input should be JSON with 'holdings' array.
34
 
 
133
  # Check if this is a multi-tool query (contains keywords for multiple tools)
134
  message_lower = message.lower()
135
  tool_keywords = {
136
+ "budget_planner": ["budget", "income", "expense", "spending", "allocat", "track", "categoriz"],
137
  "investment_analyzer": ["stock", "invest", "buy", "sell", "analyze"],
138
  "portfolio_analyzer": ["portfolio", "holdings", "allocation", "diversif"],
139
+ "market_trends": ["market", "trend", "news", "sector", "economic"]
 
140
  }
141
 
142
  detected_tools = []
agents/tools.py CHANGED
@@ -16,8 +16,21 @@ class FinancialTools:
16
  def budget_planner(input_str: str) -> str:
17
  """Create a personalized budget plan with advanced features"""
18
  try:
19
- data = json.loads(input_str)
20
- income = data.get("income", 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  expenses = data.get("expenses", {})
22
  goals = data.get("savings_goals", {})
23
  debt = data.get("debt", {})
@@ -300,172 +313,6 @@ class FinancialTools:
300
  func=investment_analyzer,
301
  )
302
 
303
- def create_expense_tracker(self) -> Tool:
304
- def expense_tracker(input_str: str) -> str:
305
- """Track and analyze expenses with advanced insights, trends, and predictions"""
306
- try:
307
- data = json.loads(input_str)
308
- expenses = data.get("expenses", [])
309
- historical_data = data.get("historical_expenses", [])
310
- budget_limits = data.get("budget_limits", {})
311
-
312
- # Combine current and historical data
313
- all_expenses = expenses + historical_data
314
- df = pd.DataFrame(all_expenses)
315
-
316
- if df.empty:
317
- return "No expense data provided"
318
-
319
- # Ensure date column exists and is properly formatted
320
- if "date" in df.columns:
321
- df["date"] = pd.to_datetime(df["date"])
322
- df = df.sort_values("date")
323
- else:
324
- # Add current date for expenses without dates
325
- df["date"] = datetime.now()
326
-
327
- # Current period analysis
328
- current_df = pd.DataFrame(expenses) if expenses else pd.DataFrame()
329
- total_current = current_df["amount"].sum() if not current_df.empty else 0
330
-
331
- # Category analysis
332
- category_summary = df.groupby("category")["amount"].agg(["sum", "mean", "count", "std"]).to_dict("index")
333
-
334
- # Trend analysis (if historical data available)
335
- trends = {}
336
- predictions = {}
337
-
338
- if len(df) > 1 and "date" in df.columns:
339
- # Monthly spending trends
340
- df["month"] = df["date"].dt.to_period("M")
341
- monthly_spending = df.groupby("month")["amount"].sum()
342
-
343
- if len(monthly_spending) > 1:
344
- # Calculate month-over-month growth
345
- mom_growth = monthly_spending.pct_change().iloc[-1] * 100
346
- trends["monthly_growth"] = f"{mom_growth:.1f}%"
347
-
348
- # Simple linear trend prediction for next month
349
- if len(monthly_spending) >= 3:
350
- recent_trend = monthly_spending.tail(3).mean()
351
- predictions["next_month_estimate"] = f"${recent_trend:.2f}"
352
-
353
- # Category trends
354
- for category in df["category"].unique():
355
- cat_data = df[df["category"] == category].groupby("month")["amount"].sum()
356
- if len(cat_data) > 1:
357
- cat_trend = cat_data.pct_change().iloc[-1] * 100
358
- trends[f"{category}_trend"] = f"{cat_trend:.1f}%"
359
-
360
- # Spending pattern analysis
361
- if "date" in df.columns:
362
- df["day_of_week"] = df["date"].dt.day_name()
363
- df["hour"] = df["date"].dt.hour
364
-
365
- spending_patterns = {
366
- "busiest_day": df.groupby("day_of_week")["amount"].sum().idxmax(),
367
- "peak_spending_hour": df.groupby("hour")["amount"].sum().idxmax(),
368
- }
369
- else:
370
- spending_patterns = {}
371
-
372
- # Budget analysis
373
- budget_analysis = {}
374
- if budget_limits:
375
- for category, limit in budget_limits.items():
376
- cat_spending = category_summary.get(category, {}).get("sum", 0)
377
- budget_analysis[category] = {
378
- "limit": f"${limit:.2f}",
379
- "spent": f"${cat_spending:.2f}",
380
- "remaining": f"${max(0, limit - cat_spending):.2f}",
381
- "percentage_used": f"{(cat_spending / limit * 100):.1f}%" if limit > 0 else "N/A",
382
- "status": "Over Budget" if cat_spending > limit else "Within Budget"
383
- }
384
-
385
- # Anomaly detection (expenses significantly above average)
386
- anomalies = []
387
- if not df.empty:
388
- for category in df["category"].unique():
389
- cat_data = df[df["category"] == category]["amount"]
390
- if len(cat_data) > 2:
391
- mean_spending = cat_data.mean()
392
- std_spending = cat_data.std()
393
- threshold = mean_spending + (2 * std_spending)
394
-
395
- recent_anomalies = cat_data[cat_data > threshold]
396
- if not recent_anomalies.empty:
397
- anomalies.append({
398
- "category": category,
399
- "unusual_amount": f"${recent_anomalies.iloc[-1]:.2f}",
400
- "typical_range": f"${mean_spending:.2f} Β± ${std_spending:.2f}"
401
- })
402
-
403
- # Generate insights and recommendations
404
- insights = []
405
- recommendations = []
406
-
407
- # Top spending categories
408
- top_categories = sorted(category_summary.items(), key=lambda x: x[1]["sum"], reverse=True)[:3]
409
- category_strings = [f'{cat} (${data["sum"]:.2f})' for cat, data in top_categories]
410
- insights.append(f"Top 3 spending categories: {', '.join(category_strings)}")
411
-
412
- # Spending frequency analysis
413
- if not df.empty:
414
- avg_transaction = df["amount"].mean()
415
- insights.append(f"Average transaction: ${avg_transaction:.2f}")
416
-
417
- if avg_transaction > 100:
418
- recommendations.append("Consider breaking down large expenses into smaller, more frequent transactions for better budget control")
419
-
420
- # Trend-based recommendations
421
- if "monthly_growth" in trends:
422
- growth = float(trends["monthly_growth"].rstrip("%"))
423
- if growth > 10:
424
- recommendations.append(f"Spending increased {growth:.1f}% this month. Review discretionary expenses.")
425
- elif growth < -10:
426
- recommendations.append(f"Good job! Spending decreased {abs(growth):.1f}% this month.")
427
-
428
- # Budget recommendations
429
- for category, analysis in budget_analysis.items():
430
- if "Over Budget" in analysis["status"]:
431
- recommendations.append(f"Reduce {category} spending - currently over budget")
432
- elif float(analysis["percentage_used"].rstrip("%")) > 80:
433
- recommendations.append(f"Approaching {category} budget limit ({analysis['percentage_used']})")
434
-
435
- analysis_result = {
436
- "current_period": {
437
- "total_expenses": f"${total_current:.2f}",
438
- "transaction_count": len(current_df) if not current_df.empty else 0,
439
- "average_transaction": f"${(total_current / len(current_df)):.2f}" if not current_df.empty else "$0.00",
440
- },
441
- "category_analysis": {
442
- category: {
443
- "total": f"${data['sum']:.2f}",
444
- "average": f"${data['mean']:.2f}",
445
- "transactions": int(data['count']),
446
- "variability": f"${data.get('std', 0):.2f}"
447
- } for category, data in category_summary.items()
448
- },
449
- "trends": trends,
450
- "predictions": predictions,
451
- "spending_patterns": spending_patterns,
452
- "budget_analysis": budget_analysis,
453
- "anomalies": anomalies,
454
- "insights": insights,
455
- "recommendations": recommendations,
456
- "analysis_date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
457
- }
458
-
459
- return json.dumps(analysis_result, indent=2)
460
-
461
- except Exception as e:
462
- return f"Error tracking expenses: {str(e)}"
463
-
464
- return Tool(
465
- name="expense_tracker",
466
- description="Track and analyze expenses with detailed insights",
467
- func=expense_tracker,
468
- )
469
 
470
  def create_market_trends_analyzer(self) -> Tool:
471
  def market_trends(query: str) -> str:
@@ -690,7 +537,6 @@ class FinancialTools:
690
  return [
691
  self.create_budget_planner(),
692
  self.create_investment_analyzer(),
693
- self.create_expense_tracker(),
694
  self.create_market_trends_analyzer(),
695
  self.create_portfolio_analyzer(),
696
  ]
 
16
  def budget_planner(input_str: str) -> str:
17
  """Create a personalized budget plan with advanced features"""
18
  try:
19
+ # Handle empty or invalid input
20
+ if not input_str or input_str.strip() == "":
21
+ input_str = '{"income": 5000, "expenses": {}}'
22
+
23
+ # Try to parse JSON, if it fails, try to extract values from text
24
+ try:
25
+ data = json.loads(input_str)
26
+ except json.JSONDecodeError:
27
+ # Fallback: extract income and expenses from text
28
+ import re
29
+ income_match = re.search(r'(\$?[\d,]+(?:\.\d{2})?)', input_str)
30
+ income = float(income_match.group(1).replace('$', '').replace(',', '')) if income_match else 5000
31
+ data = {"income": income, "expenses": {}}
32
+
33
+ income = data.get("income", 5000)
34
  expenses = data.get("expenses", {})
35
  goals = data.get("savings_goals", {})
36
  debt = data.get("debt", {})
 
313
  func=investment_analyzer,
314
  )
315
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
 
317
  def create_market_trends_analyzer(self) -> Tool:
318
  def market_trends(query: str) -> str:
 
537
  return [
538
  self.create_budget_planner(),
539
  self.create_investment_analyzer(),
 
540
  self.create_market_trends_analyzer(),
541
  self.create_portfolio_analyzer(),
542
  ]
app.py CHANGED
@@ -414,17 +414,15 @@ def determine_intended_tool(message):
414
  message_lower = message.lower()
415
 
416
  tool_detection_map = {
417
- "budget_planner": ["budget", "income", "expense", "spending", "allocat", "monthly", "plan", "financial plan", "money"],
418
  "investment_analyzer": ["stock", "invest", "buy", "sell", "analyze", "AAPL", "GOOGL", "TSLA", "share", "equity"],
419
  "portfolio_analyzer": ["portfolio", "holdings", "allocation", "diversif", "asset", "position"],
420
- "market_trends": ["market", "trend", "news", "sector", "economic", "latest", "current"],
421
- "expense_tracker": ["track", "expense", "spending", "categoriz", "cost"]
422
  }
423
 
424
  tool_names = {
425
  "budget_planner": "Budget Planner",
426
- "investment_analyzer": "Investment Analyzer",
427
- "expense_tracker": "Expense Tracker",
428
  "market_trends": "Market Trends Analyzer",
429
  "portfolio_analyzer": "Portfolio Analyzer",
430
  }
@@ -512,8 +510,6 @@ def process_financial_query(message, history):
512
  status_msg = f"πŸ’° Processing budget analysis (estimated 5-10 seconds)..."
513
  elif intended_tool_key == "portfolio_analyzer":
514
  status_msg = f"πŸ“Š Analyzing portfolio data (estimated 8-12 seconds)..."
515
- elif intended_tool_key == "expense_tracker":
516
- status_msg = f"πŸ’³ Processing expense analysis (estimated 5-10 seconds)..."
517
  else:
518
  status_msg = f"πŸ”„ Using {intended_tool_name} (estimated 5-15 seconds)..."
519
 
@@ -539,16 +535,14 @@ def process_financial_query(message, history):
539
 
540
  tool_names = {
541
  "budget_planner": "Budget Planner",
542
- "investment_analyzer": "Investment Analyzer",
543
- "expense_tracker": "Expense Tracker",
544
  "market_trends": "Market Trends Analyzer",
545
  "portfolio_analyzer": "Portfolio Analyzer",
546
  }
547
 
548
  tool_emojis = {
549
  "Budget Planner": "πŸ’°",
550
- "Investment Analyzer": "πŸ“ˆ",
551
- "Expense Tracker": "πŸ’³",
552
  "Market Trends Analyzer": "πŸ“°",
553
  "Portfolio Analyzer": "πŸ“Š",
554
  }
@@ -744,4 +738,4 @@ with gr.Blocks(theme=gr.themes.Base(), title="Financial Advisory Agent") as demo
744
  chatbot.like(like_handler)
745
 
746
  if __name__ == "__main__":
747
- demo.launch(debug=True)
 
414
  message_lower = message.lower()
415
 
416
  tool_detection_map = {
417
+ "budget_planner": ["budget", "income", "expense", "spending", "allocat", "monthly", "plan", "financial plan", "money", "track", "categoriz", "cost"],
418
  "investment_analyzer": ["stock", "invest", "buy", "sell", "analyze", "AAPL", "GOOGL", "TSLA", "share", "equity"],
419
  "portfolio_analyzer": ["portfolio", "holdings", "allocation", "diversif", "asset", "position"],
420
+ "market_trends": ["market", "trend", "news", "sector", "economic", "latest", "current"]
 
421
  }
422
 
423
  tool_names = {
424
  "budget_planner": "Budget Planner",
425
+ "investment_analyzer": "Investment Analyzer",
 
426
  "market_trends": "Market Trends Analyzer",
427
  "portfolio_analyzer": "Portfolio Analyzer",
428
  }
 
510
  status_msg = f"πŸ’° Processing budget analysis (estimated 5-10 seconds)..."
511
  elif intended_tool_key == "portfolio_analyzer":
512
  status_msg = f"πŸ“Š Analyzing portfolio data (estimated 8-12 seconds)..."
 
 
513
  else:
514
  status_msg = f"πŸ”„ Using {intended_tool_name} (estimated 5-15 seconds)..."
515
 
 
535
 
536
  tool_names = {
537
  "budget_planner": "Budget Planner",
538
+ "investment_analyzer": "Investment Analyzer",
 
539
  "market_trends": "Market Trends Analyzer",
540
  "portfolio_analyzer": "Portfolio Analyzer",
541
  }
542
 
543
  tool_emojis = {
544
  "Budget Planner": "πŸ’°",
545
+ "Investment Analyzer": "πŸ“ˆ",
 
546
  "Market Trends Analyzer": "πŸ“°",
547
  "Portfolio Analyzer": "πŸ“Š",
548
  }
 
738
  chatbot.like(like_handler)
739
 
740
  if __name__ == "__main__":
741
+ demo.launch()