Upload 15 files
Browse files- readme.md +131 -0
- requirements-txt.txt +6 -0
- requirements.txt +15 -0
- src/__init__ .py +3 -0
- src/app.py +154 -0
- src/env-template.txt +2 -0
- src/pages/__init__.py +5 -0
- src/pages/dashboard-page.py +390 -0
- src/pages/dashboard-pages-init.py +2 -0
- src/pages/decision-simulator.py +321 -0
- src/pages/financial-advisor.py +210 -0
- src/pages/fund-monitoring.py +334 -0
- src/utils/__init__.py +3 -0
- src/utils/ai-helpers.py +66 -0
- src/utils/data-processing.py +118 -0
readme.md
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# StartupFinancePilot - AI-Powered Financial Assistant for Startups
|
2 |
+
|
3 |
+
## Overview
|
4 |
+
|
5 |
+
StartupFinancePilot is an advanced AI-powered financial assistant that helps startup founders make better financial decisions, monitor spending, and optimize their runway. The application provides five main features:
|
6 |
+
|
7 |
+
1. **AI-Enhanced Financial Dashboard**: Visualize your startup's financial health with AI insights and recommendations
|
8 |
+
2. **Decision Simulator with AI Analysis**: Test business decisions and get AI-powered impact analysis before implementation
|
9 |
+
3. **Intelligent Fund Monitoring**: AI-powered detection of suspicious transactions and spending pattern analysis
|
10 |
+
4. **Voice-Enabled AI Financial Advisor**: Get strategic guidance through a conversational interface with voice support
|
11 |
+
5. **AI Advisor Booking System**: Schedule dedicated sessions with AI financial experts for deeper analysis
|
12 |
+
|
13 |
+
## How AI Powers StartupFinancePilot
|
14 |
+
|
15 |
+
StartupFinancePilot leverages advanced AI technologies to revolutionize startup financial management:
|
16 |
+
|
17 |
+
### 1. Google Gemini AI Integration
|
18 |
+
|
19 |
+
At the core of StartupFinancePilot is Google's Gemini AI, a powerful large language model that:
|
20 |
+
|
21 |
+
- Analyzes financial data to identify trends, anomalies, and opportunities
|
22 |
+
- Generates tailored recommendations based on your startup's specific situation
|
23 |
+
- Provides natural language explanations of complex financial concepts
|
24 |
+
- Creates personalized strategies for runway extension and fundraising
|
25 |
+
|
26 |
+
### 2. ElevenLabs Voice Technology
|
27 |
+
|
28 |
+
The AI Financial Advisor feature uses ElevenLabs' voice synthesis technology to:
|
29 |
+
|
30 |
+
- Convert AI-generated financial advice into natural-sounding voice responses
|
31 |
+
- Provide a more engaging and accessible way to receive financial guidance
|
32 |
+
- Enable hands-free advisory sessions during busy founder days
|
33 |
+
|
34 |
+
### 3. AI-Powered Fraud Detection
|
35 |
+
|
36 |
+
Our proprietary AI algorithms for fraud detection:
|
37 |
+
|
38 |
+
- Automatically flag suspicious transactions using multiple risk factors
|
39 |
+
- Assign risk scores to transactions based on patterns and anomalies
|
40 |
+
- Learn from your spending patterns to improve detection accuracy over time
|
41 |
+
- Prevent fund misuse before it occurs
|
42 |
+
|
43 |
+
### 4. Financial Modeling AI
|
44 |
+
|
45 |
+
The Decision Simulator uses AI financial modeling to:
|
46 |
+
|
47 |
+
- Predict the impact of business decisions on your runway and finances
|
48 |
+
- Generate multiple scenarios based on different variables
|
49 |
+
- Recommend the optimal timing and scope for major decisions
|
50 |
+
- Assess risk levels and potential ROI for different options
|
51 |
+
|
52 |
+
## Key Features
|
53 |
+
|
54 |
+
### Financial Dashboard
|
55 |
+
|
56 |
+
- AI-generated insights about your financial health
|
57 |
+
- Interactive visualizations of runway, cash flow, and burn rate
|
58 |
+
- Expense breakdown with AI-powered optimization recommendations
|
59 |
+
- Fundraising readiness assessment based on your metrics
|
60 |
+
|
61 |
+
### Decision Simulator
|
62 |
+
|
63 |
+
- Test the impact of hiring, marketing, and other decisions before implementation
|
64 |
+
- AI analysis of each decision with specific recommendations
|
65 |
+
- Component-level impact visualization to understand effects
|
66 |
+
- Risk assessment for different scenarios
|
67 |
+
|
68 |
+
### Fund Monitoring
|
69 |
+
|
70 |
+
- AI-powered detection of suspicious transactions
|
71 |
+
- Risk scoring for all spending activities
|
72 |
+
- Pattern recognition to identify concerning trends
|
73 |
+
- AI-recommended spending controls and policies
|
74 |
+
|
75 |
+
### AI Financial Advisor
|
76 |
+
|
77 |
+
- Natural language chat interface for financial questions
|
78 |
+
- Voice-enabled responses for hands-free guidance
|
79 |
+
- Context-aware advice based on your financial situation
|
80 |
+
- Library of common financial questions with instant answers
|
81 |
+
|
82 |
+
### Book a Session
|
83 |
+
|
84 |
+
- Schedule dedicated AI advisory sessions for deeper analysis
|
85 |
+
- Multiple session types for different financial needs
|
86 |
+
- AI-generated pre-session analysis and post-session reports
|
87 |
+
- 30-day follow-up support for implementation guidance
|
88 |
+
|
89 |
+
## Technical Implementation
|
90 |
+
|
91 |
+
StartupFinancePilot is built using:
|
92 |
+
|
93 |
+
- Streamlit for the web interface
|
94 |
+
- Google's Gemini AI API for intelligent analysis and recommendations
|
95 |
+
- ElevenLabs API for voice synthesis
|
96 |
+
- Plotly for interactive data visualizations
|
97 |
+
- Pandas for data processing and analysis
|
98 |
+
|
99 |
+
## Getting Started
|
100 |
+
|
101 |
+
### Local Installation
|
102 |
+
|
103 |
+
1. Clone the repository
|
104 |
+
2. Install requirements: `pip install -r requirements.txt`
|
105 |
+
3. Set up environment variables:
|
106 |
+
- `GOOGLE_API_KEY`: Your Google API key for Gemini access
|
107 |
+
- `ELEVENLABS_API_KEY`: Your ElevenLabs API key for voice synthesis
|
108 |
+
4. Run the application: `streamlit run app.py`
|
109 |
+
|
110 |
+
### Hugging Face Deployment
|
111 |
+
|
112 |
+
This application is also deployed on Hugging Face Spaces and can be accessed directly through the web interface.
|
113 |
+
|
114 |
+
To enable all AI features when deploying to Hugging Face:
|
115 |
+
|
116 |
+
1. Go to the Hugging Face Space settings
|
117 |
+
2. Click on "Repository secrets"
|
118 |
+
3. Add secrets for `GOOGLE_API_KEY` and `ELEVENLABS_API_KEY`
|
119 |
+
|
120 |
+
## Data Privacy
|
121 |
+
|
122 |
+
This application uses sample data for demonstration purposes. In a production environment:
|
123 |
+
|
124 |
+
- All financial data remains private and secure
|
125 |
+
- No data is shared with third parties without explicit consent
|
126 |
+
- API calls are encrypted and secure
|
127 |
+
- No financial data is stored in model training datasets
|
128 |
+
|
129 |
+
## About
|
130 |
+
|
131 |
+
StartupFinancePilot was created to democratize access to high-quality financial guidance for startups. By leveraging AI, we provide enterprise-level financial intelligence at a fraction of the cost of traditional consultants.
|
requirements-txt.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit==1.24.0
|
2 |
+
google-generativeai==0.3.2
|
3 |
+
pandas==2.0.0
|
4 |
+
numpy==1.24.3
|
5 |
+
plotly==5.14.1
|
6 |
+
python-dotenv==1.0.0
|
requirements.txt
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Core dependencies
|
2 |
+
streamlit==1.28.0
|
3 |
+
pandas==2.0.3
|
4 |
+
numpy==1.24.3
|
5 |
+
plotly==5.18.0
|
6 |
+
python-dateutil==2.8.2
|
7 |
+
pillow==10.0.1
|
8 |
+
|
9 |
+
# AI and ML libraries
|
10 |
+
google-generativeai==0.3.2
|
11 |
+
# elevenlabs==0.2.24 # Uncomment when implementing voice synthesis
|
12 |
+
|
13 |
+
# Data processing
|
14 |
+
pytz==2023.3
|
15 |
+
openpyxl==3.1.2
|
src/__init__ .py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
# Import necessary modules for easy access
|
2 |
+
from . import utils
|
3 |
+
from . import pages
|
src/app.py
ADDED
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import os
|
3 |
+
from dotenv import load_dotenv
|
4 |
+
|
5 |
+
# Import local modules
|
6 |
+
from src.pages import dashboard, decision_simulator, fund_monitoring, financial_advisor
|
7 |
+
from src.utils.data_processing import (
|
8 |
+
generate_sample_startup_data,
|
9 |
+
generate_sample_cash_flow_data,
|
10 |
+
generate_sample_transactions_data
|
11 |
+
)
|
12 |
+
|
13 |
+
# Load environment variables
|
14 |
+
load_dotenv()
|
15 |
+
|
16 |
+
# Constants
|
17 |
+
DEFAULT_GROWTH_RATE = 0.08 # 8% monthly growth
|
18 |
+
DEFAULT_BURN_RATE = 85000 # $85,000 monthly burn
|
19 |
+
ENGINEER_SALARY = 10000 # $10,000 monthly cost per engineer ($120K/year)
|
20 |
+
|
21 |
+
def main():
|
22 |
+
"""
|
23 |
+
Main application entry point for Startup Finance Pilot
|
24 |
+
"""
|
25 |
+
# App configuration
|
26 |
+
st.set_page_config(
|
27 |
+
page_title="StartupFinancePilot",
|
28 |
+
page_icon="💰",
|
29 |
+
layout="wide",
|
30 |
+
initial_sidebar_state="expanded"
|
31 |
+
)
|
32 |
+
|
33 |
+
# Custom CSS (you might want to move this to a separate file in a larger project)
|
34 |
+
st.markdown("""
|
35 |
+
<style>
|
36 |
+
/* Your existing CSS styles from previous implementation */
|
37 |
+
.main-header { font-size: 2.5rem; color: #0066cc; }
|
38 |
+
.sub-header { font-size: 1.5rem; color: #5c5c5c; }
|
39 |
+
/* Add more styles as needed */
|
40 |
+
</style>
|
41 |
+
""", unsafe_allow_html=True)
|
42 |
+
|
43 |
+
# Initialize session state
|
44 |
+
if 'startups' not in st.session_state:
|
45 |
+
st.session_state.startups = {}
|
46 |
+
|
47 |
+
if 'current_startup' not in st.session_state:
|
48 |
+
st.session_state.current_startup = None
|
49 |
+
|
50 |
+
if 'current_page' not in st.session_state:
|
51 |
+
st.session_state.current_page = 'upload'
|
52 |
+
|
53 |
+
if 'insights_cache' not in st.session_state:
|
54 |
+
st.session_state.insights_cache = {}
|
55 |
+
|
56 |
+
# Add sample data for demonstration
|
57 |
+
sample_startup = generate_sample_startup_data()
|
58 |
+
st.session_state.startups[sample_startup['name']] = {
|
59 |
+
'profile': sample_startup,
|
60 |
+
'cash_flow': generate_sample_cash_flow_data(),
|
61 |
+
'transactions': generate_sample_transactions_data()
|
62 |
+
}
|
63 |
+
st.session_state.current_startup = sample_startup['name']
|
64 |
+
|
65 |
+
# Sidebar navigation
|
66 |
+
with st.sidebar:
|
67 |
+
st.title("💰 StartupFinancePilot")
|
68 |
+
st.write("AI-powered financial assistant for startups")
|
69 |
+
|
70 |
+
# Startup selector
|
71 |
+
if st.session_state.startups:
|
72 |
+
startup_names = list(st.session_state.startups.keys())
|
73 |
+
selected_startup = st.selectbox(
|
74 |
+
"Choose Startup",
|
75 |
+
startup_names,
|
76 |
+
index=startup_names.index(st.session_state.current_startup)
|
77 |
+
)
|
78 |
+
|
79 |
+
st.session_state.current_startup = selected_startup
|
80 |
+
|
81 |
+
# Show basic startup info
|
82 |
+
startup_data = st.session_state.startups[selected_startup]['profile']
|
83 |
+
st.markdown(f"""
|
84 |
+
**Stage:** {startup_data['stage']}
|
85 |
+
**Cash:** ${startup_data['cash']:,}
|
86 |
+
**Monthly Burn:** ${startup_data['burn_rate']:,}
|
87 |
+
**Monthly Revenue:** ${startup_data['revenue']:,}
|
88 |
+
""")
|
89 |
+
|
90 |
+
# Navigation buttons
|
91 |
+
st.markdown("<hr>", unsafe_allow_html=True)
|
92 |
+
|
93 |
+
page_options = {
|
94 |
+
"📊 Financial Dashboard": "dashboard",
|
95 |
+
"🔮 Decision Simulator": "simulator",
|
96 |
+
"🕵️ Fund Monitoring": "monitoring",
|
97 |
+
"🤖 AI Financial Advisor": "advisor"
|
98 |
+
}
|
99 |
+
|
100 |
+
for label, page_key in page_options.items():
|
101 |
+
if st.button(label, use_container_width=True):
|
102 |
+
st.session_state.current_page = page_key
|
103 |
+
st.experimental_rerun()
|
104 |
+
|
105 |
+
# Render the correct page
|
106 |
+
if st.session_state.current_page == 'dashboard':
|
107 |
+
dashboard.render_financial_dashboard(
|
108 |
+
st.session_state.startups[st.session_state.current_startup]['profile'],
|
109 |
+
st.session_state.startups[st.session_state.current_startup]['cash_flow']
|
110 |
+
)
|
111 |
+
elif st.session_state.current_page == 'simulator':
|
112 |
+
decision_simulator.render_decision_simulator(
|
113 |
+
st.session_state.startups[st.session_state.current_startup]['profile']
|
114 |
+
)
|
115 |
+
elif st.session_state.current_page == 'monitoring':
|
116 |
+
fund_monitoring.render_fund_monitoring(
|
117 |
+
st.session_state.startups[st.session_state.current_startup]['transactions']
|
118 |
+
)
|
119 |
+
elif st.session_state.current_page == 'advisor':
|
120 |
+
financial_advisor.render_ai_financial_advisor(
|
121 |
+
st.session_state.startups[st.session_state.current_startup]['profile']
|
122 |
+
)
|
123 |
+
|
124 |
+
def validate_gemini_api_key():
|
125 |
+
"""
|
126 |
+
Validate the Google Generative AI API key
|
127 |
+
|
128 |
+
Returns:
|
129 |
+
bool: True if API key is valid, False otherwise
|
130 |
+
"""
|
131 |
+
try:
|
132 |
+
import google.generativeai as genai
|
133 |
+
api_key = os.getenv('GOOGLE_API_KEY')
|
134 |
+
|
135 |
+
if not api_key:
|
136 |
+
st.error("🚨 Google API Key not found. Please set GOOGLE_API_KEY in your .env file.")
|
137 |
+
return False
|
138 |
+
|
139 |
+
genai.configure(api_key=api_key)
|
140 |
+
model = genai.GenerativeModel('gemini-pro')
|
141 |
+
|
142 |
+
# Try a simple test generation
|
143 |
+
test_response = model.generate_content("Hello, can you confirm the API is working?")
|
144 |
+
return True
|
145 |
+
except Exception as e:
|
146 |
+
st.error(f"🚨 Error validating API key: {e}")
|
147 |
+
return False
|
148 |
+
|
149 |
+
if __name__ == "__main__":
|
150 |
+
# Check API key before running
|
151 |
+
if validate_gemini_api_key():
|
152 |
+
main()
|
153 |
+
else:
|
154 |
+
st.warning("Please set up your Google Generative AI API key to use the application.")
|
src/env-template.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
# Google Generative AI API Key
|
2 |
+
GOOGLE_API_KEY=your_google_generative_ai_api_key_here
|
src/pages/__init__.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Import all page modules for easier access
|
2 |
+
from . import dashboard
|
3 |
+
from . import decision_simulator
|
4 |
+
from . import fund_monitoring
|
5 |
+
from . import financial_advisor
|
src/pages/dashboard-page.py
ADDED
@@ -0,0 +1,390 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import plotly.express as px
|
3 |
+
import plotly.graph_objs as go
|
4 |
+
import pandas as pd
|
5 |
+
from datetime import date
|
6 |
+
|
7 |
+
# Import local utilities
|
8 |
+
from ..utils.ai_helpers import generate_ai_response
|
9 |
+
from ..utils.data_processing import calculate_runway
|
10 |
+
|
11 |
+
def render_financial_dashboard(startup_data, cash_flow_df):
|
12 |
+
"""
|
13 |
+
Render the AI-powered financial dashboard page.
|
14 |
+
|
15 |
+
This dashboard uses AI to analyze financial data and provide actionable insights
|
16 |
+
to startup founders, helping them make better decisions about their runway,
|
17 |
+
spending, and financial health.
|
18 |
+
|
19 |
+
Args:
|
20 |
+
startup_data (dict): Dictionary containing startup financial profile
|
21 |
+
cash_flow_df (pd.DataFrame): DataFrame with monthly cash flow details
|
22 |
+
"""
|
23 |
+
st.markdown("<h1 class='main-header'>Financial Dashboard</h1>", unsafe_allow_html=True)
|
24 |
+
st.markdown("<p class='sub-header'>AI-powered financial insights at a glance</p>", unsafe_allow_html=True)
|
25 |
+
|
26 |
+
# Initialize insights cache if not exists
|
27 |
+
if 'insights_cache' not in st.session_state:
|
28 |
+
st.session_state.insights_cache = {}
|
29 |
+
|
30 |
+
# AI Insights Explanation
|
31 |
+
with st.expander("ℹ️ How AI enhances your financial dashboard"):
|
32 |
+
st.markdown("""
|
33 |
+
### How AI Powers Your Financial Dashboard
|
34 |
+
|
35 |
+
The financial dashboard uses AI to transform raw financial data into actionable intelligence:
|
36 |
+
|
37 |
+
- **Automated Analysis**: Our AI model analyzes your data and highlights critical trends
|
38 |
+
- **Predictive Forecasting**: AI forecasts your runway using advanced analytics
|
39 |
+
- **Anomaly Detection**: Identifies unusual spending patterns or concerning financial trends
|
40 |
+
- **Strategic Recommendations**: Provides tailored recommendations to optimize your runway
|
41 |
+
- **Benchmark Comparison**: Compares your metrics against industry standards
|
42 |
+
|
43 |
+
This helps founders make data-driven decisions quickly and confidently.
|
44 |
+
""")
|
45 |
+
|
46 |
+
# Generate AI Insights
|
47 |
+
insights_key = f"dashboard_{date.today().isoformat()}"
|
48 |
+
if insights_key not in st.session_state.insights_cache:
|
49 |
+
try:
|
50 |
+
insights = generate_ai_response(f"""
|
51 |
+
You are a financial advisor for startups. Based on this startup's data:
|
52 |
+
- Current cash: ${startup_data['cash']:,}
|
53 |
+
- Monthly burn rate: ${startup_data['burn_rate']:,}
|
54 |
+
- Monthly revenue: ${startup_data['revenue']:,}
|
55 |
+
- Monthly growth rate: {startup_data['growth_rate'] * 100:.2f}%
|
56 |
+
|
57 |
+
Provide the top 3 most important financial insights that the founder should know today.
|
58 |
+
Format each insight as a brief, action-oriented bullet point.
|
59 |
+
""")
|
60 |
+
st.session_state.insights_cache[insights_key] = insights
|
61 |
+
except Exception as e:
|
62 |
+
st.session_state.insights_cache[insights_key] = f"Error generating insights: {str(e)}"
|
63 |
+
|
64 |
+
# Display AI Insights
|
65 |
+
with st.expander("📊 AI Financial Insights", expanded=True):
|
66 |
+
st.markdown("<span class='ai-badge'>AI-Generated Insights</span>", unsafe_allow_html=True)
|
67 |
+
st.markdown(st.session_state.insights_cache[insights_key])
|
68 |
+
|
69 |
+
# Key Metrics Section
|
70 |
+
col1, col2, col3, col4 = st.columns(4)
|
71 |
+
|
72 |
+
# Calculate Runway
|
73 |
+
try:
|
74 |
+
runway_months, runway_df = calculate_runway(
|
75 |
+
startup_data['cash'],
|
76 |
+
startup_data['burn_rate'],
|
77 |
+
startup_data['revenue'],
|
78 |
+
startup_data['growth_rate']
|
79 |
+
)
|
80 |
+
except Exception as e:
|
81 |
+
st.error(f"Error calculating runway: {e}")
|
82 |
+
runway_months = 0
|
83 |
+
runway_df = pd.DataFrame() # Placeholder
|
84 |
+
|
85 |
+
# Determine Metric Status Colors
|
86 |
+
runway_status = (
|
87 |
+
"danger-metric" if runway_months < 6 else
|
88 |
+
"warning-metric" if runway_months < 9 else
|
89 |
+
"good-metric"
|
90 |
+
)
|
91 |
+
burn_status = (
|
92 |
+
"danger-metric" if startup_data['burn_rate'] > 100000 else
|
93 |
+
"warning-metric" if startup_data['burn_rate'] > 80000 else
|
94 |
+
"good-metric"
|
95 |
+
)
|
96 |
+
revenue_status = (
|
97 |
+
"good-metric" if startup_data['revenue'] > 20000 else
|
98 |
+
"warning-metric" if startup_data['revenue'] > 10000 else
|
99 |
+
"danger-metric"
|
100 |
+
)
|
101 |
+
|
102 |
+
# Display Key Metrics
|
103 |
+
metrics_display = [
|
104 |
+
("Current Cash", f"${startup_data['cash']:,}", None),
|
105 |
+
("Monthly Burn", f"${startup_data['burn_rate']:,}", burn_status),
|
106 |
+
("Monthly Revenue", f"${startup_data['revenue']:,}", revenue_status),
|
107 |
+
("Runway", f"{runway_months} months", runway_status)
|
108 |
+
]
|
109 |
+
|
110 |
+
for i, (label, value, status) in enumerate(metrics_display):
|
111 |
+
with [col1, col2, col3, col4][i]:
|
112 |
+
status_class = f"metric-value {status}" if status else "metric-value"
|
113 |
+
st.markdown(f"""
|
114 |
+
<div class='metric-card'>
|
115 |
+
<p class='metric-label'>{label}</p>
|
116 |
+
<p class='{status_class}'>{value}</p>
|
117 |
+
</div>
|
118 |
+
""", unsafe_allow_html=True)
|
119 |
+
|
120 |
+
# Financial Overview Tabs
|
121 |
+
st.subheader("Financial Overview")
|
122 |
+
tab1, tab2, tab3 = st.tabs([
|
123 |
+
"Runway Projection",
|
124 |
+
"Revenue vs. Expenses",
|
125 |
+
"Burn Rate Trend"
|
126 |
+
])
|
127 |
+
|
128 |
+
with tab1:
|
129 |
+
# Runway Projection Chart
|
130 |
+
if not runway_df.empty:
|
131 |
+
fig = px.line(
|
132 |
+
runway_df.reset_index(),
|
133 |
+
x='index',
|
134 |
+
y='Cumulative_Cash',
|
135 |
+
title="Cash Runway Projection",
|
136 |
+
labels={'index': 'Month', 'Cumulative_Cash': 'Remaining Cash ($)'},
|
137 |
+
color_discrete_sequence=['#0066cc']
|
138 |
+
)
|
139 |
+
fig.add_hline(y=0, line_dash="dash", line_color="red", annotation_text="Out of Cash")
|
140 |
+
fig.update_layout(
|
141 |
+
height=400,
|
142 |
+
plot_bgcolor='rgba(240,247,255,0.8)',
|
143 |
+
xaxis_title="Month",
|
144 |
+
yaxis_title="Cash Balance ($)",
|
145 |
+
font=dict(family="Arial, sans-serif", size=12),
|
146 |
+
margin=dict(l=20, r=20, t=40, b=20),
|
147 |
+
)
|
148 |
+
st.plotly_chart(fig, use_container_width=True)
|
149 |
+
|
150 |
+
# Runway Analysis
|
151 |
+
with st.expander("🔍 AI Runway Analysis", expanded=True):
|
152 |
+
runway_key = f"runway_{date.today().isoformat()}"
|
153 |
+
if runway_key not in st.session_state.insights_cache:
|
154 |
+
try:
|
155 |
+
runway_analysis = get_runway_analysis(startup_data)
|
156 |
+
st.session_state.insights_cache[runway_key] = runway_analysis
|
157 |
+
except Exception as e:
|
158 |
+
st.session_state.insights_cache[runway_key] = f"Error generating runway analysis: {str(e)}"
|
159 |
+
|
160 |
+
st.markdown("<span class='ai-badge'>AI Financial Analysis</span>", unsafe_allow_html=True)
|
161 |
+
st.markdown(st.session_state.insights_cache[runway_key])
|
162 |
+
|
163 |
+
with tab2:
|
164 |
+
# Revenue vs Expenses Chart
|
165 |
+
rev_exp_df = cash_flow_df.copy()
|
166 |
+
fig = px.bar(
|
167 |
+
rev_exp_df,
|
168 |
+
x='Month',
|
169 |
+
y=['Revenue', 'Total_Expenses'],
|
170 |
+
title="Revenue vs. Expenses",
|
171 |
+
barmode='group',
|
172 |
+
labels={'value': 'Amount ($)', 'variable': 'Category'},
|
173 |
+
color_discrete_sequence=['#28a745', '#dc3545']
|
174 |
+
)
|
175 |
+
fig.update_layout(
|
176 |
+
height=400,
|
177 |
+
plot_bgcolor='rgba(240,247,255,0.8)',
|
178 |
+
xaxis_title="Month",
|
179 |
+
yaxis_title="Amount ($)",
|
180 |
+
font=dict(family="Arial, sans-serif", size=12),
|
181 |
+
legend_title="",
|
182 |
+
margin=dict(l=20, r=20, t=40, b=20),
|
183 |
+
)
|
184 |
+
st.plotly_chart(fig, use_container_width=True)
|
185 |
+
|
186 |
+
# Revenue Growth Calculations
|
187 |
+
try:
|
188 |
+
revenue_growth = [
|
189 |
+
(cash_flow_df['Revenue'].iloc[i] / cash_flow_df['Revenue'].iloc[i-1] - 1) * 100
|
190 |
+
if i > 0 else 0
|
191 |
+
for i in range(len(cash_flow_df))
|
192 |
+
]
|
193 |
+
avg_growth = sum(revenue_growth[1:]) / len(revenue_growth[1:])
|
194 |
+
|
195 |
+
col1, col2 = st.columns(2)
|
196 |
+
with col1:
|
197 |
+
st.metric("Average Monthly Revenue Growth", f"{avg_growth:.1f}%")
|
198 |
+
with col2:
|
199 |
+
expense_growth = (
|
200 |
+
cash_flow_df['Total_Expenses'].iloc[-1] /
|
201 |
+
cash_flow_df['Total_Expenses'].iloc[0] - 1
|
202 |
+
) * 100
|
203 |
+
st.metric(
|
204 |
+
"Total Expense Growth",
|
205 |
+
f"{expense_growth:.1f}%",
|
206 |
+
delta=f"{expense_growth - avg_growth:.1f}%",
|
207 |
+
delta_color="inverse"
|
208 |
+
)
|
209 |
+
except Exception as e:
|
210 |
+
st.error(f"Error calculating growth metrics: {e}")
|
211 |
+
|
212 |
+
with tab3:
|
213 |
+
# Burn Rate Trend Chart
|
214 |
+
fig = px.line(
|
215 |
+
cash_flow_df,
|
216 |
+
x='Month',
|
217 |
+
y='Net_Burn',
|
218 |
+
title="Monthly Net Burn Trend",
|
219 |
+
labels={'Net_Burn': 'Net Burn ($)'},
|
220 |
+
color_discrete_sequence=['#dc3545']
|
221 |
+
)
|
222 |
+
fig.update_layout(
|
223 |
+
height=400,
|
224 |
+
plot_bgcolor='rgba(240,247,255,0.8)',
|
225 |
+
xaxis_title="Month",
|
226 |
+
yaxis_title="Net Burn ($)",
|
227 |
+
font=dict(family="Arial, sans-serif", size=12),
|
228 |
+
margin=dict(l=20, r=20, t=40, b=20),
|
229 |
+
)
|
230 |
+
|
231 |
+
# Efficiency Ratio Calculation
|
232 |
+
try:
|
233 |
+
efficiency_ratio = [
|
234 |
+
cash_flow_df['Revenue'].iloc[i] / cash_flow_df['Total_Expenses'].iloc[i] * 100
|
235 |
+
for i in range(len(cash_flow_df))
|
236 |
+
]
|
237 |
+
|
238 |
+
fig.add_trace(go.Scatter(
|
239 |
+
x=cash_flow_df['Month'],
|
240 |
+
y=efficiency_ratio,
|
241 |
+
name='Efficiency Ratio (%)',
|
242 |
+
yaxis='y2',
|
243 |
+
line=dict(color='#0066cc', width=2, dash='dot')
|
244 |
+
))
|
245 |
+
|
246 |
+
fig.update_layout(
|
247 |
+
yaxis2=dict(
|
248 |
+
title='Efficiency Ratio (%)',
|
249 |
+
overlaying='y',
|
250 |
+
side='right',
|
251 |
+
range=[0, max(efficiency_ratio) * 1.2]
|
252 |
+
)
|
253 |
+
)
|
254 |
+
|
255 |
+
st.plotly_chart(fig, use_container_width=True)
|
256 |
+
|
257 |
+
with st.expander("🔎 Understanding Efficiency Ratio"):
|
258 |
+
st.info(
|
259 |
+
"The efficiency ratio measures how efficiently your startup is generating "
|
260 |
+
"revenue relative to expenses. A higher percentage means you're getting "
|
261 |
+
"more revenue per dollar spent. Venture-backed startups typically aim "
|
262 |
+
"for at least 40% before Series B funding."
|
263 |
+
)
|
264 |
+
except Exception as e:
|
265 |
+
st.error(f"Error calculating efficiency ratio: {e}")
|
266 |
+
|
267 |
+
# Fundraising Readiness Assessment
|
268 |
+
st.subheader("Fundraising Readiness")
|
269 |
+
|
270 |
+
# Get AI analysis of fundraising readiness
|
271 |
+
fundraising_key = f"fundraising_{date.today().isoformat()}"
|
272 |
+
if fundraising_key not in st.session_state.insights_cache:
|
273 |
+
try:
|
274 |
+
fundraising_analysis = get_fundraising_readiness_analysis(startup_data, cash_flow_df)
|
275 |
+
st.session_state.insights_cache[fundraising_key] = fundraising_analysis
|
276 |
+
except Exception as e:
|
277 |
+
st.session_state.insights_cache[fundraising_key] = f"Error generating fundraising analysis: {str(e)}"
|
278 |
+
|
279 |
+
st.markdown("<div class='advisor-card'>", unsafe_allow_html=True)
|
280 |
+
st.markdown("<span class='ai-badge'>AI Fundraising Assessment</span>", unsafe_allow_html=True)
|
281 |
+
st.markdown(
|
282 |
+
f"<p class='advice-text'>{st.session_state.insights_cache[fundraising_key]}</p>",
|
283 |
+
unsafe_allow_html=True
|
284 |
+
)
|
285 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
286 |
+
|
287 |
+
# Call-to-action for advisor
|
288 |
+
st.info("📅 Need personalized guidance on fundraising? [Book a session](#book-a-session) with our AI financial advisor.")
|
289 |
+
|
290 |
+
def get_runway_analysis(financial_data):
|
291 |
+
"""
|
292 |
+
Generate runway analysis using AI
|
293 |
+
|
294 |
+
Args:
|
295 |
+
financial_data (dict): Startup financial data
|
296 |
+
|
297 |
+
Returns:
|
298 |
+
str: AI-generated runway analysis
|
299 |
+
"""
|
300 |
+
prompt = f"""
|
301 |
+
You are a financial advisor for startups. Analyze this startup's financial data:
|
302 |
+
- Current cash: ${financial_data['cash']:,}
|
303 |
+
- Monthly burn rate: ${financial_data['burn_rate']:,}
|
304 |
+
- Monthly revenue: ${financial_data['revenue']:,}
|
305 |
+
- Monthly growth rate: {financial_data['growth_rate'] * 100:.2f}%
|
306 |
+
|
307 |
+
Provide a detailed analysis of their runway and financial health. Include:
|
308 |
+
1. Exact runway calculation in months
|
309 |
+
2. Assessment of financial health (critical, concerning, stable, or healthy)
|
310 |
+
3. Benchmarks compared to similar seed-stage startups
|
311 |
+
4. Three specific, actionable recommendations to improve runway
|
312 |
+
5. Key metrics they should focus on
|
313 |
+
|
314 |
+
Format your response in a structured, easy-to-read format with clear sections and bullet points.
|
315 |
+
"""
|
316 |
+
|
317 |
+
return generate_ai_response(prompt)
|
318 |
+
|
319 |
+
def get_fundraising_readiness_analysis(startup_data, cash_flow_df):
|
320 |
+
"""
|
321 |
+
Generate fundraising readiness analysis using AI
|
322 |
+
|
323 |
+
Args:
|
324 |
+
startup_data (dict): Startup financial profile
|
325 |
+
cash_flow_df (pd.DataFrame): Monthly cash flow data
|
326 |
+
|
327 |
+
Returns:
|
328 |
+
str: AI-generated fundraising readiness analysis
|
329 |
+
"""
|
330 |
+
# Calculate key metrics with error handling
|
331 |
+
try:
|
332 |
+
mrr_growth = (
|
333 |
+
cash_flow_df['Revenue'].iloc[-1] /
|
334 |
+
cash_flow_df['Revenue'].iloc[-2] - 1
|
335 |
+
) * 100
|
336 |
+
except Exception:
|
337 |
+
mrr_growth = 0
|
338 |
+
|
339 |
+
try:
|
340 |
+
gross_margin = (
|
341 |
+
cash_flow_df['Revenue'].iloc[-1] -
|
342 |
+
cash_flow_df['Total_Expenses'].iloc[-1] / 2
|
343 |
+
) / cash_flow_df['Revenue'].iloc[-1] * 100
|
344 |
+
except Exception:
|
345 |
+
gross_margin = 0
|
346 |
+
|
347 |
+
# Predefined metrics with example values
|
348 |
+
metrics = {
|
349 |
+
"MRR Growth": f"{mrr_growth:.1f}%",
|
350 |
+
"Gross Margin": f"{gross_margin:.1f}%",
|
351 |
+
"CAC": "$950", # Customer Acquisition Cost
|
352 |
+
"LTV": "$4,500", # Lifetime Value
|
353 |
+
"Churn": "3.2%",
|
354 |
+
}
|
355 |
+
|
356 |
+
# Convert metrics to formatted text
|
357 |
+
metrics_text = "\n".join([f"- {k}: {v}" for k, v in metrics.items()])
|
358 |
+
|
359 |
+
# Calculate runway
|
360 |
+
try:
|
361 |
+
runway = startup_data['cash'] / (startup_data['burn_rate'] - startup_data['revenue'])
|
362 |
+
except Exception:
|
363 |
+
runway = 0
|
364 |
+
|
365 |
+
# Prepare prompt for AI analysis
|
366 |
+
prompt = f"""
|
367 |
+
You are a startup fundraising advisor. Analyze this startup's readiness for their next funding round:
|
368 |
+
|
369 |
+
Company Profile:
|
370 |
+
- Stage: {startup_data['stage']}
|
371 |
+
- Last Funding: {startup_data.get('last_funding', 'N/A')}
|
372 |
+
- Current Cash: ${startup_data['cash']:,}
|
373 |
+
- Monthly Burn: ${startup_data['burn_rate']:,}
|
374 |
+
- Runway: {runway:.1f} months
|
375 |
+
|
376 |
+
Key Metrics:
|
377 |
+
{metrics_text}
|
378 |
+
|
379 |
+
Provide a comprehensive fundraising readiness assessment:
|
380 |
+
1. Overall fundraising readiness score (0-10)
|
381 |
+
2. Assessment of current metrics compared to investor expectations for next round
|
382 |
+
3. Identify the 3 most critical metrics to improve before fundraising
|
383 |
+
4. Recommend specific targets for each key metric
|
384 |
+
5. Suggest timeline and specific milestones for fundraising preparation
|
385 |
+
6. Estimate reasonable valuation range based on metrics and market conditions
|
386 |
+
|
387 |
+
Be specific with numbers, timelines, and actionable targets.
|
388 |
+
"""
|
389 |
+
|
390 |
+
return generate_ai_response(prompt)
|
src/pages/dashboard-pages-init.py
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
# Import the main rendering function for easier access
|
2 |
+
from .dashboard import render_financial_dashboard
|
src/pages/decision-simulator.py
ADDED
@@ -0,0 +1,321 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
def render_decision_simulator(startup_data):
|
2 |
+
"""
|
3 |
+
Render the AI-powered decision simulator page.
|
4 |
+
|
5 |
+
This feature helps startup founders test the financial impact of business
|
6 |
+
decisions before implementing them, using AI to analyze risks and benefits.
|
7 |
+
"""
|
8 |
+
st.markdown("<h1 class='main-header'>Decision Simulator</h1>", unsafe_allow_html=True)
|
9 |
+
st.markdown("<p class='sub-header'>AI-powered analysis of business decisions</p>", unsafe_allow_html=True)
|
10 |
+
|
11 |
+
# How AI helps with decision-making
|
12 |
+
with st.expander("ℹ️ How AI enhances your decision-making"):
|
13 |
+
st.markdown("""
|
14 |
+
### How AI Powers Your Decision Simulator
|
15 |
+
|
16 |
+
The decision simulator uses AI to help you make better strategic decisions:
|
17 |
+
|
18 |
+
- **Scenario Analysis**: Our AI model simulates multiple financial scenarios based on your input variables
|
19 |
+
- **Risk Assessment**: The system automatically evaluates risk levels based on your cash runway and growth metrics
|
20 |
+
- **Return Prediction**: AI algorithms predict potential returns on investments like hiring or marketing
|
21 |
+
- **Opportunity Cost Analysis**: The model compares different allocations of capital to maximize growth
|
22 |
+
- **Personalized Recommendations**: Based on your specific situation, the AI provides tailored alternatives
|
23 |
+
|
24 |
+
This helps founders make data-driven decisions with less guesswork, avoid costly mistakes, and optimize resource allocation.
|
25 |
+
""")
|
26 |
+
|
27 |
+
st.write("Test the financial impact of key business decisions before implementing them. Our AI advisor will analyze the risks and benefits.")
|
28 |
+
|
29 |
+
# Quick decision templates
|
30 |
+
st.subheader("Common Scenarios")
|
31 |
+
|
32 |
+
decision_templates = {
|
33 |
+
"Hiring Engineering Team": {
|
34 |
+
"description": "Evaluate the impact of growing your engineering team",
|
35 |
+
"new_hires": 3,
|
36 |
+
"new_marketing": 0,
|
37 |
+
"other_expenses": 2000,
|
38 |
+
"growth_impact": 0.02,
|
39 |
+
"question": "We're considering hiring 3 more engineers to accelerate product development. How will this affect our runway and what growth impact should we expect to justify this investment?"
|
40 |
+
},
|
41 |
+
"Marketing Expansion": {
|
42 |
+
"description": "Test increasing your marketing budget",
|
43 |
+
"new_hires": 0,
|
44 |
+
"new_marketing": 15000,
|
45 |
+
"other_expenses": 0,
|
46 |
+
"growth_impact": 0.04,
|
47 |
+
"question": "We want to increase our marketing spend by $15K/month to drive growth. What growth rate would we need to achieve to make this financially viable?"
|
48 |
+
},
|
49 |
+
"Office Expansion": {
|
50 |
+
"description": "Analyze the cost of moving to a larger office",
|
51 |
+
"new_hires": 0,
|
52 |
+
"new_marketing": 0,
|
53 |
+
"other_expenses": 8000,
|
54 |
+
"growth_impact": 0.01,
|
55 |
+
"question": "We're considering moving to a larger office space that would add $8K/month to our expenses. Is this justified at our current stage?"
|
56 |
+
},
|
57 |
+
"Custom Scenario": {
|
58 |
+
"description": "Create your own custom scenario",
|
59 |
+
"new_hires": 0,
|
60 |
+
"new_marketing": 0,
|
61 |
+
"other_expenses": 0,
|
62 |
+
"growth_impact": 0.0,
|
63 |
+
"question": ""
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
# Template selection
|
68 |
+
template_cols = st.columns(4)
|
69 |
+
selected_template = None
|
70 |
+
|
71 |
+
for i, (template_name, template) in enumerate(decision_templates.items()):
|
72 |
+
with template_cols[i]:
|
73 |
+
if st.button(f"{template_name}\n{template['description']}", key=f"template_{i}"):
|
74 |
+
selected_template = template_name
|
75 |
+
|
76 |
+
# Initialize form values based on selected template
|
77 |
+
if selected_template and selected_template != "Custom Scenario":
|
78 |
+
new_hires = decision_templates[selected_template]["new_hires"]
|
79 |
+
new_marketing = decision_templates[selected_template]["new_marketing"]
|
80 |
+
other_expenses = decision_templates[selected_template]["other_expenses"]
|
81 |
+
growth_impact = decision_templates[selected_template]["growth_impact"]
|
82 |
+
question = decision_templates[selected_template]["question"]
|
83 |
+
else:
|
84 |
+
new_hires = 0
|
85 |
+
new_marketing = 0
|
86 |
+
other_expenses = 0
|
87 |
+
growth_impact = 0.0
|
88 |
+
question = ""
|
89 |
+
|
90 |
+
# Decision input form
|
91 |
+
with st.form("decision_form"):
|
92 |
+
st.subheader("Scenario Parameters")
|
93 |
+
|
94 |
+
col1, col2 = st.columns(2)
|
95 |
+
|
96 |
+
with col1:
|
97 |
+
new_hires = st.number_input("New Engineering Hires", min_value=0, max_value=10, value=new_hires,
|
98 |
+
help=f"Each engineer costs ${ENGINEER_SALARY:,} per month")
|
99 |
+
st.caption(f"Monthly Cost: ${new_hires * ENGINEER_SALARY:,}")
|
100 |
+
|
101 |
+
new_marketing = st.number_input("Additional Monthly Marketing Budget",
|
102 |
+
min_value=0, max_value=50000, value=new_marketing, step=1000,
|
103 |
+
help="Additional marketing spend per month")
|
104 |
+
|
105 |
+
with col2:
|
106 |
+
other_expenses = st.number_input("Other Additional Monthly Expenses",
|
107 |
+
min_value=0, max_value=50000, value=other_expenses, step=1000,
|
108 |
+
help="Any other additional monthly expenses")
|
109 |
+
|
110 |
+
growth_impact = st.slider("Estimated Impact on Monthly Growth Rate",
|
111 |
+
min_value=0.0, max_value=0.10, value=growth_impact, step=0.01,
|
112 |
+
format="%.2f",
|
113 |
+
help="Estimated increase in monthly growth rate due to these investments")
|
114 |
+
st.caption(f"New Growth Rate: {(startup_data['growth_rate'] + growth_impact) * 100:.1f}% (current: {startup_data['growth_rate'] * 100:.1f}%)")
|
115 |
+
|
116 |
+
question = st.text_area("Describe your decision scenario",
|
117 |
+
value=question,
|
118 |
+
height=100,
|
119 |
+
placeholder="E.g., We're considering hiring two more engineers and increasing our marketing budget...")
|
120 |
+
|
121 |
+
decision_summary = f"""
|
122 |
+
- {new_hires} new engineers: ${new_hires * ENGINEER_SALARY:,}/month
|
123 |
+
- Marketing increase: ${new_marketing:,}/month
|
124 |
+
- Other expenses: ${other_expenses:,}/month
|
125 |
+
- Total additional burn: ${new_hires * ENGINEER_SALARY + new_marketing + other_expenses:,}/month
|
126 |
+
- Growth impact: +{growth_impact * 100:.1f}% monthly growth
|
127 |
+
"""
|
128 |
+
|
129 |
+
st.markdown(f"**Decision Summary:**\n{decision_summary}")
|
130 |
+
|
131 |
+
submitted = st.form_submit_button("Simulate Decision")
|
132 |
+
|
133 |
+
if submitted:
|
134 |
+
# Calculate current and new runway
|
135 |
+
current_runway, new_runway, current_df, new_df = simulate_decision(
|
136 |
+
startup_data['cash'],
|
137 |
+
startup_data['burn_rate'],
|
138 |
+
startup_data['revenue'],
|
139 |
+
startup_data['growth_rate'],
|
140 |
+
other_expenses,
|
141 |
+
new_hires,
|
142 |
+
new_marketing,
|
143 |
+
growth_impact
|
144 |
+
)
|
145 |
+
|
146 |
+
# Display results
|
147 |
+
st.markdown("<h3>Decision Impact Analysis</h3>", unsafe_allow_html=True)
|
148 |
+
|
149 |
+
# Summary metrics
|
150 |
+
col1, col2, col3 = st.columns(3)
|
151 |
+
|
152 |
+
with col1:
|
153 |
+
st.metric("Current Runway", f"{current_runway} months")
|
154 |
+
with col2:
|
155 |
+
runway_change = new_runway - current_runway
|
156 |
+
st.metric("New Runway", f"{new_runway} months",
|
157 |
+
delta=f"{runway_change} months",
|
158 |
+
delta_color="off" if runway_change == 0 else ("normal" if runway_change > 0 else "inverse"))
|
159 |
+
with col3:
|
160 |
+
new_burn = startup_data['burn_rate'] + other_expenses + (new_hires * ENGINEER_SALARY) + new_marketing
|
161 |
+
burn_change = new_burn - startup_data['burn_rate']
|
162 |
+
burn_percentage = burn_change / startup_data['burn_rate'] * 100
|
163 |
+
st.metric("New Monthly Burn", f"${new_burn:,}",
|
164 |
+
delta=f"${burn_change:,} ({burn_percentage:.1f}%)",
|
165 |
+
delta_color="inverse")
|
166 |
+
|
167 |
+
# Cash projection comparison
|
168 |
+
st.subheader("Cash Projection Comparison")
|
169 |
+
|
170 |
+
# Combine dataframes for comparison
|
171 |
+
current_df['Scenario'] = 'Current'
|
172 |
+
new_df['Scenario'] = 'After Decision'
|
173 |
+
|
174 |
+
combined_df = pd.concat([current_df, new_df])
|
175 |
+
combined_df = combined_df.reset_index()
|
176 |
+
combined_df = combined_df.rename(columns={'index': 'Date'})
|
177 |
+
|
178 |
+
# Plot comparison
|
179 |
+
fig = px.line(combined_df, x='Date', y='Cumulative_Cash', color='Scenario',
|
180 |
+
title="Cash Runway Comparison",
|
181 |
+
labels={'Cumulative_Cash': 'Remaining Cash'},
|
182 |
+
color_discrete_sequence=['#4c78a8', '#f58518'])
|
183 |
+
|
184 |
+
fig.add_hline(y=0, line_dash="dash", line_color="red", annotation_text="Out of Cash")
|
185 |
+
|
186 |
+
fig.update_layout(
|
187 |
+
height=400,
|
188 |
+
plot_bgcolor='rgba(240,247,255,0.8)',
|
189 |
+
xaxis_title="Date",
|
190 |
+
yaxis_title="Cash Balance ($)",
|
191 |
+
font=dict(family="Arial, sans-serif", size=12),
|
192 |
+
margin=dict(l=20, r=20, t=40, b=20),
|
193 |
+
)
|
194 |
+
|
195 |
+
st.plotly_chart(fig, use_container_width=True)
|
196 |
+
|
197 |
+
# Get AI analysis
|
198 |
+
if question:
|
199 |
+
decision_params = {
|
200 |
+
"new_hires": new_hires,
|
201 |
+
"new_marketing": new_marketing,
|
202 |
+
"other_expenses": other_expenses,
|
203 |
+
"growth_impact": growth_impact
|
204 |
+
}
|
205 |
+
|
206 |
+
analysis = get_decision_analysis(question, startup_data, decision_params)
|
207 |
+
|
208 |
+
st.markdown("<div class='advisor-card'>", unsafe_allow_html=True)
|
209 |
+
st.markdown("<span class='ai-badge'>AI Decision Analysis</span>", unsafe_allow_html=True)
|
210 |
+
st.markdown(f"<p class='advice-text'>{analysis}</p>", unsafe_allow_html=True)
|
211 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
212 |
+
|
213 |
+
# Break down impacts of each component
|
214 |
+
st.subheader("Component Impact Analysis")
|
215 |
+
|
216 |
+
# Calculate the impact of each component in isolation
|
217 |
+
_, hiring_runway, _, _ = simulate_decision(
|
218 |
+
startup_data['cash'],
|
219 |
+
startup_data['burn_rate'],
|
220 |
+
startup_data['revenue'],
|
221 |
+
startup_data['growth_rate'],
|
222 |
+
0,
|
223 |
+
new_hires,
|
224 |
+
0,
|
225 |
+
0
|
226 |
+
)
|
227 |
+
|
228 |
+
_, marketing_runway, _, _ = simulate_decision(
|
229 |
+
startup_data['cash'],
|
230 |
+
startup_data['burn_rate'],
|
231 |
+
startup_data['revenue'],
|
232 |
+
startup_data['growth_rate'],
|
233 |
+
0,
|
234 |
+
0,
|
235 |
+
new_marketing,
|
236 |
+
growth_impact
|
237 |
+
)
|
238 |
+
|
239 |
+
_, expenses_runway, _, _ = simulate_decision(
|
240 |
+
startup_data['cash'],
|
241 |
+
startup_data['burn_rate'],
|
242 |
+
startup_data['revenue'],
|
243 |
+
startup_data['growth_rate'],
|
244 |
+
other_expenses,
|
245 |
+
0,
|
246 |
+
0,
|
247 |
+
0
|
248 |
+
)
|
249 |
+
|
250 |
+
component_data = {
|
251 |
+
"Component": ["Engineering Hires", "Marketing Increase", "Other Expenses", "Combined Impact"],
|
252 |
+
"Runway Impact (months)": [
|
253 |
+
hiring_runway - current_runway,
|
254 |
+
marketing_runway - current_runway,
|
255 |
+
expenses_runway - current_runway,
|
256 |
+
new_runway - current_runway
|
257 |
+
]
|
258 |
+
}
|
259 |
+
|
260 |
+
component_df = pd.DataFrame(component_data)
|
261 |
+
|
262 |
+
fig = px.bar(component_df, x='Component', y='Runway Impact (months)',
|
263 |
+
title="Impact of Each Component on Runway",
|
264 |
+
color='Runway Impact (months)',
|
265 |
+
color_continuous_scale=['#dc3545', '#ffc107', '#28a745'],
|
266 |
+
text='Runway Impact (months)')
|
267 |
+
|
268 |
+
fig.update_layout(
|
269 |
+
height=400,
|
270 |
+
plot_bgcolor='rgba(240,247,255,0.8)',
|
271 |
+
font=dict(family="Arial, sans-serif", size=12),
|
272 |
+
margin=dict(l=20, r=20, t=40, b=20),
|
273 |
+
)
|
274 |
+
|
275 |
+
fig.update_traces(texttemplate='%{text:.1f}', textposition='outside')
|
276 |
+
st.plotly_chart(fig, use_container_width=True)
|
277 |
+
|
278 |
+
# Risk assessment
|
279 |
+
risk_level = "High" if new_runway < 3 else ("Medium" if new_runway < 6 else "Low")
|
280 |
+
risk_color = "danger-metric" if risk_level == "High" else ("warning-metric" if risk_level == "Medium" else "good-metric")
|
281 |
+
|
282 |
+
st.markdown(f"""
|
283 |
+
<div class='metric-card'>
|
284 |
+
<p class='metric-label'>Risk Assessment</p>
|
285 |
+
<p class='metric-value {risk_color}'>{risk_level} Risk Decision</p>
|
286 |
+
<p>This decision would give you {new_runway} months of runway.</p>
|
287 |
+
</div>
|
288 |
+
""", unsafe_allow_html=True)
|
289 |
+
|
290 |
+
# Recommendations
|
291 |
+
st.info("💡 **Want personalized guidance on this decision?** [Book a session](#book-a-session) with our AI financial advisor for detailed analysis.")
|
292 |
+
|
293 |
+
def get_decision_analysis(question, financial_data, decision_params):
|
294 |
+
"""Get AI analysis for a specific business decision."""
|
295 |
+
prompt = f"""
|
296 |
+
You are a financial advisor for startups. A founder asks:
|
297 |
+
"{question}"
|
298 |
+
|
299 |
+
Here's their current financial situation:
|
300 |
+
- Current cash: ${financial_data['cash']}
|
301 |
+
- Monthly burn rate: ${financial_data['burn_rate']}
|
302 |
+
- Monthly revenue: ${financial_data['revenue']}
|
303 |
+
- Monthly growth rate: {financial_data['growth_rate'] * 100}%
|
304 |
+
|
305 |
+
They're considering these changes:
|
306 |
+
- Adding {decision_params['new_hires']} new engineers (${ENGINEER_SALARY}/month each)
|
307 |
+
- Increasing marketing budget by ${decision_params['new_marketing']}/month
|
308 |
+
- Adding ${decision_params['other_expenses']}/month in other expenses
|
309 |
+
- Expecting {decision_params['growth_impact'] * 100}% additional monthly growth
|
310 |
+
|
311 |
+
Analyze this decision thoroughly:
|
312 |
+
1. Quantify the impact on runway (exact calculation)
|
313 |
+
2. Assess the risk level (low, medium, high)
|
314 |
+
3. Compare the ROI potential
|
315 |
+
4. Provide 3 specific recommendations or alternatives
|
316 |
+
5. Suggest timeline and milestones for implementation if approved
|
317 |
+
|
318 |
+
Be direct and specific with numbers and timeframes.
|
319 |
+
"""
|
320 |
+
|
321 |
+
return generate_ai_response(prompt)
|
src/pages/financial-advisor.py
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
def render_ai_financial_advisor(startup_data):
|
2 |
+
"""
|
3 |
+
Render the AI financial advisor page with voice chat capabilities.
|
4 |
+
|
5 |
+
This feature provides conversational financial guidance to founders through a
|
6 |
+
natural chat interface with both text and voice responses.
|
7 |
+
"""
|
8 |
+
st.markdown("<h1 class='main-header'>AI Financial Advisor</h1>", unsafe_allow_html=True)
|
9 |
+
st.markdown("<p class='sub-header'>Get expert financial guidance through our AI-powered advisor</p>", unsafe_allow_html=True)
|
10 |
+
|
11 |
+
# How AI helps with financial advisory
|
12 |
+
with st.expander("ℹ️ How AI powers your financial advisor"):
|
13 |
+
st.markdown("""
|
14 |
+
### How AI Powers Your Financial Advisor
|
15 |
+
|
16 |
+
Our AI financial advisor combines advanced language models with financial expertise:
|
17 |
+
|
18 |
+
- **Natural Language Understanding**: The system interprets complex financial questions in plain English
|
19 |
+
- **Domain-Specific Knowledge**: Our AI is trained on startup finance, venture capital, and financial modeling
|
20 |
+
- **Context-Aware Responses**: The advisor takes into account your specific financial situation and history
|
21 |
+
- **Voice Synthesis**: ElevenLabs voice technology creates natural, high-quality voice responses
|
22 |
+
- **Customized Guidance**: AI tailors advice specifically to your stage, industry, and financial position
|
23 |
+
|
24 |
+
This gives founders 24/7 access to high-quality financial guidance without the high cost of consultants.
|
25 |
+
""")
|
26 |
+
|
27 |
+
# Chat container
|
28 |
+
st.markdown("<div style='background-color: #f8f9fa; padding: 20px; border-radius: 10px; margin-bottom: 20px;'>", unsafe_allow_html=True)
|
29 |
+
|
30 |
+
# Display chat history
|
31 |
+
st.subheader("Chat with your Financial Advisor")
|
32 |
+
|
33 |
+
# Initialize chat history if needed
|
34 |
+
if 'chat_history' not in st.session_state:
|
35 |
+
st.session_state.chat_history = [
|
36 |
+
{"role": "assistant", "content": "Hi there! I'm your AI financial advisor. How can I help with your startup's finances today?"}
|
37 |
+
]
|
38 |
+
|
39 |
+
# Display chat messages
|
40 |
+
for message in st.session_state.chat_history:
|
41 |
+
if message["role"] == "user":
|
42 |
+
st.markdown(f"<div style='background-color: #e6f7ff; padding: 10px; border-radius: 10px; margin-bottom: 10px;'><strong>You:</strong> {message['content']}</div>", unsafe_allow_html=True)
|
43 |
+
else:
|
44 |
+
st.markdown(f"<div style='background-color: #f0f7ff; padding: 10px; border-radius: 10px; margin-bottom: 10px;'><strong>Financial Advisor:</strong> {message['content']}</div>", unsafe_allow_html=True)
|
45 |
+
|
46 |
+
# Show play button for voice if it exists
|
47 |
+
if 'audio' in message and message['audio']:
|
48 |
+
st.audio(message['audio'], format='audio/mp3')
|
49 |
+
|
50 |
+
# Input for new message
|
51 |
+
col1, col2 = st.columns([5, 1])
|
52 |
+
|
53 |
+
with col1:
|
54 |
+
user_input = st.text_input("Ask a financial question", key="user_question")
|
55 |
+
|
56 |
+
with col2:
|
57 |
+
use_voice = st.checkbox("Enable voice", value=True)
|
58 |
+
|
59 |
+
# Common financial questions
|
60 |
+
st.markdown("### Common Questions")
|
61 |
+
question_cols = st.columns(3)
|
62 |
+
|
63 |
+
common_questions = [
|
64 |
+
"How much runway do we have at our current burn rate?",
|
65 |
+
"Should we increase our marketing spend given our growth rate?",
|
66 |
+
"When should we start preparing for our next fundraising round?",
|
67 |
+
"How can we optimize our burn rate without impacting growth?",
|
68 |
+
"What metrics should we focus on improving right now?",
|
69 |
+
"How do our unit economics compare to similar startups?"
|
70 |
+
]
|
71 |
+
|
72 |
+
selected_question = None
|
73 |
+
|
74 |
+
for i, question in enumerate(common_questions):
|
75 |
+
with question_cols[i % 3]:
|
76 |
+
if st.button(question, key=f"q_{i}"):
|
77 |
+
selected_question = question
|
78 |
+
|
79 |
+
# Process user input (either from text input or selected question)
|
80 |
+
if user_input or selected_question:
|
81 |
+
question = user_input or selected_question
|
82 |
+
|
83 |
+
# Add user message to chat history
|
84 |
+
st.session_state.chat_history.append({"role": "user", "content": question})
|
85 |
+
|
86 |
+
# Get AI response
|
87 |
+
response = get_advisory_guidance(question, startup_data)
|
88 |
+
|
89 |
+
# Generate voice response if enabled
|
90 |
+
audio_data = None
|
91 |
+
if use_voice:
|
92 |
+
audio_data = generate_voice_response(response)
|
93 |
+
|
94 |
+
# Add AI response to chat history
|
95 |
+
st.session_state.chat_history.append({
|
96 |
+
"role": "assistant",
|
97 |
+
"content": response,
|
98 |
+
"audio": audio_data
|
99 |
+
})
|
100 |
+
|
101 |
+
# Rerun to display updated chat
|
102 |
+
st.experimental_rerun()
|
103 |
+
|
104 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
105 |
+
|
106 |
+
# Advanced options
|
107 |
+
st.subheader("Advanced Tools")
|
108 |
+
|
109 |
+
tool_cols = st.columns(3)
|
110 |
+
|
111 |
+
with tool_cols[0]:
|
112 |
+
st.markdown("""
|
113 |
+
<div style='background-color: white; padding: 15px; border-radius: 10px; height: 200px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);'>
|
114 |
+
<h4>Financial Model Review</h4>
|
115 |
+
<p>Upload your financial model for AI analysis and recommendations.</p>
|
116 |
+
<div style='position: absolute; bottom: 15px;'>
|
117 |
+
<input type='file' disabled/>
|
118 |
+
</div>
|
119 |
+
</div>
|
120 |
+
""", unsafe_allow_html=True)
|
121 |
+
|
122 |
+
with tool_cols[1]:
|
123 |
+
st.markdown("""
|
124 |
+
<div style='background-color: white; padding: 15px; border-radius: 10px; height: 200px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);'>
|
125 |
+
<h4>Investor Pitch Review</h4>
|
126 |
+
<p>Get AI feedback on your investor pitch deck and financial projections.</p>
|
127 |
+
<div style='position: absolute; bottom: 15px;'>
|
128 |
+
<input type='file' disabled/>
|
129 |
+
</div>
|
130 |
+
</div>
|
131 |
+
""", unsafe_allow_html=True)
|
132 |
+
|
133 |
+
with tool_cols[2]:
|
134 |
+
st.markdown("""
|
135 |
+
<div style='background-color: white; padding: 15px; border-radius: 10px; height: 200px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);'>
|
136 |
+
<h4>Fundraising Strategy</h4>
|
137 |
+
<p>Generate a customized fundraising strategy based on your metrics.</p>
|
138 |
+
<div style='position: absolute; bottom: 15px;'>
|
139 |
+
<button disabled>Generate Strategy</button>
|
140 |
+
</div>
|
141 |
+
</div>
|
142 |
+
""", unsafe_allow_html=True)
|
143 |
+
|
144 |
+
# Book a session CTA
|
145 |
+
st.markdown("""
|
146 |
+
<div style='background-color: #e6f7ff; padding: 20px; border-radius: 10px; margin-top: 30px;'>
|
147 |
+
<h3>Need more in-depth guidance?</h3>
|
148 |
+
<p>Book a dedicated session with our AI financial advisor for comprehensive analysis and personalized advice.</p>
|
149 |
+
<a href='#book-a-session'><button>Book a Session</button></a>
|
150 |
+
</div>
|
151 |
+
""", unsafe_allow_html=True)
|
152 |
+
|
153 |
+
def get_advisory_guidance(question, financial_data):
|
154 |
+
"""Get strategic guidance for a startup question."""
|
155 |
+
prompt = f"""
|
156 |
+
You are a strategic financial advisor for startups. A founder asks:
|
157 |
+
"{question}"
|
158 |
+
|
159 |
+
Here's their current financial situation:
|
160 |
+
- Stage: {financial_data['stage']}
|
161 |
+
- Current cash: ${financial_data['cash']}
|
162 |
+
- Monthly burn rate: ${financial_data['burn_rate']}
|
163 |
+
- Monthly revenue: ${financial_data['revenue']}
|
164 |
+
- Monthly growth rate: {financial_data['growth_rate'] * 100}%
|
165 |
+
- Last funding: {financial_data['last_funding']}
|
166 |
+
- Team size: {financial_data['employees']}
|
167 |
+
|
168 |
+
Provide detailed, actionable advice addressing their question. Include:
|
169 |
+
1. Clear assessment of their current situation
|
170 |
+
2. 3-5 specific, actionable recommendations with expected outcomes
|
171 |
+
3. Relevant metrics they should track
|
172 |
+
4. Industry benchmarks for comparison
|
173 |
+
5. Timeline for implementation and results
|
174 |
+
|
175 |
+
Be specific with numbers, timeframes, and expected outcomes.
|
176 |
+
"""
|
177 |
+
|
178 |
+
return generate_ai_response(prompt)
|
179 |
+
|
180 |
+
def generate_voice_response(text):
|
181 |
+
"""Generate voice response using ElevenLabs API (simulated)."""
|
182 |
+
try:
|
183 |
+
# In a real implementation, this would call the ElevenLabs API
|
184 |
+
# For demonstration, we'll simulate an audio response
|
185 |
+
|
186 |
+
# Simulated audio data (just an empty response)
|
187 |
+
audio_data = b''
|
188 |
+
|
189 |
+
# In a real implementation, you would do something like:
|
190 |
+
# url = "https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
|
191 |
+
# headers = {
|
192 |
+
# "Accept": "audio/mpeg",
|
193 |
+
# "Content-Type": "application/json",
|
194 |
+
# "xi-api-key": st.secrets["ELEVENLABS_API_KEY"]
|
195 |
+
# }
|
196 |
+
# data = {
|
197 |
+
# "text": text,
|
198 |
+
# "model_id": "eleven_monolingual_v1",
|
199 |
+
# "voice_settings": {
|
200 |
+
# "stability": 0.5,
|
201 |
+
# "similarity_boost": 0.5
|
202 |
+
# }
|
203 |
+
# }
|
204 |
+
# response = requests.post(url, json=data, headers=headers)
|
205 |
+
# audio_data = response.content
|
206 |
+
|
207 |
+
return audio_data
|
208 |
+
except Exception as e:
|
209 |
+
st.warning(f"Error generating voice response: {e}")
|
210 |
+
return None
|
src/pages/fund-monitoring.py
ADDED
@@ -0,0 +1,334 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
def render_fund_monitoring(transactions_df):
|
2 |
+
"""
|
3 |
+
Render the AI-powered fund monitoring page.
|
4 |
+
|
5 |
+
This feature helps startups monitor spending, detect fraudulent transactions,
|
6 |
+
and maintain investor trust through AI-powered analysis.
|
7 |
+
"""
|
8 |
+
st.markdown("<h1 class='main-header'>Investor Fund Monitoring</h1>", unsafe_allow_html=True)
|
9 |
+
st.markdown("<p class='sub-header'>AI-powered fraud detection and spending analysis</p>", unsafe_allow_html=True)
|
10 |
+
|
11 |
+
# How AI helps with fund monitoring
|
12 |
+
with st.expander("ℹ️ How AI enhances fund monitoring"):
|
13 |
+
st.markdown("""
|
14 |
+
### How AI Powers Your Fund Monitoring
|
15 |
+
|
16 |
+
The fund monitoring system uses AI to help maintain investor trust and optimize spending:
|
17 |
+
|
18 |
+
- **Anomaly Detection**: Our AI models identify unusual transactions that don't match typical startup spending patterns
|
19 |
+
- **Risk Scoring**: Each transaction is assigned a risk score based on multiple factors like amount, category, vendor, and description
|
20 |
+
- **Pattern Recognition**: The system identifies potentially concerning spending trends across categories over time
|
21 |
+
- **Fraud Prevention**: AI algorithms flag transactions that match known patterns of misuse before they become issues
|
22 |
+
- **Investor-Ready Reporting**: Generate reports that demonstrate responsible financial stewardship to investors
|
23 |
+
|
24 |
+
This helps founders maintain investor trust, prevent misuse of funds, and create transparency in financial operations.
|
25 |
+
""")
|
26 |
+
|
27 |
+
st.write("Monitor your startup's spending to maintain investor trust and ensure proper fund usage. Our AI algorithms automatically flag suspicious transactions and identify spending patterns.")
|
28 |
+
|
29 |
+
# AI insights for fund monitoring
|
30 |
+
insights_key = f"fund_monitoring_{date.today().isoformat()}"
|
31 |
+
if insights_key not in st.session_state.insights_cache:
|
32 |
+
insights = generate_ai_response("""
|
33 |
+
You are a financial fraud detection expert. Provide 2-3 critical spending patterns that investors typically look for when monitoring startup fund usage.
|
34 |
+
Format as brief bullet points focused on maintaining investor trust.
|
35 |
+
""", simulate=True)
|
36 |
+
st.session_state.insights_cache[insights_key] = insights
|
37 |
+
|
38 |
+
with st.expander("🔍 AI Monitoring Insights", expanded=True):
|
39 |
+
st.markdown("<span class='ai-badge'>AI-Generated Insights</span>", unsafe_allow_html=True)
|
40 |
+
st.markdown(st.session_state.insights_cache[insights_key])
|
41 |
+
|
42 |
+
# Process transactions to detect suspicious ones with AI enhancement
|
43 |
+
processed_df = detect_suspicious_transactions(transactions_df)
|
44 |
+
|
45 |
+
# Summary metrics
|
46 |
+
total_transactions = len(processed_df)
|
47 |
+
suspicious_transactions = processed_df[processed_df['Suspicious']].copy()
|
48 |
+
suspicious_count = len(suspicious_transactions)
|
49 |
+
suspicious_amount = suspicious_transactions['Amount'].sum()
|
50 |
+
total_amount = processed_df['Amount'].sum()
|
51 |
+
|
52 |
+
col1, col2, col3, col4 = st.columns(4)
|
53 |
+
|
54 |
+
with col1:
|
55 |
+
st.markdown(f"""
|
56 |
+
<div class='metric-card'>
|
57 |
+
<p class='metric-label'>Total Transactions</p>
|
58 |
+
<p class='metric-value'>{total_transactions}</p>
|
59 |
+
</div>
|
60 |
+
""", unsafe_allow_html=True)
|
61 |
+
|
62 |
+
with col2:
|
63 |
+
flagged_percent = suspicious_count/total_transactions*100 if total_transactions > 0 else 0
|
64 |
+
status = "danger-metric" if flagged_percent > 10 else ("warning-metric" if flagged_percent > 5 else "good-metric")
|
65 |
+
st.markdown(f"""
|
66 |
+
<div class='metric-card'>
|
67 |
+
<p class='metric-label'>Flagged Transactions</p>
|
68 |
+
<p class='metric-value {status}'>{suspicious_count} ({flagged_percent:.1f}%)</p>
|
69 |
+
</div>
|
70 |
+
""", unsafe_allow_html=True)
|
71 |
+
|
72 |
+
with col3:
|
73 |
+
amount_percent = suspicious_amount/total_amount*100 if total_amount > 0 else 0
|
74 |
+
status = "danger-metric" if amount_percent > 15 else ("warning-metric" if amount_percent > 7 else "good-metric")
|
75 |
+
st.markdown(f"""
|
76 |
+
<div class='metric-card'>
|
77 |
+
<p class='metric-label'>Flagged Amount</p>
|
78 |
+
<p class='metric-value {status}'>${suspicious_amount:,.0f} ({amount_percent:.1f}%)</p>
|
79 |
+
</div>
|
80 |
+
""", unsafe_allow_html=True)
|
81 |
+
|
82 |
+
with col4:
|
83 |
+
avg_risk = suspicious_transactions['Risk_Score'].mean() if not suspicious_transactions.empty else 0
|
84 |
+
status = "danger-metric" if avg_risk > 50 else ("warning-metric" if avg_risk > 30 else "good-metric")
|
85 |
+
st.markdown(f"""
|
86 |
+
<div class='metric-card'>
|
87 |
+
<p class='metric-label'>Average Risk Score</p>
|
88 |
+
<p class='metric-value {status}'>{avg_risk:.1f}/100</p>
|
89 |
+
</div>
|
90 |
+
""", unsafe_allow_html=True)
|
91 |
+
|
92 |
+
# Tabs for different views
|
93 |
+
tab1, tab2 = st.tabs(["Flagged Transactions", "All Transactions"])
|
94 |
+
|
95 |
+
with tab1:
|
96 |
+
if suspicious_count > 0:
|
97 |
+
# Add risk score visualization (color coded)
|
98 |
+
suspicious_view = suspicious_transactions.copy()
|
99 |
+
|
100 |
+
# Format for display
|
101 |
+
def colorize_risk(val):
|
102 |
+
color = "red" if val > 50 else ("orange" if val > 30 else "blue")
|
103 |
+
return f'background-color: {color}; color: white; font-weight: bold'
|
104 |
+
|
105 |
+
# Apply styling
|
106 |
+
styled_suspicious = suspicious_view.style.applymap(
|
107 |
+
lambda x: colorize_risk(x) if x > 0 else '',
|
108 |
+
subset=['Risk_Score']
|
109 |
+
)
|
110 |
+
|
111 |
+
st.dataframe(
|
112 |
+
suspicious_view[['Date', 'Category', 'Vendor', 'Amount', 'Description', 'Risk_Score', 'Reason']],
|
113 |
+
use_container_width=True
|
114 |
+
)
|
115 |
+
|
116 |
+
# Get AI analysis of suspicious transactions
|
117 |
+
fraud_key = f"fraud_{date.today().isoformat()}"
|
118 |
+
if fraud_key not in st.session_state.insights_cache:
|
119 |
+
fraud_analysis = get_fraud_analysis(suspicious_transactions)
|
120 |
+
st.session_state.insights_cache[fraud_key] = fraud_analysis
|
121 |
+
|
122 |
+
st.markdown("<div class='advisor-card'>", unsafe_allow_html=True)
|
123 |
+
st.markdown("<span class='ai-badge'>AI Fraud Analysis</span>", unsafe_allow_html=True)
|
124 |
+
st.markdown(f"<p class='advice-text'>{st.session_state.insights_cache[fraud_key]}</p>", unsafe_allow_html=True)
|
125 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
126 |
+
|
127 |
+
# Action buttons
|
128 |
+
st.subheader("Recommended Actions")
|
129 |
+
|
130 |
+
col1, col2, col3 = st.columns(3)
|
131 |
+
with col1:
|
132 |
+
if st.button("🔍 Investigate All Flagged"):
|
133 |
+
st.session_state.investigation_started = True
|
134 |
+
with col2:
|
135 |
+
if st.button("📝 Generate Investor Report"):
|
136 |
+
st.session_state.report_generated = True
|
137 |
+
with col3:
|
138 |
+
if st.button("✅ Mark Reviewed"):
|
139 |
+
st.session_state.marked_reviewed = True
|
140 |
+
|
141 |
+
# Simulate action responses
|
142 |
+
if 'investigation_started' in st.session_state and st.session_state.investigation_started:
|
143 |
+
st.success("Investigation initiated for all flagged transactions. Your financial team will be notified.")
|
144 |
+
|
145 |
+
if 'report_generated' in st.session_state and st.session_state.report_generated:
|
146 |
+
st.success("Investor report generated and ready for review before sending.")
|
147 |
+
|
148 |
+
if 'marked_reviewed' in st.session_state and st.session_state.marked_reviewed:
|
149 |
+
st.success("All transactions marked as reviewed. Status will be updated in the system.")
|
150 |
+
else:
|
151 |
+
st.success("No suspicious transactions detected by our AI system. Your spending appears to be normal for a startup at your stage.")
|
152 |
+
|
153 |
+
with tab2:
|
154 |
+
st.dataframe(processed_df[['Date', 'Category', 'Vendor', 'Amount', 'Description', 'Suspicious', 'Risk_Score']],
|
155 |
+
use_container_width=True)
|
156 |
+
|
157 |
+
# Spending patterns
|
158 |
+
st.subheader("Spending Pattern Analysis")
|
159 |
+
|
160 |
+
# Category breakdown
|
161 |
+
category_spending = processed_df.groupby('Category')['Amount'].sum().reset_index()
|
162 |
+
|
163 |
+
col1, col2 = st.columns(2)
|
164 |
+
|
165 |
+
with col1:
|
166 |
+
fig = px.bar(category_spending, x='Category', y='Amount',
|
167 |
+
title="Spending by Category",
|
168 |
+
labels={'Amount': 'Total Spent ($)'},
|
169 |
+
color='Amount',
|
170 |
+
color_continuous_scale='Blues')
|
171 |
+
fig.update_layout(
|
172 |
+
height=400,
|
173 |
+
plot_bgcolor='rgba(240,247,255,0.8)',
|
174 |
+
xaxis_title="Category",
|
175 |
+
yaxis_title="Amount Spent ($)",
|
176 |
+
font=dict(family="Arial, sans-serif", size=12),
|
177 |
+
margin=dict(l=20, r=20, t=40, b=20),
|
178 |
+
)
|
179 |
+
st.plotly_chart(fig, use_container_width=True)
|
180 |
+
|
181 |
+
with col2:
|
182 |
+
# AI spending pattern analysis
|
183 |
+
spending_key = f"spending_pattern_{date.today().isoformat()}"
|
184 |
+
if spending_key not in st.session_state.insights_cache:
|
185 |
+
spending_pattern_analysis = generate_ai_response("""
|
186 |
+
You are a startup spending analyst. Review the spending patterns and provide 3 key insights about:
|
187 |
+
1. Categories that appear to have unusually high spending
|
188 |
+
2. Potential areas where spending could be optimized
|
189 |
+
3. Changes in spending patterns that investors might find concerning
|
190 |
+
|
191 |
+
Format as concise, actionable bullet points.
|
192 |
+
""", simulate=True)
|
193 |
+
st.session_state.insights_cache[spending_key] = spending_pattern_analysis
|
194 |
+
|
195 |
+
st.markdown("<div class='insight-card'>", unsafe_allow_html=True)
|
196 |
+
st.markdown("<span class='ai-badge'>AI Spending Analysis</span>", unsafe_allow_html=True)
|
197 |
+
st.markdown(st.session_state.insights_cache[spending_key])
|
198 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
199 |
+
|
200 |
+
# Time series of spending
|
201 |
+
processed_df['Date'] = pd.to_datetime(processed_df['Date'])
|
202 |
+
processed_df['Week'] = processed_df['Date'].dt.isocalendar().week
|
203 |
+
weekly_spending = processed_df.groupby(['Week', 'Category'])['Amount'].sum().reset_index()
|
204 |
+
|
205 |
+
fig = px.line(weekly_spending, x='Week', y='Amount', color='Category',
|
206 |
+
title="Weekly Spending Trends",
|
207 |
+
labels={'Amount': 'Amount Spent ($)'},
|
208 |
+
color_discrete_sequence=px.colors.qualitative.Bold)
|
209 |
+
fig.update_layout(
|
210 |
+
height=400,
|
211 |
+
plot_bgcolor='rgba(240,247,255,0.8)',
|
212 |
+
xaxis_title="Week",
|
213 |
+
yaxis_title="Amount Spent ($)",
|
214 |
+
font=dict(family="Arial, sans-serif", size=12),
|
215 |
+
margin=dict(l=20, r=20, t=40, b=20),
|
216 |
+
)
|
217 |
+
st.plotly_chart(fig, use_container_width=True)
|
218 |
+
|
219 |
+
# AI-powered spending controls recommendation
|
220 |
+
st.subheader("AI-Recommended Spending Controls")
|
221 |
+
|
222 |
+
# Get AI recommendations for spending controls
|
223 |
+
controls_key = f"spending_controls_{date.today().isoformat()}"
|
224 |
+
if controls_key not in st.session_state.insights_cache:
|
225 |
+
controls_recommendations = generate_ai_response("""
|
226 |
+
You are a financial controls expert for startups. Based on the spending patterns and suspicious transactions,
|
227 |
+
recommend 3-4 specific spending controls that the startup should implement to prevent misuse of funds.
|
228 |
+
|
229 |
+
For each control, provide:
|
230 |
+
1. A clear policy statement
|
231 |
+
2. Implementation steps
|
232 |
+
3. Expected impact
|
233 |
+
|
234 |
+
Format as concise, actionable recommendations.
|
235 |
+
""", simulate=True)
|
236 |
+
st.session_state.insights_cache[controls_key] = controls_recommendations
|
237 |
+
|
238 |
+
st.markdown("<div class='advisor-card'>", unsafe_allow_html=True)
|
239 |
+
st.markdown("<span class='ai-badge'>AI Control Recommendations</span>", unsafe_allow_html=True)
|
240 |
+
st.markdown(f"<p class='advice-text'>{st.session_state.insights_cache[controls_key]}</p>", unsafe_allow_html=True)
|
241 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
242 |
+
|
243 |
+
# Call-to-action
|
244 |
+
st.info("📅 Need help implementing financial controls? [Book a session](#book-a-session) with our AI financial advisor.")
|
245 |
+
|
246 |
+
def detect_suspicious_transactions(transactions_df):
|
247 |
+
"""AI-enhanced suspicious transaction detection."""
|
248 |
+
df = transactions_df.copy()
|
249 |
+
|
250 |
+
# Define thresholds for each category
|
251 |
+
category_thresholds = {
|
252 |
+
"Travel": 3000,
|
253 |
+
"Marketing": 10000,
|
254 |
+
"Office": 7000,
|
255 |
+
"Software": 6000,
|
256 |
+
"Consulting": 5000,
|
257 |
+
"Legal": 6000
|
258 |
+
}
|
259 |
+
|
260 |
+
# Define suspicious terms
|
261 |
+
suspicious_terms = ['luxury', 'cruise', 'premium', 'personal', 'gift']
|
262 |
+
|
263 |
+
# Add suspicious column
|
264 |
+
df['Suspicious'] = False
|
265 |
+
df['Reason'] = ""
|
266 |
+
df['Risk_Score'] = 0
|
267 |
+
|
268 |
+
# Check for suspicious patterns
|
269 |
+
for idx, row in df.iterrows():
|
270 |
+
reasons = []
|
271 |
+
risk_score = 0
|
272 |
+
|
273 |
+
# Check if amount exceeds category threshold
|
274 |
+
if row['Category'] in category_thresholds:
|
275 |
+
if row['Amount'] > category_thresholds[row['Category']]:
|
276 |
+
reasons.append(f"Amount exceeds typical spending for {row['Category']}")
|
277 |
+
risk_score += 30
|
278 |
+
|
279 |
+
# Higher risk for significantly exceeding threshold
|
280 |
+
excess_percentage = (row['Amount'] - category_thresholds[row['Category']]) / category_thresholds[row['Category']] * 100
|
281 |
+
if excess_percentage > 100: # More than double the threshold
|
282 |
+
risk_score += 20
|
283 |
+
|
284 |
+
# Check for suspicious vendors or descriptions
|
285 |
+
if any(term in str(row['Vendor']).lower() for term in suspicious_terms):
|
286 |
+
reasons.append(f"Vendor name contains suspicious term")
|
287 |
+
risk_score += 25
|
288 |
+
|
289 |
+
if any(term in str(row['Description']).lower() for term in suspicious_terms):
|
290 |
+
reasons.append(f"Description contains suspicious term")
|
291 |
+
risk_score += 20
|
292 |
+
|
293 |
+
# Check for rounded amounts (potential indicator of estimation/fabrication)
|
294 |
+
if row['Amount'] % 1000 == 0 and row['Amount'] > 3000:
|
295 |
+
reasons.append(f"Suspiciously round amount")
|
296 |
+
risk_score += 15
|
297 |
+
|
298 |
+
# Mark as suspicious if risk score is high enough
|
299 |
+
if risk_score >= 30:
|
300 |
+
df.at[idx, 'Suspicious'] = True
|
301 |
+
df.at[idx, 'Reason'] = "; ".join(reasons)
|
302 |
+
df.at[idx, 'Risk_Score'] = risk_score
|
303 |
+
|
304 |
+
# Sort by risk score
|
305 |
+
df = df.sort_values(by='Risk_Score', ascending=False)
|
306 |
+
|
307 |
+
return df
|
308 |
+
|
309 |
+
def get_fraud_analysis(transactions_df):
|
310 |
+
"""Get AI analysis of potentially fraudulent transactions."""
|
311 |
+
suspicious_df = transactions_df[transactions_df['Suspicious']].copy()
|
312 |
+
|
313 |
+
if len(suspicious_df) == 0:
|
314 |
+
return "No suspicious transactions detected."
|
315 |
+
|
316 |
+
transactions_text = suspicious_df[['Date', 'Category', 'Vendor', 'Amount', 'Description', 'Risk_Score']].to_string(index=False)
|
317 |
+
|
318 |
+
prompt = f"""
|
319 |
+
You are a financial forensics expert specializing in startup spending oversight.
|
320 |
+
Review these flagged transactions:
|
321 |
+
|
322 |
+
{transactions_text}
|
323 |
+
|
324 |
+
Provide a detailed analysis:
|
325 |
+
1. Identify the most concerning transactions and explain why
|
326 |
+
2. Calculate the total financial impact of these suspicious transactions
|
327 |
+
3. Identify spending patterns or potential policy violations
|
328 |
+
4. Recommend specific actions the startup should take immediately
|
329 |
+
5. Suggest controls to prevent similar issues in the future
|
330 |
+
|
331 |
+
Be specific about which transactions are most concerning and why investors would have questions.
|
332 |
+
"""
|
333 |
+
|
334 |
+
return generate_ai_response(prompt)
|
src/utils/__init__.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
# Import utility modules
|
2 |
+
from . import ai_helpers
|
3 |
+
from . import data_processing
|
src/utils/ai-helpers.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import google.generativeai as genai
|
3 |
+
from dotenv import load_dotenv
|
4 |
+
|
5 |
+
# Load environment variables
|
6 |
+
load_dotenv()
|
7 |
+
|
8 |
+
# Configure the Gemini API
|
9 |
+
genai.configure(api_key=os.getenv('GOOGLE_API_KEY'))
|
10 |
+
|
11 |
+
def generate_ai_response(prompt, model_name='gemini-pro', temperature=0.7, max_tokens=1000):
|
12 |
+
"""
|
13 |
+
Generate an AI response using Google's Generative AI (Gemini)
|
14 |
+
|
15 |
+
Args:
|
16 |
+
prompt (str): The input prompt for the AI
|
17 |
+
model_name (str, optional): The Gemini model to use. Defaults to 'gemini-pro'.
|
18 |
+
temperature (float, optional): Controls randomness. Defaults to 0.7.
|
19 |
+
max_tokens (int, optional): Maximum length of the generated response. Defaults to 1000.
|
20 |
+
|
21 |
+
Returns:
|
22 |
+
str: The generated AI response
|
23 |
+
"""
|
24 |
+
try:
|
25 |
+
# Select the model
|
26 |
+
model = genai.GenerativeModel(model_name)
|
27 |
+
|
28 |
+
# Generate content
|
29 |
+
response = model.generate_content(
|
30 |
+
prompt,
|
31 |
+
generation_config=genai.types.GenerationConfig(
|
32 |
+
temperature=temperature,
|
33 |
+
max_output_tokens=max_tokens
|
34 |
+
)
|
35 |
+
)
|
36 |
+
|
37 |
+
# Return the text of the response
|
38 |
+
return response.text
|
39 |
+
|
40 |
+
except Exception as e:
|
41 |
+
print(f"Error generating AI response: {e}")
|
42 |
+
return f"An error occurred while generating the response: {str(e)}"
|
43 |
+
|
44 |
+
def simulate_ai_response(prompt):
|
45 |
+
"""
|
46 |
+
Simulated AI response for development and testing
|
47 |
+
|
48 |
+
Args:
|
49 |
+
prompt (str): The input prompt
|
50 |
+
|
51 |
+
Returns:
|
52 |
+
str: A simulated response based on the prompt
|
53 |
+
"""
|
54 |
+
# This is a placeholder for simulated responses during development
|
55 |
+
# In a real implementation, this would be removed or more sophisticatedly implemented
|
56 |
+
import random
|
57 |
+
|
58 |
+
simulated_responses = [
|
59 |
+
"Based on the current financial data, here are some key insights...",
|
60 |
+
"The AI suggests optimizing your spending in these key areas...",
|
61 |
+
"Your startup shows promising growth potential with these recommendations...",
|
62 |
+
"We've identified potential areas for financial improvement...",
|
63 |
+
"Here's a strategic overview of your financial situation..."
|
64 |
+
]
|
65 |
+
|
66 |
+
return random.choice(simulated_responses)
|
src/utils/data-processing.py
ADDED
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import numpy as np
|
3 |
+
from datetime import datetime, timedelta
|
4 |
+
|
5 |
+
def calculate_runway(current_cash, burn_rate, monthly_revenue, growth_rate, months=12):
|
6 |
+
"""
|
7 |
+
Calculate the startup's runway based on financial parameters
|
8 |
+
|
9 |
+
Args:
|
10 |
+
current_cash (float): Current cash balance
|
11 |
+
burn_rate (float): Monthly burn rate
|
12 |
+
monthly_revenue (float): Current monthly revenue
|
13 |
+
growth_rate (float): Monthly revenue growth rate
|
14 |
+
months (int, optional): Projection period. Defaults to 12.
|
15 |
+
|
16 |
+
Returns:
|
17 |
+
tuple: (runway months, runway dataframe)
|
18 |
+
"""
|
19 |
+
# Create projection dataframe
|
20 |
+
df = pd.DataFrame(index=range(months))
|
21 |
+
|
22 |
+
# Initialize first month
|
23 |
+
df.loc[0, 'Revenue'] = monthly_revenue
|
24 |
+
df.loc[0, 'Burn_Rate'] = burn_rate
|
25 |
+
df.loc[0, 'Net_Burn'] = burn_rate - monthly_revenue
|
26 |
+
df.loc[0, 'Cumulative_Cash'] = current_cash - df.loc[0, 'Net_Burn']
|
27 |
+
|
28 |
+
# Project forward
|
29 |
+
for i in range(1, months):
|
30 |
+
# Grow revenue
|
31 |
+
df.loc[i, 'Revenue'] = df.loc[i-1, 'Revenue'] * (1 + growth_rate)
|
32 |
+
|
33 |
+
# Adjust burn rate (simplified model)
|
34 |
+
df.loc[i, 'Burn_Rate'] = burn_rate # Could make this more sophisticated
|
35 |
+
|
36 |
+
# Calculate net burn
|
37 |
+
df.loc[i, 'Net_Burn'] = df.loc[i, 'Burn_Rate'] - df.loc[i, 'Revenue']
|
38 |
+
|
39 |
+
# Calculate cumulative cash
|
40 |
+
df.loc[i, 'Cumulative_Cash'] = df.loc[i-1, 'Cumulative_Cash'] - df.loc[i, 'Net_Burn']
|
41 |
+
|
42 |
+
# Stop if out of cash
|
43 |
+
if df.loc[i, 'Cumulative_Cash'] <= 0:
|
44 |
+
break
|
45 |
+
|
46 |
+
# Calculate runway months
|
47 |
+
runway_months = df[df['Cumulative_Cash'] > 0].shape[0]
|
48 |
+
|
49 |
+
return runway_months, df
|
50 |
+
|
51 |
+
def generate_sample_startup_data():
|
52 |
+
"""
|
53 |
+
Generate sample startup financial data for demonstration
|
54 |
+
|
55 |
+
Returns:
|
56 |
+
dict: Sample startup financial data
|
57 |
+
"""
|
58 |
+
return {
|
59 |
+
"name": "TechHealth AI",
|
60 |
+
"stage": "Seed",
|
61 |
+
"founded": "18 months ago",
|
62 |
+
"employees": 12,
|
63 |
+
"last_funding": "$1.2M seed round 10 months ago",
|
64 |
+
"cash": 320000,
|
65 |
+
"burn_rate": 85000,
|
66 |
+
"revenue": 15000,
|
67 |
+
"growth_rate": 0.08
|
68 |
+
}
|
69 |
+
|
70 |
+
def generate_sample_cash_flow_data():
|
71 |
+
"""
|
72 |
+
Generate sample cash flow data for demonstration
|
73 |
+
|
74 |
+
Returns:
|
75 |
+
pd.DataFrame: Sample cash flow DataFrame
|
76 |
+
"""
|
77 |
+
cash_flow_data = {
|
78 |
+
"Month": [f"Month {i}" for i in range(1, 11)],
|
79 |
+
"Revenue": [8000, 8500, 9200, 10000, 10800, 11700, 12600, 13600, 14700, 15800],
|
80 |
+
"Payroll": [60000, 60000, 62000, 62000, 65000, 65000, 70000, 70000, 75000, 75000],
|
81 |
+
"Marketing": [8000, 9000, 10000, 12000, 15000, 18000, 15000, 12000, 10000, 8000],
|
82 |
+
"Office": [5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000],
|
83 |
+
"Software": [3000, 3200, 3500, 3800, 4000, 4200, 4500, 4800, 5000, 5200],
|
84 |
+
"Travel": [2000, 1800, 2500, 3000, 4000, 4500, 3500, 3000, 2500, 2000],
|
85 |
+
"Legal": [1500, 1000, 800, 1200, 800, 2000, 1500, 1000, 3000, 1200],
|
86 |
+
"Misc": [1000, 1200, 1300, 1500, 1700, 1800, 2000, 2200, 2500, 2800]
|
87 |
+
}
|
88 |
+
|
89 |
+
# Create DataFrame
|
90 |
+
df = pd.DataFrame(cash_flow_data)
|
91 |
+
|
92 |
+
# Add calculated fields
|
93 |
+
df["Total_Expenses"] = df[["Payroll", "Marketing", "Office", "Software", "Travel", "Legal", "Misc"]].sum(axis=1)
|
94 |
+
df["Net_Burn"] = df["Total_Expenses"] - df["Revenue"]
|
95 |
+
|
96 |
+
return df
|
97 |
+
|
98 |
+
def generate_sample_transactions_data():
|
99 |
+
"""
|
100 |
+
Generate sample transactions data for demonstration
|
101 |
+
|
102 |
+
Returns:
|
103 |
+
pd.DataFrame: Sample transactions DataFrame
|
104 |
+
"""
|
105 |
+
transactions = pd.DataFrame([
|
106 |
+
{"Date": "2023-11-05", "Category": "Travel", "Vendor": "Caribbean Cruises", "Amount": 8500, "Description": "Team Retreat Planning", "Flag": "Suspicious"},
|
107 |
+
{"Date": "2023-11-12", "Category": "Marketing", "Vendor": "LuxuryGifts Inc", "Amount": 4200, "Description": "Client Appreciation", "Flag": "Suspicious"},
|
108 |
+
{"Date": "2023-11-22", "Category": "Office", "Vendor": "Premium Furniture", "Amount": 12000, "Description": "Office Upgrades", "Flag": "Suspicious"},
|
109 |
+
{"Date": "2023-11-28", "Category": "Consulting", "Vendor": "Strategic Vision LLC", "Amount": 7500, "Description": "Strategy Consulting", "Flag": "Suspicious"},
|
110 |
+
{"Date": "2023-12-05", "Category": "Software", "Vendor": "Personal Apple Store", "Amount": 3200, "Description": "Development Tools", "Flag": "Suspicious"},
|
111 |
+
{"Date": "2023-12-12", "Category": "Legal", "Vendor": "Anderson Brothers", "Amount": 5800, "Description": "Legal Services", "Flag": "Normal"},
|
112 |
+
{"Date": "2023-12-20", "Category": "Payroll", "Vendor": "November Payroll", "Amount": 75000, "Description": "Monthly Payroll", "Flag": "Normal"},
|
113 |
+
{"Date": "2023-12-22", "Category": "Marketing", "Vendor": "Google Ads", "Amount": 8000, "Description": "Ad Campaign", "Flag": "Normal"},
|
114 |
+
{"Date": "2023-12-25", "Category": "Office", "Vendor": "WeWork", "Amount": 5000, "Description": "Monthly Rent", "Flag": "Normal"},
|
115 |
+
{"Date": "2023-12-28", "Category": "Software", "Vendor": "AWS", "Amount": 5200, "Description": "Cloud Services", "Flag": "Normal"}
|
116 |
+
])
|
117 |
+
|
118 |
+
return transactions
|