Spaces:
Runtime error
Runtime error
import streamlit as st | |
import pandas as pd | |
import plotly.express as px | |
import plotly.graph_objects as go | |
from plotly.subplots import make_subplots | |
import numpy as np | |
from datetime import datetime | |
import io | |
# Page configuration | |
st.set_page_config( | |
page_title="📊 FinanceGPT Analyzer", | |
page_icon="📊", | |
layout="wide", | |
initial_sidebar_state="expanded" | |
) | |
# Custom CSS for better styling | |
st.markdown(""" | |
<style> | |
.metric-card { | |
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); | |
padding: 1rem; | |
border-radius: 10px; | |
color: white; | |
text-align: center; | |
margin: 0.5rem 0; | |
} | |
.insight-box { | |
background: #f8f9fa; | |
padding: 1rem; | |
border-left: 4px solid #007bff; | |
border-radius: 5px; | |
margin: 1rem 0; | |
} | |
.warning-box { | |
background: #fff3cd; | |
padding: 1rem; | |
border-left: 4px solid #ffc107; | |
border-radius: 5px; | |
margin: 1rem 0; | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
class FinanceAnalyzer: | |
def __init__(self): | |
self.data = None | |
self.processed_data = {} | |
def load_sample_data(self): | |
"""Load sample financial data""" | |
sample_data = { | |
'Year': [2024, 2024, 2024, 2024, 2024, 2024, 2024, 2024, 2024, 2024, | |
2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023], | |
'Statement_Type': ['Income Statement'] * 10 + ['Income Statement'] * 10, | |
'Account_Name_Norwegian': ['Salgsinntekt', 'Varekostnad', 'Bruttoresultat', 'Lønnskostnad', | |
'Andre driftskostnader', 'Driftsresultat', 'Finansinntekter', | |
'Finanskostnader', 'Ordinært resultat før skatt', 'Årsresultat'] * 2, | |
'Account_Name_English': ['Sales Revenue', 'Cost of Goods Sold', 'Gross Profit', 'Salary Costs', | |
'Other Operating Expenses', 'Operating Result', 'Financial Income', | |
'Financial Expenses', 'Profit Before Tax', 'Net Profit'] * 2, | |
'2024_Amount_NOK': [25107008, -15064205, 10042803, -3521456, -1987234, 4534113, 123456, | |
-234567, 4422002, 3537602, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
'2023_Amount_NOK': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4891891, -2934535, 1957356, -1234567, | |
-654321, 68468, 45678, -123456, -9310, -7448] | |
} | |
return pd.DataFrame(sample_data) | |
def process_financial_data(self, df): | |
"""Process uploaded financial data""" | |
self.data = df | |
# Create pivot tables for easier analysis | |
income_2024 = df[df['Year'] == 2024]['2024_Amount_NOK'].values | |
income_2023 = df[df['Year'] == 2023]['2023_Amount_NOK'].values | |
accounts = df[df['Year'] == 2024]['Account_Name_English'].values | |
self.processed_data = { | |
'revenue_2024': income_2024[0] if len(income_2024) > 0 else 0, | |
'revenue_2023': income_2023[0] if len(income_2023) > 0 else 0, | |
'net_profit_2024': income_2024[9] if len(income_2024) > 9 else 0, | |
'net_profit_2023': income_2023[9] if len(income_2023) > 9 else 0, | |
'cogs_2024': abs(income_2024[1]) if len(income_2024) > 1 else 0, | |
'cogs_2023': abs(income_2023[1]) if len(income_2023) > 1 else 0, | |
'operating_profit_2024': income_2024[5] if len(income_2024) > 5 else 0, | |
'operating_profit_2023': income_2023[5] if len(income_2023) > 5 else 0, | |
} | |
def calculate_metrics(self): | |
"""Calculate key financial metrics""" | |
if not self.processed_data: | |
return {} | |
data = self.processed_data | |
# Growth rates | |
revenue_growth = ((data['revenue_2024'] - data['revenue_2023']) / | |
abs(data['revenue_2023']) * 100) if data['revenue_2023'] != 0 else 0 | |
# Profitability ratios | |
gross_margin_2024 = ((data['revenue_2024'] - data['cogs_2024']) / | |
data['revenue_2024'] * 100) if data['revenue_2024'] != 0 else 0 | |
net_margin_2024 = (data['net_profit_2024'] / data['revenue_2024'] * 100) if data['revenue_2024'] != 0 else 0 | |
return { | |
'revenue_growth': revenue_growth, | |
'gross_margin_2024': gross_margin_2024, | |
'net_margin_2024': net_margin_2024, | |
'revenue_2024_m': data['revenue_2024'] / 1000000, | |
'net_profit_2024_m': data['net_profit_2024'] / 1000000, | |
} | |
def create_revenue_trend_chart(self): | |
"""Create revenue trend visualization""" | |
if not self.processed_data: | |
return go.Figure() | |
fig = go.Figure() | |
years = [2023, 2024] | |
revenues = [self.processed_data['revenue_2023']/1000000, | |
self.processed_data['revenue_2024']/1000000] | |
net_profits = [self.processed_data['net_profit_2023']/1000000, | |
self.processed_data['net_profit_2024']/1000000] | |
fig.add_trace(go.Scatter(x=years, y=revenues, mode='lines+markers', | |
name='Revenue (M NOK)', line=dict(color='#1f77b4', width=3))) | |
fig.add_trace(go.Scatter(x=years, y=net_profits, mode='lines+markers', | |
name='Net Profit (M NOK)', line=dict(color='#ff7f0e', width=3))) | |
fig.update_layout(title='Revenue vs Profit Trend', xaxis_title='Year', | |
yaxis_title='Amount (M NOK)', height=400) | |
return fig | |
def create_financial_health_radar(self): | |
"""Create financial health radar chart""" | |
metrics = self.calculate_metrics() | |
categories = ['Revenue Growth', 'Gross Margin', 'Net Margin', 'Profitability', 'Efficiency'] | |
values = [ | |
min(metrics.get('revenue_growth', 0) / 5, 100), # Scale revenue growth | |
metrics.get('gross_margin_2024', 0), | |
max(metrics.get('net_margin_2024', 0), 0), | |
70, # Sample value | |
65 # Sample value | |
] | |
fig = go.Figure() | |
fig.add_trace(go.Scatterpolar( | |
r=values, | |
theta=categories, | |
fill='toself', | |
name='Financial Health' | |
)) | |
fig.update_layout( | |
polar=dict( | |
radialaxis=dict(visible=True, range=[0, 100]) | |
), | |
title="Financial Health Score", | |
height=400 | |
) | |
return fig | |
def main(): | |
st.title("📊 FinanceGPT Analyzer") | |
st.markdown("### Professional Financial Analysis Dashboard") | |
analyzer = FinanceAnalyzer() | |
# Sidebar navigation | |
with st.sidebar: | |
st.header("Navigation") | |
page = st.selectbox("Choose Analysis Page", [ | |
"🏠 Dashboard", | |
"💰 Income Analysis", | |
"🏛️ Balance Sheet Analysis", | |
"💸 Cash Flow Analysis", | |
"📊 Financial Ratios Hub", | |
"🤖 AI Finance Assistant" | |
]) | |
st.header("Data Upload") | |
uploaded_file = st.file_uploader("Upload CSV file", type=['csv']) | |
if st.button("Use Sample Data"): | |
analyzer.data = analyzer.load_sample_data() | |
analyzer.process_financial_data(analyzer.data) | |
st.success("Sample data loaded!") | |
if uploaded_file: | |
try: | |
df = pd.read_csv(uploaded_file) | |
analyzer.data = df | |
analyzer.process_financial_data(df) | |
st.success("Data uploaded successfully!") | |
except Exception as e: | |
st.error(f"Error loading file: {e}") | |
# Main content based on selected page | |
if page == "🏠 Dashboard": | |
dashboard_page(analyzer) | |
elif page == "💰 Income Analysis": | |
income_analysis_page(analyzer) | |
elif page == "🏛️ Balance Sheet Analysis": | |
balance_sheet_page(analyzer) | |
elif page == "💸 Cash Flow Analysis": | |
cash_flow_page(analyzer) | |
elif page == "📊 Financial Ratios Hub": | |
ratios_page(analyzer) | |
elif page == "🤖 AI Finance Assistant": | |
ai_assistant_page(analyzer) | |
def dashboard_page(analyzer): | |
"""Main dashboard page""" | |
st.header("📊 Financial Dashboard") | |
if analyzer.data is None: | |
st.warning("Please upload data or use sample data to begin analysis.") | |
return | |
metrics = analyzer.calculate_metrics() | |
# Key metrics cards | |
col1, col2, col3, col4 = st.columns(4) | |
with col1: | |
st.markdown(""" | |
<div class="metric-card"> | |
<h3>💰 Revenue</h3> | |
<h2>{:.1f}M NOK</h2> | |
<p>+{:.0f}% 🔥</p> | |
</div> | |
""".format(metrics.get('revenue_2024_m', 0), metrics.get('revenue_growth', 0)), | |
unsafe_allow_html=True) | |
with col2: | |
st.markdown(""" | |
<div class="metric-card"> | |
<h3>📈 Net Profit</h3> | |
<h2>{:.1f}M NOK</h2> | |
<p>Profitable ✅</p> | |
</div> | |
""".format(metrics.get('net_profit_2024_m', 0)), unsafe_allow_html=True) | |
with col3: | |
st.markdown(""" | |
<div class="metric-card"> | |
<h3>📊 Gross Margin</h3> | |
<h2>{:.1f}%</h2> | |
<p>Healthy 💪</p> | |
</div> | |
""".format(metrics.get('gross_margin_2024', 0)), unsafe_allow_html=True) | |
with col4: | |
st.markdown(""" | |
<div class="metric-card"> | |
<h3>🎯 Net Margin</h3> | |
<h2>{:.1f}%</h2> | |
<p>Strong 📈</p> | |
</div> | |
""".format(metrics.get('net_margin_2024', 0)), unsafe_allow_html=True) | |
# Charts section | |
col1, col2 = st.columns(2) | |
with col1: | |
st.plotly_chart(analyzer.create_revenue_trend_chart(), use_container_width=True) | |
with col2: | |
st.plotly_chart(analyzer.create_financial_health_radar(), use_container_width=True) | |
# Quick insights | |
st.markdown(""" | |
<div class="insight-box"> | |
<h4>🎯 Quick Insights</h4> | |
<ul> | |
<li>✅ Revenue growth of {:.0f}% indicates explosive business development</li> | |
<li>💡 Net profit margin of {:.1f}% shows strong profitability</li> | |
<li>📈 Gross margin of {:.1f}% demonstrates healthy pricing power</li> | |
</ul> | |
</div> | |
""".format( | |
metrics.get('revenue_growth', 0), | |
metrics.get('net_margin_2024', 0), | |
metrics.get('gross_margin_2024', 0) | |
), unsafe_allow_html=True) | |
def income_analysis_page(analyzer): | |
"""Income statement analysis page""" | |
st.header("💰 Income Analysis") | |
if analyzer.data is None: | |
st.warning("Please upload data to begin analysis.") | |
return | |
# Revenue analysis | |
st.subheader("📈 Revenue Trend Analysis") | |
st.plotly_chart(analyzer.create_revenue_trend_chart(), use_container_width=True) | |
# Cost structure | |
st.subheader("🥧 Cost Structure Analysis") | |
if analyzer.processed_data: | |
data = analyzer.processed_data | |
costs = ['Cost of Goods Sold', 'Operating Expenses', 'Financial Expenses'] | |
values = [data['cogs_2024'], 2000000, 234567] # Sample values | |
fig = px.pie(values=values, names=costs, title="Cost Breakdown 2024") | |
st.plotly_chart(fig, use_container_width=True) | |
# Profitability metrics | |
st.subheader("📊 Profitability Indicators") | |
metrics = analyzer.calculate_metrics() | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
st.metric("Gross Margin", f"{metrics.get('gross_margin_2024', 0):.1f}%") | |
with col2: | |
st.metric("Net Margin", f"{metrics.get('net_margin_2024', 0):.1f}%") | |
with col3: | |
st.metric("Revenue Growth", f"{metrics.get('revenue_growth', 0):.1f}%") | |
def balance_sheet_page(analyzer): | |
"""Balance sheet analysis page""" | |
st.header("🏛️ Balance Sheet Analysis") | |
if analyzer.data is None: | |
st.warning("Please upload balance sheet data to begin analysis.") | |
return | |
st.info("Balance sheet analysis requires additional data. Please upload complete financial statements.") | |
# Sample asset structure chart | |
assets = ['Current Assets', 'Fixed Assets', 'Intangible Assets'] | |
values = [45, 35, 20] | |
fig = px.pie(values=values, names=assets, title="Asset Structure") | |
st.plotly_chart(fig, use_container_width=True) | |
def cash_flow_page(analyzer): | |
"""Cash flow analysis page""" | |
st.header("💸 Cash Flow Analysis") | |
if analyzer.data is None: | |
st.warning("Please upload cash flow data to begin analysis.") | |
return | |
st.info("Cash flow analysis requires additional data. Please upload complete cash flow statements.") | |
# Sample cash flow chart | |
categories = ['Operating CF', 'Investing CF', 'Financing CF'] | |
values = [5000000, -2000000, -1000000] | |
fig = go.Figure(go.Waterfall( | |
name="Cash Flow", orientation="v", | |
measure=["relative", "relative", "relative"], | |
x=categories, y=values, | |
text=[f"{v/1000000:.1f}M" for v in values] | |
)) | |
fig.update_layout(title="Cash Flow Waterfall") | |
st.plotly_chart(fig, use_container_width=True) | |
def ratios_page(analyzer): | |
"""Financial ratios analysis page""" | |
st.header("📊 Financial Ratios Hub") | |
if analyzer.data is None: | |
st.warning("Please upload data to calculate ratios.") | |
return | |
# Ratio categories | |
col1, col2, col3, col4 = st.columns(4) | |
with col1: | |
if st.button("Profitability"): | |
st.session_state.ratio_category = "profitability" | |
with col2: | |
if st.button("Liquidity"): | |
st.session_state.ratio_category = "liquidity" | |
with col3: | |
if st.button("Efficiency"): | |
st.session_state.ratio_category = "efficiency" | |
with col4: | |
if st.button("Growth"): | |
st.session_state.ratio_category = "growth" | |
# Display ratios based on selection | |
metrics = analyzer.calculate_metrics() | |
st.subheader("Key Financial Ratios") | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
st.metric("Gross Profit Margin", f"{metrics.get('gross_margin_2024', 0):.1f}%", "A+") | |
with col2: | |
st.metric("Net Profit Margin", f"{metrics.get('net_margin_2024', 0):.1f}%", "A") | |
with col3: | |
st.metric("Revenue Growth", f"{metrics.get('revenue_growth', 0):.1f}%", "A+") | |
def ai_assistant_page(analyzer): | |
"""AI finance assistant page""" | |
st.header("🤖 AI Finance Assistant") | |
if analyzer.data is None: | |
st.warning("Please upload data to enable AI analysis.") | |
return | |
# Chat interface | |
st.subheader("💬 Ask Your Financial Questions") | |
# Predefined questions | |
col1, col2 = st.columns(2) | |
with col1: | |
if st.button("Analyze my financial health"): | |
st.session_state.ai_query = "financial_health" | |
if st.button("Find the biggest risks"): | |
st.session_state.ai_query = "risks" | |
with col2: | |
if st.button("Give investment advice"): | |
st.session_state.ai_query = "investment" | |
if st.button("Create improvement plan"): | |
st.session_state.ai_query = "improvement" | |
# Text input for custom questions | |
user_question = st.text_input("Or ask your own question:") | |
if user_question or 'ai_query' in st.session_state: | |
metrics = analyzer.calculate_metrics() | |
# Simple AI-like responses based on data | |
if user_question or st.session_state.get('ai_query') == 'financial_health': | |
st.markdown(""" | |
<div class="insight-box"> | |
<h4>🎯 Financial Health Analysis</h4> | |
<p>Based on your financial data:</p> | |
<ul> | |
<li>✅ <strong>Revenue Growth:</strong> {:.0f}% growth shows strong market performance</li> | |
<li>✅ <strong>Profitability:</strong> {:.1f}% net margin indicates healthy operations</li> | |
<li>📊 <strong>Overall Rating:</strong> A- (Strong financial position)</li> | |
</ul> | |
</div> | |
""".format( | |
metrics.get('revenue_growth', 0), | |
metrics.get('net_margin_2024', 0) | |
), unsafe_allow_html=True) | |
# Clear the session state | |
if 'ai_query' in st.session_state: | |
del st.session_state.ai_query | |
if __name__ == "__main__": | |
main() |