From 9975e7eea278614b212e497392c1839ff9b2ea74 Mon Sep 17 00:00:00 2001 From: Madhu Date: Sun, 13 Apr 2025 22:10:33 +0530 Subject: [PATCH] completed the script - readme --- .../ai_financial_coach_agent/.env | 2 +- .../ai_financial_coach_agent/README.md | 78 +++ .../ai_financial_coach_agent.py | 565 ++++++++++++++---- .../ai_financial_coach_agent/requirements.txt | 4 +- 4 files changed, 520 insertions(+), 129 deletions(-) diff --git a/ai_agent_tutorials/ai_financial_coach_agent/.env b/ai_agent_tutorials/ai_financial_coach_agent/.env index b8d7980..bc02262 100644 --- a/ai_agent_tutorials/ai_financial_coach_agent/.env +++ b/ai_agent_tutorials/ai_financial_coach_agent/.env @@ -1 +1 @@ -GOOGLE_API_KEY= \ No newline at end of file +GOOGLE_API_KEY=your_gemini_api_key_here \ No newline at end of file diff --git a/ai_agent_tutorials/ai_financial_coach_agent/README.md b/ai_agent_tutorials/ai_financial_coach_agent/README.md index 8b13789..c73671e 100644 --- a/ai_agent_tutorials/ai_financial_coach_agent/README.md +++ b/ai_agent_tutorials/ai_financial_coach_agent/README.md @@ -1 +1,79 @@ +# AI Financial Coach Agent with Google ADK 💰 +The **AI Financial Coach** is a personalized financial advisor powered by Google's ADK (Agent Development Kit) framework. This app provides comprehensive financial analysis and recommendations based on user inputs including income, expenses, debts, and financial goals. + +## Features + +- **Multi-Agent Financial Analysis System** + - Budget Analysis Agent: Analyzes spending patterns and recommends optimizations + - Savings Strategy Agent: Creates personalized savings plans and emergency fund strategies + - Debt Reduction Agent: Develops optimized debt payoff strategies using avalanche and snowball methods + +- **Expense Analysis**: + - Supports both CSV upload and manual expense entry + - CSV transaction analysis with date, category, and amount tracking + - Visual breakdown of spending by category + - Automated expense categorization and pattern detection + +- **Savings Recommendations**: + - Emergency fund sizing and building strategies + - Custom savings allocations across different goals + - Practical automation techniques for consistent saving + - Progress tracking and milestone recommendations + +- **Debt Management**: + - Multiple debt handling with interest rate optimization + - Comparison between avalanche and snowball methods + - Visual debt payoff timeline and interest savings analysis + - Actionable debt reduction recommendations + +- **Interactive Visualizations**: + - Pie charts for expense breakdown + - Bar charts for income vs. expenses + - Debt comparison graphs + - Progress tracking metrics + + +## How to Run + +Follow the steps below to set up and run the application: + +1. **Get API Key**: + - Get a free Gemini API Key from Google AI Studio: https://aistudio.google.com/apikey + - Create a `.env` file in the project root and add your API key: + ``` + GOOGLE_API_KEY=your_api_key_here + ``` + +2. **Clone the Repository**: + ```bash + git clone https://github.com/Shubhamsaboo/awesome-llm-apps.git + cd awesome-llm-apps/ai_agent_tutorials/ai_financial_coach_agent + ``` + +3. **Install Dependencies**: + ```bash + pip install -r requirements.txt + ``` + +4. **Run the Streamlit App**: + ```bash + streamlit run ai_financial_coach_agent.py + ``` + +## CSV File Format + +The application accepts CSV files with the following required columns: +- `Date`: Transaction date in YYYY-MM-DD format +- `Category`: Expense category +- `Amount`: Transaction amount (supports currency symbols and comma formatting) + +Example: +```csv +Date,Category,Amount +2024-01-01,Housing,1200.00 +2024-01-02,Food,150.50 +2024-01-03,Transportation,45.00 +``` + +A template CSV file can be downloaded directly from the application's sidebar. diff --git a/ai_agent_tutorials/ai_financial_coach_agent/ai_financial_coach_agent.py b/ai_agent_tutorials/ai_financial_coach_agent/ai_financial_coach_agent.py index 43b4f6c..42d93d2 100644 --- a/ai_agent_tutorials/ai_financial_coach_agent/ai_financial_coach_agent.py +++ b/ai_agent_tutorials/ai_financial_coach_agent/ai_financial_coach_agent.py @@ -2,7 +2,7 @@ import streamlit as st import pandas as pd import plotly.express as px import plotly.graph_objects as go -from typing import Dict, List, Optional, Tuple, Any, AsyncGenerator +from typing import Dict, List, Optional, Tuple, Any import os import asyncio from datetime import datetime @@ -10,6 +10,8 @@ from dotenv import load_dotenv import json import logging from pydantic import BaseModel, Field +import csv +from io import StringIO from google.adk.agents import LlmAgent, SequentialAgent, BaseAgent from google.adk.agents.invocation_context import InvocationContext @@ -540,145 +542,456 @@ def display_debt_reduction(plan: Dict[str, Any]): if "impact" in rec: st.markdown(f"_Impact: {rec['impact']}_") -def main(): - st.set_page_config(page_title="AI Personal Finance Coach", layout="wide") +def parse_csv_transactions(file_content) -> List[Dict[str, Any]]: + """Parse CSV file content into a list of transactions""" + try: + # Read CSV content + df = pd.read_csv(StringIO(file_content.decode('utf-8'))) + + # Validate required columns + required_columns = ['Date', 'Category', 'Amount'] + missing_columns = [col for col in required_columns if col not in df.columns] + + if missing_columns: + raise ValueError(f"Missing required columns: {', '.join(missing_columns)}") + + # Convert date strings to datetime and then to string format YYYY-MM-DD + df['Date'] = pd.to_datetime(df['Date']).dt.strftime('%Y-%m-%d') + + # Convert amount strings to float, handling currency symbols and commas + df['Amount'] = df['Amount'].replace('[\$,]', '', regex=True).astype(float) + + # Group by category and calculate totals + category_totals = df.groupby('Category')['Amount'].sum().reset_index() + + # Convert to list of dictionaries + transactions = df.to_dict('records') + + return { + 'transactions': transactions, + 'category_totals': category_totals.to_dict('records') + } + except Exception as e: + raise ValueError(f"Error parsing CSV file: {str(e)}") + +def validate_csv_format(file) -> bool: + """Validate CSV file format and content""" + try: + content = file.read().decode('utf-8') + dialect = csv.Sniffer().sniff(content) + has_header = csv.Sniffer().has_header(content) + file.seek(0) # Reset file pointer + + if not has_header: + return False, "CSV file must have headers" + + df = pd.read_csv(StringIO(content)) + required_columns = ['Date', 'Category', 'Amount'] + missing_columns = [col for col in required_columns if col not in df.columns] + + if missing_columns: + return False, f"Missing required columns: {', '.join(missing_columns)}" + + # Validate date format + try: + pd.to_datetime(df['Date']) + except: + return False, "Invalid date format in Date column" + + # Validate amount format (should be numeric after removing currency symbols) + try: + df['Amount'].replace('[\$,]', '', regex=True).astype(float) + except: + return False, "Invalid amount format in Amount column" + + return True, "CSV format is valid" + except Exception as e: + return False, f"Invalid CSV format: {str(e)}" + +def display_csv_preview(df: pd.DataFrame): + """Display a preview of the CSV data with basic statistics""" + st.subheader("CSV Data Preview") - # Sidebar with API key info + # Show basic statistics + total_transactions = len(df) + total_amount = df['Amount'].sum() + + # Convert dates for display + df_dates = pd.to_datetime(df['Date']) + date_range = f"{df_dates.min().strftime('%Y-%m-%d')} to {df_dates.max().strftime('%Y-%m-%d')}" + + col1, col2, col3 = st.columns(3) + with col1: + st.metric("Total Transactions", total_transactions) + with col2: + st.metric("Total Amount", f"${total_amount:,.2f}") + with col3: + st.metric("Date Range", date_range) + + # Show category breakdown + st.subheader("Spending by Category") + category_totals = df.groupby('Category')['Amount'].agg(['sum', 'count']).reset_index() + category_totals.columns = ['Category', 'Total Amount', 'Transaction Count'] + st.dataframe(category_totals) + + # Show sample transactions + st.subheader("Sample Transactions") + st.dataframe(df.head()) + +def main(): + st.set_page_config( + page_title="AI Financial Coach with Google ADK", + layout="wide", + initial_sidebar_state="expanded" + ) + + # Sidebar with API key info and CSV template with st.sidebar: + st.title("🔑 Setup & Templates") st.info("📝 Please ensure you have your Gemini API key in the .env file:\n```\nGOOGLE_API_KEY=your_api_key_here\n```") - st.caption("This application uses Google's Gemini AI to provide personalized financial advice.") + st.caption("This application uses Google's ADK (Agent Development Kit) and Gemini AI to provide personalized financial advice.") + + st.divider() + + # Add CSV template download + st.subheader("📊 CSV Template") + st.markdown(""" + Download the template CSV file with the required format: + - Date (YYYY-MM-DD) + - Category + - Amount (numeric) + """) + + # Create sample CSV content + sample_csv = """Date,Category,Amount +2024-01-01,Housing,1200.00 +2024-01-02,Food,150.50 +2024-01-03,Transportation,45.00""" + + st.download_button( + label="đŸ“Ĩ Download CSV Template", + data=sample_csv, + file_name="expense_template.csv", + mime="text/csv" + ) if not GEMINI_API_KEY: - st.error("GOOGLE_API_KEY not found in environment variables. Please add it to your .env file.") + st.error("🔑 GOOGLE_API_KEY not found in environment variables. Please add it to your .env file.") return - st.title("📊 AI Personal Finance Coach") - st.subheader("Get personalized financial advice from AI agents") - st.info("This tool analyzes your financial data and provides tailored recommendations for budgeting, savings, and debt management.") - st.markdown("---") + # Main content + st.title("📊 AI Financial Coach with Google ADK") + st.caption("Powered by Google's Agent Development Kit (ADK) and Gemini AI") + st.info("This tool analyzes your financial data and provides tailored recommendations for budgeting, savings, and debt management using multiple specialized AI agents.") + st.divider() - st.header("Step 1: Enter Your Financial Information") - st.caption("All data is processed locally and not stored anywhere.") + # Create tabs for different sections + input_tab, about_tab = st.tabs(["đŸ’ŧ Financial Information", "â„šī¸ About"]) - col1, col2 = st.columns(2) - - with col1: - st.subheader("Income & Dependants") - monthly_income = st.number_input("Monthly Income ($)", min_value=0.0, step=100.0, value=3000.0, key="income") - dependants = st.number_input("Number of Dependants", min_value=0, step=1, value=0, key="dependants") - - with col2: - st.subheader("Expense Data") - expense_option = st.radio( - "How do you want to enter expenses?", - ("Upload CSV Transactions", "Enter Manually"), - key="expense_option" - ) + with input_tab: + st.header("Enter Your Financial Information") + st.caption("All data is processed locally and not stored anywhere.") - transaction_file = None - manual_expenses = {} - use_manual_expenses = False - transactions_df = None + # Income and Dependants section in a container + with st.container(): + st.subheader("💰 Income & Household") + income_col, dependants_col = st.columns([2, 1]) + with income_col: + monthly_income = st.number_input( + "Monthly Income ($)", + min_value=0.0, + step=100.0, + value=3000.0, + key="income", + help="Enter your total monthly income after taxes" + ) + with dependants_col: + dependants = st.number_input( + "Number of Dependants", + min_value=0, + step=1, + value=0, + key="dependants", + help="Include all dependants in your household" + ) + + st.divider() + + # Expenses section + with st.container(): + st.subheader("đŸ’ŗ Expenses") + expense_option = st.radio( + "How would you like to enter your expenses?", + ("📤 Upload CSV Transactions", "âœī¸ Enter Manually"), + key="expense_option", + horizontal=True + ) + + transaction_file = None + manual_expenses = {} + use_manual_expenses = False + transactions_df = None - if expense_option == "Upload CSV Transactions": - st.write("Upload a CSV with columns: Date, Category, Amount") - transaction_file = st.file_uploader("Upload CSV of transactions", type=["csv"], key="transaction_file") - if transaction_file is not None: + if expense_option == "📤 Upload CSV Transactions": + col1, col2 = st.columns([2, 1]) + with col1: + st.markdown(""" + #### Upload your transaction data + Your CSV file should have these columns: + - 📅 Date (YYYY-MM-DD) + - 📝 Category + - 💲 Amount + """) + + transaction_file = st.file_uploader( + "Choose your CSV file", + type=["csv"], + key="transaction_file", + help="Upload a CSV file containing your transactions" + ) + + if transaction_file is not None: + # Validate CSV format + is_valid, message = validate_csv_format(transaction_file) + + if is_valid: + try: + # Parse CSV content + transaction_file.seek(0) + file_content = transaction_file.read() + parsed_data = parse_csv_transactions(file_content) + + # Create DataFrame + transactions_df = pd.DataFrame(parsed_data['transactions']) + + # Display preview + display_csv_preview(transactions_df) + + st.success("✅ Transaction file uploaded and validated successfully!") + except Exception as e: + st.error(f"❌ Error processing CSV file: {str(e)}") + transactions_df = None + else: + st.error(message) + transactions_df = None + else: + use_manual_expenses = True + st.markdown("#### Enter your monthly expenses by category") + + # Define expense categories with emojis + categories = [ + ("🏠 Housing", "Housing"), + ("🔌 Utilities", "Utilities"), + ("đŸŊī¸ Food", "Food"), + ("🚗 Transportation", "Transportation"), + ("đŸĨ Healthcare", "Healthcare"), + ("🎭 Entertainment", "Entertainment"), + ("👤 Personal", "Personal"), + ("💰 Savings", "Savings"), + ("đŸ“Ļ Other", "Other") + ] + + # Create three columns for better layout + col1, col2, col3 = st.columns(3) + cols = [col1, col2, col3] + + # Distribute categories across columns + for i, (emoji_cat, cat) in enumerate(categories): + with cols[i % 3]: + manual_expenses[cat] = st.number_input( + emoji_cat, + min_value=0.0, + step=50.0, + value=0.0, + key=f"manual_{cat}", + help=f"Enter your monthly {cat.lower()} expenses" + ) + + if any(manual_expenses.values()): + st.markdown("#### 📊 Summary of Entered Expenses") + manual_df_disp = pd.DataFrame({ + 'Category': list(manual_expenses.keys()), + 'Amount': list(manual_expenses.values()) + }) + manual_df_disp = manual_df_disp[manual_df_disp['Amount'] > 0] + if not manual_df_disp.empty: + col1, col2 = st.columns([2, 1]) + with col1: + st.dataframe( + manual_df_disp, + column_config={ + "Category": "Category", + "Amount": st.column_config.NumberColumn( + "Amount", + format="$%.2f" + ) + }, + hide_index=True + ) + with col2: + st.metric( + "Total Monthly Expenses", + f"${manual_df_disp['Amount'].sum():,.2f}" + ) + + st.divider() + + # Debt Information section + with st.container(): + st.subheader("đŸĻ Debt Information") + st.info("Enter your debts to get personalized payoff strategies using both avalanche and snowball methods.") + + num_debts = st.number_input( + "How many debts do you have?", + min_value=0, + max_value=10, + step=1, + value=0, + key="num_debts" + ) + + debts = [] + if num_debts > 0: + # Create columns for debts + cols = st.columns(min(num_debts, 3)) # Max 3 columns per row + for i in range(num_debts): + col_idx = i % 3 + with cols[col_idx]: + st.markdown(f"##### Debt #{i+1}") + debt_name = st.text_input( + "Name", + value=f"Debt {i+1}", + key=f"debt_name_{i}", + help="Enter a name for this debt (e.g., Credit Card, Student Loan)" + ) + debt_amount = st.number_input( + "Amount ($)", + min_value=0.01, + step=100.0, + value=1000.0, + key=f"debt_amount_{i}", + help="Enter the current balance of this debt" + ) + interest_rate = st.number_input( + "Interest Rate (%)", + min_value=0.0, + max_value=100.0, + step=0.1, + value=5.0, + key=f"debt_rate_{i}", + help="Enter the annual interest rate" + ) + min_payment = st.number_input( + "Minimum Payment ($)", + min_value=0.0, + step=10.0, + value=50.0, + key=f"debt_min_payment_{i}", + help="Enter the minimum monthly payment required" + ) + + debts.append({ + "name": debt_name, + "amount": debt_amount, + "interest_rate": interest_rate, + "min_payment": min_payment + }) + + if col_idx == 2 or i == num_debts - 1: # Add spacing after every 3 debts or last debt + st.markdown("---") + + st.divider() + + # Analysis button + col1, col2, col3 = st.columns([1, 2, 1]) + with col2: + analyze_button = st.button( + "🔄 Analyze My Finances", + key="analyze_button", + use_container_width=True, + help="Click to get your personalized financial analysis" + ) + + if analyze_button: + if expense_option == "Upload CSV Transactions" and transactions_df is None: + st.error("Please upload a valid transaction CSV file or choose manual entry.") + return + if use_manual_expenses and not any(manual_expenses.values()): + st.warning("No manual expenses entered. Analysis might be limited.") + + st.header("Financial Analysis Results") + with st.spinner("🤖 AI agents are analyzing your financial data..."): + financial_data = { + "monthly_income": monthly_income, + "dependants": dependants, + "transactions": transactions_df.to_dict('records') if transactions_df is not None else None, + "manual_expenses": manual_expenses if use_manual_expenses else None, + "debts": debts + } + + finance_system = FinanceAdvisorSystem() + try: - transactions_df = pd.read_csv(transaction_file) - st.success("Transaction file uploaded successfully!") + results = asyncio.run(finance_system.analyze_finances(financial_data)) + + tabs = st.tabs(["💰 Budget Analysis", "📈 Savings Strategy", "đŸ’ŗ Debt Reduction"]) + + with tabs[0]: + st.subheader("Budget Analysis") + if "budget_analysis" in results and results["budget_analysis"]: + display_budget_analysis(results["budget_analysis"]) + else: + st.write("No budget analysis available.") + + with tabs[1]: + st.subheader("Savings Strategy") + if "savings_strategy" in results and results["savings_strategy"]: + display_savings_strategy(results["savings_strategy"]) + else: + st.write("No savings strategy available.") + + with tabs[2]: + st.subheader("Debt Reduction Plan") + if "debt_reduction" in results and results["debt_reduction"]: + display_debt_reduction(results["debt_reduction"]) + else: + st.write("No debt reduction plan available.") except Exception as e: - st.error(f"Error reading CSV: {e}") - transactions_df = None - else: - use_manual_expenses = True - st.write("Enter monthly expenses by category:") - categories = ["Housing", "Utilities", "Food", "Transportation", "Healthcare", - "Entertainment", "Personal", "Savings", "Other"] - exp_col1, exp_col2 = st.columns(2) - for i, category in enumerate(categories): - col = exp_col1 if i < (len(categories) + 1) // 2 else exp_col2 - manual_expenses[category] = col.number_input(f"{category} ($)", min_value=0.0, step=50.0, value=0.0, key=f"manual_{category}") - if any(manual_expenses.values()): - st.write("Entered Manual Expenses:") - manual_df_disp = pd.DataFrame({ - 'Category': list(manual_expenses.keys()), - 'Amount': list(manual_expenses.values()) - }) - st.dataframe(manual_df_disp[manual_df_disp['Amount'] > 0]) - - st.subheader("Debt Information") - st.info("Enter your debts to get personalized payoff strategies.") - num_debts = st.number_input("Number of Debts", min_value=0, max_value=10, step=1, value=0, key="num_debts") + st.error(f"An error occurred during analysis: {str(e)}") - debts = [] - if num_debts > 0: - debt_cols = st.columns(num_debts) - for i in range(num_debts): - with debt_cols[i]: - st.markdown(f"**Debt #{i+1}**") - debt_name = st.text_input(f"Name", value=f"Debt {i+1}", key=f"debt_name_{i}") - debt_amount = st.number_input(f"Amount $", min_value=0.01, step=100.0, value=1000.0, key=f"debt_amount_{i}") - interest_rate = st.number_input(f"Interest Rate (%)", min_value=0.0, max_value=100.0, step=0.1, value=5.0, key=f"debt_rate_{i}") - min_payment = st.number_input(f"Min. Payment $", min_value=0.0, step=10.0, value=50.0, key=f"debt_min_payment_{i}") - - debts.append({ - "name": debt_name, - "amount": debt_amount, - "interest_rate": interest_rate, - "min_payment": min_payment - }) - - st.markdown("---") - analyze_button = st.button("Analyze My Finances", key="analyze_button") - st.markdown("---") - - if analyze_button: - if expense_option == "Upload CSV Transactions" and transactions_df is None: - st.error("Please upload a valid transaction CSV file or choose manual entry.") - return - if use_manual_expenses and not any(manual_expenses.values()): - st.warning("No manual expenses entered. Analysis might be limited.") - - st.header("Step 2: Financial Analysis Results") - with st.spinner("AI agents are analyzing your financial data..."): - financial_data = { - "monthly_income": monthly_income, - "dependants": dependants, - "transactions": transactions_df.to_dict('records') if transactions_df is not None else None, - "manual_expenses": manual_expenses if use_manual_expenses else None, - "debts": debts - } - - finance_system = FinanceAdvisorSystem() - - try: - results = asyncio.run(finance_system.analyze_finances(financial_data)) - - tabs = st.tabs(["💰 Budget Analysis", "📈 Savings Strategy", "đŸ’ŗ Debt Reduction"]) - - with tabs[0]: - st.subheader("Budget Analysis") - if "budget_analysis" in results and results["budget_analysis"]: - display_budget_analysis(results["budget_analysis"]) - else: - st.write("No budget analysis available.") - - with tabs[1]: - st.subheader("Savings Strategy") - if "savings_strategy" in results and results["savings_strategy"]: - display_savings_strategy(results["savings_strategy"]) - else: - st.write("No savings strategy available.") - - with tabs[2]: - st.subheader("Debt Reduction Plan") - if "debt_reduction" in results and results["debt_reduction"]: - display_debt_reduction(results["debt_reduction"]) - else: - st.write("No debt reduction plan available.") - except Exception as e: - st.error(f"An error occurred during analysis: {str(e)}") + with about_tab: + st.markdown(""" + ### About AI Financial Coach + + This application uses Google's Agent Development Kit (ADK) to provide comprehensive financial analysis and advice through multiple specialized AI agents: + + 1. **🔍 Budget Analysis Agent** + - Analyzes spending patterns + - Identifies areas for cost reduction + - Provides actionable recommendations + + 2. **💰 Savings Strategy Agent** + - Creates personalized savings plans + - Calculates emergency fund requirements + - Suggests automation techniques + + 3. **đŸ’ŗ Debt Reduction Agent** + - Develops optimal debt payoff strategies + - Compares different repayment methods + - Provides actionable debt reduction tips + + ### Privacy & Security + + - All data is processed locally + - No financial information is stored or transmitted + - Secure API communication with Google's services + + ### Need Help? + + For support or questions: + - Check the [documentation](https://github.com/Shubhamsaboo/awesome-llm-apps) + - Report issues on [GitHub](https://github.com/Shubhamsaboo/awesome-llm-apps/issues) + """) if __name__ == "__main__": main() \ No newline at end of file diff --git a/ai_agent_tutorials/ai_financial_coach_agent/requirements.txt b/ai_agent_tutorials/ai_financial_coach_agent/requirements.txt index b642de4..2f6d591 100644 --- a/ai_agent_tutorials/ai_financial_coach_agent/requirements.txt +++ b/ai_agent_tutorials/ai_financial_coach_agent/requirements.txt @@ -1,5 +1,5 @@ -google-adk==0.4.0 -streamlit==1.31.0 +google-adk==0.1.0 +streamlit pandas==2.1.1 matplotlib==3.8.0 numpy==1.26.0