2001muhammadumair commited on
Commit
9569ba2
Β·
verified Β·
1 Parent(s): 81fb5f7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -41
app.py CHANGED
@@ -1,5 +1,3 @@
1
-
2
-
3
  # budget_tracker_with_voice_ocr.py
4
  import streamlit as st
5
  import pandas as pd
@@ -266,7 +264,7 @@ def process_voice_text(text):
266
  break
267
 
268
  # Extract numbers for amount using regex
269
- amount_pattern = r'(?:β‚Ή|\$|rs|rupees?|dollars?)\s*(\d+(?:\.\d+)?)|(\d+(?:\.\d+)?)\s*(?:β‚Ή|\$|rs|rupees?|dollars?)'
270
  matches = re.findall(amount_pattern, text_lower)
271
  if matches:
272
  for match in matches:
@@ -292,7 +290,7 @@ def process_voice_text(text):
292
  'receipt_image': ['']
293
  })
294
  st.session_state.expenses = pd.concat([st.session_state.expenses, new_expense], ignore_index=True)
295
- st.success(f"βœ… Expense logged: β‚Ή{amount:.2f} for {category}")
296
 
297
  # Check budget alerts
298
  check_budget_alerts(amount, category)
@@ -442,8 +440,8 @@ def ocr_receipt_processing():
442
  if amount == 0:
443
  # Extract amount with multiple patterns
444
  amount_patterns = [
445
- r'[$₹€£]\s*(\d+(?:\.\d+)?)',
446
- r'(\d+(?:\.\d+)?)\s*[$₹€£]',
447
  r'(?:total|amount|paid|grand total).*?(\d+(?:\.\d+)?)',
448
  r'(?:bill|invoice).*?(\d+(?:\.\d+)?)'
449
  ]
@@ -489,7 +487,7 @@ def ocr_receipt_processing():
489
  'receipt_image': [image_data]
490
  })
491
  st.session_state.expenses = pd.concat([st.session_state.expenses, new_expense], ignore_index=True)
492
- st.success(f"βœ… Receipt processed successfully: β‚Ή{amount:.2f} for {category}")
493
 
494
  # Check budget alerts
495
  check_budget_alerts(amount, category)
@@ -525,7 +523,7 @@ def create_budget():
525
  else:
526
  category = st.text_input("Enter custom category")
527
  with col2:
528
- budget_amount = st.number_input("Budget Amount (β‚Ή)", min_value=0.0, step=100.0, value=1000.0)
529
  period = st.selectbox("Period", ["Monthly", "Weekly", "Custom"])
530
 
531
  # AI-powered budget recommendations
@@ -535,7 +533,7 @@ def create_budget():
535
  try:
536
  # Prepare spending history for LLM
537
  spending_summary = st.session_state.expenses.groupby('category')['amount'].sum().to_dict()
538
- spending_text = "\n".join([f"{cat}: β‚Ή{amt:.2f}" for cat, amt in spending_summary.items()])
539
 
540
  prompt = f"""
541
  Based on this user's spending history:
@@ -556,7 +554,7 @@ def create_budget():
556
  recommendation = re.findall(r'\d+(?:\.\d+)?', response.content)
557
  if recommendation:
558
  recommended_amount = float(recommendation[0])
559
- st.info(f"πŸ€– AI Recommendation: β‚Ή{recommended_amount:.2f} for {category}")
560
  except:
561
  st.info("πŸ€– AI Recommendation: " + response.content)
562
 
@@ -578,7 +576,7 @@ def create_budget():
578
  st.session_state.budgets.loc[
579
  st.session_state.budgets['category'] == category, 'period'
580
  ] = period
581
- st.success(f"πŸ”„ Budget updated: β‚Ή{budget_amount:.2f} for {category}")
582
  else:
583
  # Add new budget
584
  new_budget = pd.DataFrame({
@@ -587,7 +585,7 @@ def create_budget():
587
  'period': [period]
588
  })
589
  st.session_state.budgets = pd.concat([st.session_state.budgets, new_budget], ignore_index=True)
590
- st.success(f"βœ… Budget set: β‚Ή{budget_amount:.2f} for {category}")
591
  except Exception as e:
592
  st.error(f"❌ Error setting budget: {str(e)}")
593
  else:
@@ -623,7 +621,7 @@ def set_savings_goals():
623
  with col1:
624
  goal_name = st.text_input("Goal Name", placeholder="e.g., Vacation, Emergency Fund")
625
  with col2:
626
- target_amount = st.number_input("Target Amount (β‚Ή)", min_value=0.0, step=1000.0, value=10000.0)
627
  with col3:
628
  target_date = st.date_input("Target Date",
629
  value=datetime.now() + timedelta(days=30))
@@ -640,9 +638,9 @@ def set_savings_goals():
640
 
641
  prompt = f"""
