import streamlit as st import pandas as pd import numpy as np import plotly.express as px import plotly.graph_objects as go from datetime import datetime, timedelta, date import requests import google.generativeai as genai # Constants ENGINEER_SALARY = 10000 # Monthly cost per engineer ($120K/year) # Initialize session state variables if 'startups' not in st.session_state: st.session_state.startups = {} # Dictionary to store startup data if 'current_startup' not in st.session_state: st.session_state.current_startup = None # Currently selected startup if 'current_page' not in st.session_state: st.session_state.current_page = 'upload' # Default page if 'insights_cache' not in st.session_state: st.session_state.insights_cache = {} if 'chat_history' not in st.session_state: st.session_state.chat_history = [ {"role": "assistant", "content": "Hi! I'm your AI financial advisor. How can I help with your startup's finances?"} ] # Setup page config and styling st.set_page_config(page_title="StartupFinancePilot", page_icon="💰", layout="wide") # Apply custom styling st.markdown(""" """, unsafe_allow_html=True) # AI Integration Functions def initialize_gemini(): """Initialize Google's Gemini AI with API key""" try: api_key = st.secrets.get("GEMINI_API_KEY", None) if api_key: genai.configure(api_key=api_key) return True else: st.warning("Gemini API key not found. Using simulated responses.") return False except Exception as e: st.error(f"Failed to initialize Gemini AI: {e}") return False def generate_ai_response(prompt, simulate=False): """Generate text using Google's Gemini AI""" if simulate: return "AI response simulation: Based on your financial data, I recommend focusing on extending runway, accelerating revenue growth, and preparing for your next funding round." else: try: model = genai.GenerativeModel('gemini-pro') response = model.generate_content(prompt) return response.text except Exception as e: st.error(f"Error generating AI response: {e}") return "Sorry, I couldn't generate a response at this time." def autoplay_audio(audio_content): """Generate HTML with audio player that auto-plays""" b64 = base64.b64encode(audio_content).decode() md = f""" """ st.markdown(md, unsafe_allow_html=True) def generate_voice_response(text, simulate=False): """Generate voice response using ElevenLabs API""" if simulate: return None else: try: api_key = st.secrets.get("ELEVENLABS_API_KEY", None) if not api_key: return None url = "https://api.elevenlabs.io/v1/text-to-speech/21m00Tcm4TlvDq8ikWAM" # Rachel voice headers = { "Accept": "audio/mpeg", "Content-Type": "application/json", "xi-api-key": api_key } data = { "text": text, "model_id": "eleven_monolingual_v1", "voice_settings": { "stability": 0.5, "similarity_boost": 0.5 } } response = requests.post(url, json=data, headers=headers) if response.status_code == 200: return response.content else: st.error(f"Error with ElevenLabs API: {response.status_code}") return None except Exception as e: st.error(f"Error generating voice response: {e}") return None # Utility Functions def switch_page(page_name): """Function to switch between pages""" st.session_state.current_page = page_name st.rerun() def calculate_runway(cash, burn_rate, revenue, growth_rate, months=24): """Calculate runway based on cash, burn, revenue and growth""" current_date = datetime.now() date_range = [current_date + timedelta(days=30*i) for i in range(months)] cash_flow = [] monthly_revenue = revenue for i in range(months): net_burn = burn_rate - monthly_revenue cash_flow.append(net_burn) monthly_revenue *= (1 + growth_rate) df = pd.DataFrame({ 'Net_Burn': cash_flow, 'Cumulative_Cash': [cash - sum(cash_flow[:i+1]) for i in range(len(cash_flow))] }, index=date_range) negative_cash = df[df['Cumulative_Cash'] < 0] runway_months = (negative_cash.index[0] - current_date).days // 30 if len(negative_cash) > 0 else months return runway_months, df def simulate_decision(cash, burn_rate, revenue, growth_rate, additional_expenses, new_hires, marketing_increase, growth_impact): """Simulate the financial impact of a business decision""" current_runway, current_df = calculate_runway(cash, burn_rate, revenue, growth_rate) new_burn_rate = burn_rate + additional_expenses + (new_hires * ENGINEER_SALARY) + marketing_increase new_growth_rate = growth_rate + growth_impact new_runway, new_df = calculate_runway(cash, new_burn_rate, revenue, new_growth_rate) return current_runway, new_runway, current_df, new_df def detect_suspicious_transactions(transactions_df): """AI-enhanced suspicious transaction detection""" df = transactions_df.copy() # Define thresholds for each category category_thresholds = { "Travel": 3000, "Marketing": 10000, "Office": 7000, "Software": 6000, "Consulting": 5000, "Legal": 6000 } suspicious_terms = ['luxury', 'cruise', 'premium', 'personal', 'gift'] # Add analysis columns df['Suspicious'] = False df['Reason'] = "" df['Risk_Score'] = 0 for idx, row in df.iterrows(): reasons = [] risk_score = 0 # Check category thresholds if row['Category'] in category_thresholds and row['Amount'] > category_thresholds[row['Category']]: reasons.append(f"Amount exceeds typical spending for {row['Category']}") risk_score += 30 # Check for suspicious terms for field in ['Vendor', 'Description']: if any(term in str(row[field]).lower() for term in suspicious_terms): reasons.append(f"{field} contains suspicious term") risk_score += 20 # Check for round amounts if row['Amount'] % 1000 == 0 and row['Amount'] > 3000: reasons.append(f"Suspiciously round amount") risk_score += 15 # Mark as suspicious if risk score is high enough if risk_score >= 30: df.at[idx, 'Suspicious'] = True df.at[idx, 'Reason'] = "; ".join(reasons) df.at[idx, 'Risk_Score'] = risk_score return df.sort_values(by='Risk_Score', ascending=False) def parse_csv_to_df(file): """Parse uploaded CSV file to DataFrame""" try: df = pd.read_csv(file) return df, None except Exception as e: return None, f"Error parsing CSV: {e}" # Navigation def create_sidebar(): with st.sidebar: st.markdown("""
AI-powered financial assistant for startups
Upload CSV files to get started
", unsafe_allow_html=True) with st.expander("Upload Instructions", expanded=False): st.markdown(""" ### How to Upload Your Startup Data You can upload three types of files: 1. **Company Profile** - A CSV with basic information about your startup including: - name, stage, founded, employees, last_funding, cash, burn_rate, revenue, growth_rate 2. **Cash Flow Data** - A CSV with monthly cash flow data with columns: - Month, Revenue, Payroll, Marketing, Office, Software, Travel, Legal, Misc 3. **Transaction Data** - A CSV with transaction details: - Date, Category, Vendor, Amount, Description, Flag """) startup_name = st.text_input("Startup Name", value="My Startup") col1, col2, col3 = st.columns(3) with col1: profile_file = st.file_uploader("Upload Company Profile (CSV)", type=['csv']) with col2: cash_flow_file = st.file_uploader("Upload Cash Flow Data (CSV)", type=['csv']) with col3: transactions_file = st.file_uploader("Upload Transactions Data (CSV)", type=['csv']) # Process the files if uploaded if st.button("Process Data"): # Initialize with default values startup_data = { "name": startup_name, "stage": "Seed", "founded": "12 months ago", "employees": 5, "last_funding": "Not specified", "cash": 100000, "burn_rate": 20000, "revenue": 5000, "growth_rate": 0.05 } cash_flow_df = None transactions_df = None # Parse company profile if profile_file: profile_df, error = parse_csv_to_df(profile_file) if error: st.error(error) elif len(profile_df) > 0: startup_data.update(profile_df.iloc[0].to_dict()) st.success(f"Successfully loaded company profile") # Parse cash flow data if cash_flow_file: cash_flow_df, error = parse_csv_to_df(cash_flow_file) if error: st.error(error) else: if "Total_Expenses" not in cash_flow_df.columns: expense_columns = [col for col in cash_flow_df.columns if col not in ["Month", "Revenue", "Total_Expenses", "Net_Burn"]] cash_flow_df["Total_Expenses"] = cash_flow_df[expense_columns].sum(axis=1) if "Net_Burn" not in cash_flow_df.columns: cash_flow_df["Net_Burn"] = cash_flow_df["Total_Expenses"] - cash_flow_df["Revenue"] st.success("Successfully loaded cash flow data") # Parse transactions data if transactions_file: transactions_df, error = parse_csv_to_df(transactions_file) if error: st.error(error) else: # Ensure transactions data has required columns required_columns = ["Date", "Category", "Vendor", "Amount", "Description"] if all(col in transactions_df.columns for col in required_columns): if "Flag" not in transactions_df.columns: transactions_df["Flag"] = "Normal" st.success("Successfully loaded transactions data") else: st.error("Transactions file is missing required columns") # Save to session state if we have at least some data if profile_file: # Store in session state st.session_state.startups[startup_data['name']] = { 'profile': startup_data, 'cash_flow': cash_flow_df, 'transactions': transactions_df } # Set as current startup st.session_state.current_startup = startup_data['name'] st.success(f"Successfully added {startup_data['name']} to your startups") switch_page('dashboard') else: st.error("Please upload at least a company profile file") def render_financial_dashboard(): """Render the AI-powered financial dashboard page""" if not st.session_state.current_startup or st.session_state.current_startup not in st.session_state.startups: st.warning("No startup selected. Please upload data first.") render_upload_page() return # Get the selected startup data startup_data = st.session_state.startups[st.session_state.current_startup]['profile'] cash_flow_df = st.session_state.startups[st.session_state.current_startup]['cash_flow'] st.markdown("Current Cash
${startup_data['cash']:,}
Monthly Burn
${startup_data['burn_rate']:,}
Monthly Revenue
${startup_data['revenue']:,}
Runway
{runway_months} months
Test the financial impact of business decisions
", unsafe_allow_html=True) # Decision input form with st.form("decision_form"): st.subheader("Scenario Parameters") col1, col2 = st.columns(2) with col1: new_hires = st.number_input("New Engineering Hires", min_value=0, max_value=10, value=0) st.caption(f"Monthly Cost: ${new_hires * ENGINEER_SALARY:,}") new_marketing = st.number_input("Additional Monthly Marketing Budget", min_value=0, max_value=50000, value=0, step=1000) with col2: other_expenses = st.number_input("Other Additional Monthly Expenses", min_value=0, max_value=50000, value=0, step=1000) growth_impact = st.slider("Estimated Impact on Monthly Growth Rate", min_value=0.0, max_value=0.10, value=0.0, step=0.01, format="%.2f") question = st.text_area("Describe your decision scenario", height=100) decision_summary = f""" - {new_hires} new engineers: ${new_hires * ENGINEER_SALARY:,}/month - Marketing increase: ${new_marketing:,}/month - Other expenses: ${other_expenses:,}/month - Total additional burn: ${new_hires * ENGINEER_SALARY + new_marketing + other_expenses:,}/month - Growth impact: +{growth_impact * 100:.1f}% monthly growth """ st.markdown(f"**Decision Summary:**\n{decision_summary}") submitted = st.form_submit_button("Simulate Decision") if submitted: # Calculate current and new runway current_runway, new_runway, current_df, new_df = simulate_decision( startup_data['cash'], startup_data['burn_rate'], startup_data['revenue'], startup_data['growth_rate'], other_expenses, new_hires, new_marketing, growth_impact ) # Display results st.markdown("{st.session_state.insights_cache[analysis_key]}
", unsafe_allow_html=True) st.markdown("AI-powered fraud detection and spending analysis
", unsafe_allow_html=True) if transactions_df is None: st.warning("No transaction data available. Please upload transaction data.") return # Process transactions to detect suspicious ones processed_df = detect_suspicious_transactions(transactions_df) # Summary metrics total_transactions = len(processed_df) suspicious_transactions = processed_df[processed_df['Suspicious']].copy() suspicious_count = len(suspicious_transactions) suspicious_amount = suspicious_transactions['Amount'].sum() if not suspicious_transactions.empty else 0 total_amount = processed_df['Amount'].sum() col1, col2 = st.columns(2) with col1: st.markdown(f"""Total Transactions
{total_transactions}
Flagged Transactions
{suspicious_count} ({flagged_percent:.1f}%)
{st.session_state.insights_cache[fraud_key]}
", unsafe_allow_html=True) st.markdown("