642
  Based on this financial situation:
643
- - Monthly income (budgeted): β‚Ή{total_income:.2f}
644
- - Monthly spending: β‚Ή{total_spending:.2f}
645
- - Current savings: β‚Ή{current_savings:.2f}
646
 
647
  For a savings goal named '{goal_name}', suggest:
648
  1. A realistic target amount
@@ -688,7 +686,7 @@ def set_savings_goals():
688
  days_left = (goal['target_date'] - datetime.now().date()).days
689
  st.write(f"**{goal['goal_name']}**")
690
  st.progress(min(progress/100, 1.0))
691
- st.write(f"πŸ’° β‚Ή{goal['current_amount']:.2f} / β‚Ή{goal['target_amount']:.2f} ({progress:.1f}%)")
692
  st.write(f"πŸ“… Target Date: {goal['target_date']} ({days_left} days left)")
693
 
694
  # Add to current savings
@@ -697,7 +695,7 @@ def set_savings_goals():
697
  if st.button(f"βž• Add to {goal['goal_name']}", key=f"btn_{idx}"):
698
  if add_amount > 0:
699
  st.session_state.savings_goals.at[idx, 'current_amount'] += add_amount
700
- st.success(f"βœ… Added β‚Ή{add_amount:.2f} to {goal['goal_name']}")
701
  st.rerun()
702
  st.write("---")
703
  except Exception as e:
@@ -721,7 +719,7 @@ def spending_categorization():
721
  st.write("πŸ“ Uncategorized Expenses:")
722
  for idx, expense in uncategorized.iterrows():
723
  try:
724
- st.write(f"πŸ“… {expense['date']} | β‚Ή{expense['amount']:.2f} | {expense['description']}")
725
  predefined_categories = ["Food", "Transport", "Shopping", "Entertainment", "Bills", "Health", "Education", "Other"]
726
  new_category = st.selectbox(f"Re-categorize", predefined_categories,
727
  key=f"cat_{idx}")
@@ -777,8 +775,8 @@ def spending_categorization():
777
  st.subheader("πŸ“Š Summary")
778
  total_spent = filtered_expenses['amount'].sum()
779
  avg_spent = filtered_expenses['amount'].mean()
780
- st.metric("Total Spent", f"β‚Ή{total_spent:.2f}")
781
- st.metric("Average Expense", f"β‚Ή{avg_spent:.2f}")
782
 
783
  # AI-powered spending analysis
784
  if st.button("πŸ€– Analyze Spending Patterns"):
@@ -787,7 +785,7 @@ def spending_categorization():
787
  try:
788
  # Prepare spending data for analysis
789
  category_spending = filtered_expenses.groupby('category')['amount'].sum().to_dict()
790
- spending_text = "\n".join([f"{cat}: β‚Ή{amt:.2f}" for cat, amt in category_spending.items()])
791
 
792
  prompt = f"""
793
  Analyze this spending pattern and provide insights:
@@ -833,11 +831,11 @@ def check_budget_alerts(amount, category):
833
  ]['amount'].sum()
834
 
835
  if current_spending > budget_amount:
836
- alert_msg = f"🚨 OVERSPENT: {category} - β‚Ή{current_spending:.2f}/β‚Ή{budget_amount:.2f}"
837
  if alert_msg not in st.session_state.notifications:
838
  st.session_state.notifications.append(alert_msg)
839
  elif current_spending > budget_amount * 0.8: # 80% threshold
840
- alert_msg = f"⚠️ WARNING: {category} - β‚Ή{current_spending:.2f}/β‚Ή{budget_amount:.2f} ({((current_spending/budget_amount)*100):.1f}%)"
841
  if alert_msg not in st.session_state.notifications:
842
  st.session_state.notifications.append(alert_msg)
843
  except Exception as e:
@@ -850,7 +848,7 @@ def generate_financial_insight_for_expense(expense):
850
  if llm:
851
  prompt = f"""
852
  For this expense:
853
- - Amount: β‚Ή{expense['amount']:.2f}
854
  - Category: {expense['category']}
855
  - Description: {expense['description']}
856
 
@@ -895,9 +893,9 @@ def alerts_and_notifications():
895
  spent = category_spending.iloc[0]['amount']
896
  budget_amount = budget['budget_amount']
897
  if spent > budget_amount:
898
- alerts.append(f"🚨 OVERSPENT: {budget['category']} - β‚Ή{spent:.2f}/β‚Ή{budget_amount:.2f} ({((spent/budget_amount)*100):.1f}%)")
899
  elif spent > budget_amount * 0.8: # 80% threshold
900
- alerts.append(f"⚠️ WARNING: {budget['category']} - β‚Ή{spent:.2f}/β‚Ή{budget_amount:.2f} ({((spent/budget_amount)*100):.1f}%)")
901
 
902
  # Display alerts
903
  if alerts:
@@ -967,7 +965,7 @@ def visualizations_and_summaries():
967
  ]
968
  if not monthly_expenses.empty:
969
  total_spent = monthly_expenses['amount'].sum()
970
- st.metric("Total Monthly Spending", f"β‚Ή{total_spent:.2f}")
971
  category_summary = monthly_expenses.groupby('category')['amount'].sum().reset_index()
972
  fig3 = px.bar(category_summary, x='category', y='amount',
973
  title='Monthly Spending by Category')
@@ -1008,17 +1006,17 @@ def visualizations_and_summaries():
1008
  # Prepare data for summary
1009
  total_expenses = st.session_state.expenses['amount'].sum()
1010
  category_spending = st.session_state.expenses.groupby('category')['amount'].sum().to_dict()
1011
- spending_text = "\n".join([f"{cat}: β‚Ή{amt:.2f}" for cat, amt in category_spending.items()])
1012
 
1013
  # Get budget data
1014
  total_budget = st.session_state.budgets['budget_amount'].sum()
1015
- budget_text = "\n".join([f"{row['category']}: β‚Ή{row['budget_amount']:.2f}"
1016
  for _, row in st.session_state.budgets.iterrows()])
1017
 
1018
  prompt = f"""
1019
  Based on this financial data:
1020
 
1021
- Total Expenses: β‚Ή{total_expenses:.2f}
1022
 
1023
  Spending by Category:
1024
  {spending_text}
@@ -1093,7 +1091,7 @@ def receipt_management():
1093
  try:
1094
  with cols[idx % 3]:
1095
  st.write(f"**πŸ“… {receipt['date']}**")
1096
- st.write(f"πŸ’° β‚Ή{receipt['amount']:.2f}")
1097
  st.write(f"🏷️ {receipt['category']}")
1098
  if receipt['receipt_image'].startswith('data:image'):
1099
  # Display base64 image
@@ -1107,7 +1105,7 @@ def receipt_management():
1107
  try:
1108
  prompt = f"""
1109
  Analyze this receipt expense:
1110
- - Amount: β‚Ή{receipt['amount']:.2f}
1111
  - Category: {receipt['category']}
1112
  - Date: {receipt['date']}
1113
 
@@ -1266,11 +1264,11 @@ def main_dashboard():
1266
  expense_count = len(st.session_state.expenses)
1267
 
1268
  with col1:
1269
- st.metric("πŸ’° Total Expenses", f"β‚Ή{total_expenses:.2f}")
1270
  with col2:
1271
- st.metric("πŸ“Š Total Budget", f"β‚Ή{total_budget:.2f}")
1272
  with col3:
1273
- st.metric("πŸ† Total Savings", f"β‚Ή{total_savings:.2f}")
1274
  with col4:
1275
  st.metric("🧾 Expense Count", f"{expense_count}")
1276
 
@@ -1308,7 +1306,7 @@ def main_dashboard():
1308
  progress = (category_spending / budget['budget_amount']) * 100 if budget['budget_amount'] > 0 else 0
1309
  st.write(f"**{budget['category']}**")
1310
  st.progress(min(progress/100, 1.0))
1311
- st.write(f"β‚Ή{category_spending:.2f} / β‚Ή{budget['budget_amount']:.2f} ({progress:.1f}%)")
1312
 
1313
  # Savings goals progress
1314
  if not st.session_state.savings_goals.empty:
@@ -1317,7 +1315,7 @@ def main_dashboard():
1317
  progress = (goal['current_amount'] / goal['target_amount']) * 100 if goal['target_amount'] > 0 else 0
1318
  st.write(f"**{goal['goal_name']}**")
1319
  st.progress(min(progress/100, 1.0))
1320
- st.write(f"β‚Ή{goal['current_amount']:.2f} / β‚Ή{goal['target_amount']:.2f} ({progress:.1f}%)")
1321
 
1322
  # AI-powered financial health score
1323
  if st.button("πŸ€– Calculate Financial Health Score"):
@@ -1334,9 +1332,9 @@ def main_dashboard():
1334
 
1335
  prompt = f"""
1336
  Calculate a financial health score (0-100) based on:
1337
- - Total income/budget: β‚Ή{total_income:.2f}
1338
- - Total spending: β‚Ή{total_spent:.2f}
1339
- - Savings amount: β‚Ή{total_savings:.2f}
1340
  - Savings rate: {savings_rate:.1f}%
1341
  - Spending category diversity: {category_count} categories
1342
 
 
 
 
1
  # budget_tracker_with_voice_ocr.py
2
  import streamlit as st
3
  import pandas as pd
 
264
  break
265
 
266
  # Extract numbers for amount using regex
267
+ amount_pattern = r'(?:$|\$|rs|rupees?|dollars?)\s*(\d+(?:\.\d+)?)|(\d+(?:\.\d+)?)\s*(?:$|\$|rs|rupees?|dollars?)'
268
  matches = re.findall(amount_pattern, text_lower)
269
  if matches:
270
  for match in matches:
 
290
  'receipt_image': ['']
291
  })
292
  st.session_state.expenses = pd.concat([st.session_state.expenses, new_expense], ignore_index=True)
293
+ st.success(f"βœ… Expense logged: ${amount:.2f} for {category}")
294
 
295
  # Check budget alerts
296
  check_budget_alerts(amount, category)
 
440
  if amount == 0:
441
  # Extract amount with multiple patterns
442
  amount_patterns = [
443
+ r'[$$€£]\s*(\d+(?:\.\d+)?)',
444
+ r'(\d+(?:\.\d+)?)\s*[$$€£]',
445
  r'(?:total|amount|paid|grand total).*?(\d+(?:\.\d+)?)',
446
  r'(?:bill|invoice).*?(\d+(?:\.\d+)?)'
447
  ]
 
487
  'receipt_image': [image_data]
488
  })
489
  st.session_state.expenses = pd.concat([st.session_state.expenses, new_expense], ignore_index=True)
490
+ st.success(f"βœ… Receipt processed successfully: ${amount:.2f} for {category}")
491
 
492
  # Check budget alerts
493
  check_budget_alerts(amount, category)
 
523
  else:
524
  category = st.text_input("Enter custom category")
525
  with col2:
526
+ budget_amount = st.number_input("Budget Amount ($)", min_value=0.0, step=100.0, value=1000.0)
527
  period = st.selectbox("Period", ["Monthly", "Weekly", "Custom"])
528
 
529
  # AI-powered budget recommendations
 
533
  try:
534
  # Prepare spending history for LLM
535
  spending_summary = st.session_state.expenses.groupby('category')['amount'].sum().to_dict()
536
+ spending_text = "\n".join([f"{cat}: ${amt:.2f}" for cat, amt in spending_summary.items()])
537
 
538
  prompt = f"""
539
  Based on this user's spending history:
 
554
  recommendation = re.findall(r'\d+(?:\.\d+)?', response.content)
555
  if recommendation:
556
  recommended_amount = float(recommendation[0])
557
+ st.info(f"πŸ€– AI Recommendation: ${recommended_amount:.2f} for {category}")
558
  except:
559
  st.info("πŸ€– AI Recommendation: " + response.content)
560
 
 
576
  st.session_state.budgets.loc[
577
  st.session_state.budgets['category'] == category, 'period'
578
  ] = period
579
+ st.success(f"πŸ”„ Budget updated: ${budget_amount:.2f} for {category}")
580
  else:
581
  # Add new budget
582
  new_budget = pd.DataFrame({
 
585
  'period': [period]
586
  })
587
  st.session_state.budgets = pd.concat([st.session_state.budgets, new_budget], ignore_index=True)
588
+ st.success(f"βœ… Budget set: ${budget_amount:.2f} for {category}")
589
  except Exception as e:
590
  st.error(f"❌ Error setting budget: {str(e)}")
591
  else:
 
621
  with col1:
622
  goal_name = st.text_input("Goal Name", placeholder="e.g., Vacation, Emergency Fund")
623
  with col2:
624
+ target_amount = st.number_input("Target Amount ($)", min_value=0.0, step=1000.0, value=10000.0)
625
  with col3:
626
  target_date = st.date_input("Target Date",
627
  value=datetime.now() + timedelta(days=30))
 
638
 
639
  prompt = f"""
640
  Based on this financial situation:
641
+ - Monthly income (budgeted): ${total_income:.2f}
642
+ - Monthly spending: ${total_spending:.2f}
643
+ - Current savings: ${current_savings:.2f}
644
 
645
  For a savings goal named '{goal_name}', suggest:
646
  1. A realistic target amount
 
686
  days_left = (goal['target_date'] - datetime.now().date()).days
687
  st.write(f"**{goal['goal_name']}**")
688
  st.progress(min(progress/100, 1.0))
689
+ st.write(f"πŸ’° ${goal['current_amount']:.2f} / ${goal['target_amount']:.2f} ({progress:.1f}%)")
690
  st.write(f"πŸ“… Target Date: {goal['target_date']} ({days_left} days left)")
691
 
692
  # Add to current savings
 
695
  if st.button(f"βž• Add to {goal['goal_name']}", key=f"btn_{idx}"):
696
  if add_amount > 0:
697
  st.session_state.savings_goals.at[idx, 'current_amount'] += add_amount
698
+ st.success(f"βœ… Added ${add_amount:.2f} to {goal['goal_name']}")
699
  st.rerun()
700
  st.write("---")
701
  except Exception as e:
 
719
  st.write("πŸ“ Uncategorized Expenses:")
720
  for idx, expense in uncategorized.iterrows():
721
  try:
722
+ st.write(f"πŸ“… {expense['date']} | ${expense['amount']:.2f} | {expense['description']}")
723
  predefined_categories = ["Food", "Transport", "Shopping", "Entertainment", "Bills", "Health", "Education", "Other"]
724
  new_category = st.selectbox(f"Re-categorize", predefined_categories,
725
  key=f"cat_{idx}")
 
775
  st.subheader("πŸ“Š Summary")
776
  total_spent = filtered_expenses['amount'].sum()
777
  avg_spent = filtered_expenses['amount'].mean()
778
+ st.metric("Total Spent", f"${total_spent:.2f}")
779
+ st.metric("Average Expense", f"${avg_spent:.2f}")
780
 
781
  # AI-powered spending analysis
782
  if st.button("πŸ€– Analyze Spending Patterns"):
 
785
  try:
786
  # Prepare spending data for analysis
787
  category_spending = filtered_expenses.groupby('category')['amount'].sum().to_dict()
788
+ spending_text = "\n".join([f"{cat}: ${amt:.2f}" for cat, amt in category_spending.items()])
789
 
790
  prompt = f"""
791
  Analyze this spending pattern and provide insights:
 
831
  ]['amount'].sum()
832
 
833
  if current_spending > budget_amount:
834
+ alert_msg = f"🚨 OVERSPENT: {category} - ${current_spending:.2f}/${budget_amount:.2f}"
835
  if alert_msg not in st.session_state.notifications:
836
  st.session_state.notifications.append(alert_msg)
837
  elif current_spending > budget_amount * 0.8: # 80% threshold
838
+ alert_msg = f"⚠️ WARNING: {category} - ${current_spending:.2f}/${budget_amount:.2f} ({((current_spending/budget_amount)*100):.1f}%)"
839
  if alert_msg not in st.session_state.notifications:
840
  st.session_state.notifications.append(alert_msg)
841
  except Exception as e:
 
848
  if llm:
849
  prompt = f"""
850
  For this expense:
851
+ - Amount: ${expense['amount']:.2f}
852
  - Category: {expense['category']}
853
  - Description: {expense['description']}
854
 
 
893
  spent = category_spending.iloc[0]['amount']
894
  budget_amount = budget['budget_amount']
895
  if spent > budget_amount:
896
+ alerts.append(f"🚨 OVERSPENT: {budget['category']} - ${spent:.2f}/${budget_amount:.2f} ({((spent/budget_amount)*100):.1f}%)")
897
  elif spent > budget_amount * 0.8: # 80% threshold
898
+ alerts.append(f"⚠️ WARNING: {budget['category']} - ${spent:.2f}/${budget_amount:.2f} ({((spent/budget_amount)*100):.1f}%)")
899
 
900
  # Display alerts
901
  if alerts:
 
965
  ]
966
  if not monthly_expenses.empty:
967
  total_spent = monthly_expenses['amount'].sum()
968
+ st.metric("Total Monthly Spending", f"${total_spent:.2f}")
969
  category_summary = monthly_expenses.groupby('category')['amount'].sum().reset_index()
970
  fig3 = px.bar(category_summary, x='category', y='amount',
971
  title='Monthly Spending by Category')
 
1006
  # Prepare data for summary
1007
  total_expenses = st.session_state.expenses['amount'].sum()
1008
  category_spending = st.session_state.expenses.groupby('category')['amount'].sum().to_dict()
1009
+ spending_text = "\n".join([f"{cat}: ${amt:.2f}" for cat, amt in category_spending.items()])
1010
 
1011
  # Get budget data
1012
  total_budget = st.session_state.budgets['budget_amount'].sum()
1013
+ budget_text = "\n".join([f"{row['category']}: ${row['budget_amount']:.2f}"
1014
  for _, row in st.session_state.budgets.iterrows()])
1015
 
1016
  prompt = f"""
1017
  Based on this financial data:
1018
 
1019
+ Total Expenses: ${total_expenses:.2f}
1020
 
1021
  Spending by Category:
1022
  {spending_text}
 
1091
  try:
1092
  with cols[idx % 3]:
1093
  st.write(f"**πŸ“… {receipt['date']}**")
1094
+ st.write(f"πŸ’° ${receipt['amount']:.2f}")
1095
  st.write(f"🏷️ {receipt['category']}")
1096
  if receipt['receipt_image'].startswith('data:image'):
1097
  # Display base64 image
 
1105
  try:
1106
  prompt = f"""
1107
  Analyze this receipt expense:
1108
+ - Amount: ${receipt['amount']:.2f}
1109
  - Category: {receipt['category']}
1110
  - Date: {receipt['date']}
1111
 
 
1264
  expense_count = len(st.session_state.expenses)
1265
 
1266
  with col1:
1267
+ st.metric("πŸ’° Total Expenses", f"${total_expenses:.2f}")
1268
  with col2:
1269
+ st.metric("πŸ“Š Total Budget", f"${total_budget:.2f}")
1270
  with col3:
1271
+ st.metric("πŸ† Total Savings", f"${total_savings:.2f}")
1272
  with col4:
1273
  st.metric("🧾 Expense Count", f"{expense_count}")
1274
 
 
1306
  progress = (category_spending / budget['budget_amount']) * 100 if budget['budget_amount'] > 0 else 0
1307
  st.write(f"**{budget['category']}**")
1308
  st.progress(min(progress/100, 1.0))
1309
+ st.write(f"${category_spending:.2f} / ${budget['budget_amount']:.2f} ({progress:.1f}%)")
1310
 
1311
  # Savings goals progress
1312
  if not st.session_state.savings_goals.empty:
 
1315
  progress = (goal['current_amount'] / goal['target_amount']) * 100 if goal['target_amount'] > 0 else 0
1316
  st.write(f"**{goal['goal_name']}**")
1317
  st.progress(min(progress/100, 1.0))
1318
+ st.write(f"${goal['current_amount']:.2f} / ${goal['target_amount']:.2f} ({progress:.1f}%)")
1319
 
1320
  # AI-powered financial health score
1321
  if st.button("πŸ€– Calculate Financial Health Score"):
 
1332
 
1333
  prompt = f"""
1334
  Calculate a financial health score (0-100) based on:
1335
+ - Total income/budget: ${total_income:.2f}
1336
+ - Total spending: ${total_spent:.2f}
1337
+ - Savings amount: ${total_savings:.2f}
1338
  - Savings rate: {savings_rate:.1f}%
1339
  - Spending category diversity: {category_count} categories
1340