FinSight_AI / app.py
Sujatha's picture
Update app.py
7ac1427 verified
Raw History Blame Contribute Delete
34.3 kB
import gradio as gr
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.graph_objects as go
import plotly.express as px
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')
# Hugging Face imports with error handling
try:
from transformers import pipeline
from sentence_transformers import SentenceTransformer
import torch
HF_AVAILABLE = True
except ImportError:
HF_AVAILABLE = False
print("Hugging Face libraries not available. Running in lightweight mode.")
class FinancialSpacesAgent:
"""Optimized Financial Agent for Hugging Face Spaces"""
def __init__(self):
print("πŸš€ Initializing Financial Analysis Agent for Spaces...")
self.models_loaded = False
self.company_cache = {}
self.load_models_optimized()
def load_models_optimized(self):
"""Load models optimized for Spaces memory constraints"""
try:
if not HF_AVAILABLE:
self.models_loaded = False
print("Running in lightweight mode (no AI models)")
return
# Load lightweight models
print("πŸ“¦ Loading AI models...")
# 1. Lightweight sentiment model
try:
self.sentiment_model = pipeline(
"text-classification",
model="ProsusAI/finbert",
device_map="auto" if torch.cuda.is_available() else "cpu",
max_length=128,
truncation=True
)
print("βœ… Financial sentiment model loaded")
except:
print("⚠️ Could not load FinBERT, using smaller model")
self.sentiment_model = pipeline(
"sentiment-analysis",
model="distilbert-base-uncased-finetuned-sst-2-english",
device_map="auto" if torch.cuda.is_available() else "cpu"
)
# 2. Mini summarizer (skip to save memory)
self.summarizer = None
print("⚠️ Summarization model skipped to save memory")
# 3. Lightweight embeddings
try:
self.embedder = SentenceTransformer('all-MiniLM-L6-v2')
print("βœ… Embeddings model loaded")
except:
self.embedder = None
# 4. Text generation (skip to save memory)
self.text_generator = None
self.models_loaded = True
print("πŸŽ‰ All models loaded successfully!")
except Exception as e:
print(f"⚠️ Model loading failed: {e}")
print("Running in data-only mode")
self.models_loaded = False
def fetch_company_data(self, ticker):
"""Fetch and cache company data"""
cache_key = f"{ticker}_{datetime.now().strftime('%Y%m%d')}"
if cache_key in self.company_cache:
return self.company_cache[cache_key]
try:
print(f"πŸ“₯ Fetching data for {ticker}...")
stock = yf.Ticker(ticker)
# Basic info with timeout protection
info = stock.info
# Get essential financials
data = {
'ticker': ticker,
'info': info,
'balance_sheet': stock.balance_sheet,
'income_statement': stock.financials,
'cash_flow': stock.cashflow,
'history_1y': stock.history(period="1y"),
'history_5y': stock.history(period="5y"),
'dividends': stock.dividends,
'news': getattr(stock, 'news', [])[:5] # Limit news to save memory
}
# Calculate key metrics
data['metrics'] = self.calculate_key_metrics(data)
# Cache for today
self.company_cache[cache_key] = data
return data
except Exception as e:
print(f"Error fetching data for {ticker}: {e}")
return {'error': str(e), 'ticker': ticker}
def calculate_key_metrics(self, data):
"""Calculate essential financial metrics"""
metrics = {}
try:
info = data.get('info', {})
inc = data.get('income_statement', pd.DataFrame())
bal = data.get('balance_sheet', pd.DataFrame())
if not inc.empty and not bal.empty:
# Latest period data
if len(inc.columns) > 0:
latest_inc = inc.iloc[:, 0]
if len(bal.columns) > 0:
latest_bal = bal.iloc[:, 0]
# Profitability
if 'Total Revenue' in latest_inc.index and latest_inc['Total Revenue'] != 0:
if 'Net Income' in latest_inc.index:
metrics['net_margin'] = (latest_inc['Net Income'] / latest_inc['Total Revenue'] * 100)
# ROE
if 'Total Stockholder Equity' in latest_bal.index and latest_bal['Total Stockholder Equity'] != 0:
if 'Net Income' in latest_inc.index:
metrics['roe'] = (latest_inc['Net Income'] / latest_bal['Total Stockholder Equity'] * 100)
# Liquidity
if 'Total Current Assets' in latest_bal.index and 'Total Current Liabilities' in latest_bal.index:
if latest_bal['Total Current Liabilities'] != 0:
metrics['current_ratio'] = (latest_bal['Total Current Assets'] / latest_bal['Total Current Liabilities'])
# Leverage
if 'Total Liab' in latest_bal.index and 'Total Stockholder Equity' in latest_bal.index:
if latest_bal['Total Stockholder Equity'] != 0:
metrics['debt_to_equity'] = (latest_bal['Total Liab'] / latest_bal['Total Stockholder Equity'])
# Market metrics
if info:
metrics['pe_ratio'] = info.get('trailingPE', 'N/A')
metrics['pb_ratio'] = info.get('priceToBook', 'N/A')
metrics['dividend_yield'] = info.get('dividendYield', 0) * 100 if info.get('dividendYield') else 0
metrics['market_cap'] = info.get('marketCap', 'N/A')
metrics['beta'] = info.get('beta', 'N/A')
except Exception as e:
print(f"Error calculating metrics: {e}")
return metrics
def create_dashboard(self, ticker, data):
"""Create interactive Plotly dashboard"""
try:
metrics = data.get('metrics', {})
history = data.get('history_1y', pd.DataFrame())
# Create subplots
from plotly.subplots import make_subplots
fig = make_subplots(
rows=2, cols=2,
subplot_titles=(
'πŸ“ˆ Price Trend',
'πŸ’° Key Metrics',
'πŸ“Š Financial Health',
'🎯 Recommendation'
),
specs=[
[{"type": "scatter"}, {"type": "bar"}],
[{"type": "indicator"}, {"type": "indicator"}]
],
vertical_spacing=0.2,
horizontal_spacing=0.15
)
# 1. Price Trend
if not history.empty:
fig.add_trace(
go.Scatter(
x=history.index,
y=history['Close'],
mode='lines',
name='Price',
line=dict(color='#2E86AB', width=2),
fill='tozeroy',
fillcolor='rgba(46, 134, 171, 0.1)'
),
row=1, col=1
)
# Add moving average
if len(history) > 20:
ma20 = history['Close'].rolling(window=20).mean()
fig.add_trace(
go.Scatter(
x=history.index,
y=ma20,
mode='lines',
name='MA20',
line=dict(color='#F18F01', width=1, dash='dash')
),
row=1, col=1
)
fig.update_xaxes(title_text="Date", row=1, col=1)
fig.update_yaxes(title_text="Price ($)", row=1, col=1)
# 2. Key Metrics Bar Chart
if metrics:
metric_keys = ['roe', 'net_margin', 'current_ratio', 'debt_to_equity']
metric_labels = ['ROE %', 'Net Margin %', 'Current Ratio', 'Debt/Equity']
metric_values = []
metric_colors = []
for key in metric_keys:
val = metrics.get(key, 0)
if isinstance(val, (int, float)):
metric_values.append(val)
# Color coding
if key == 'roe':
metric_colors.append('#2E86AB' if val > 15 else '#A23B72' if val > 8 else '#C73E1D')
elif key == 'net_margin':
metric_colors.append('#2E86AB' if val > 10 else '#A23B72' if val > 5 else '#C73E1D')
elif key == 'current_ratio':
metric_colors.append('#2E86AB' if val > 1.5 else '#A23B72' if val > 1 else '#C73E1D')
elif key == 'debt_to_equity':
metric_colors.append('#2E86AB' if val < 1 else '#A23B72' if val < 2 else '#C73E1D')
else:
metric_values.append(0)
metric_colors.append('#CCCCCC')
fig.add_trace(
go.Bar(
x=metric_labels,
y=metric_values,
marker_color=metric_colors,
text=[f'{v:.1f}' if isinstance(v, (int, float)) else 'N/A' for v in metric_values],
textposition='auto',
name='Metrics'
),
row=1, col=2
)
fig.update_xaxes(title_text="Metrics", row=1, col=2, tickangle=45)
fig.update_yaxes(title_text="Value", row=1, col=2)
# 3. Financial Health Gauge
health_score = self.calculate_health_score(metrics)
fig.add_trace(
go.Indicator(
mode="gauge+number",
value=health_score,
title={'text': "Financial Health"},
gauge={
'axis': {'range': [None, 10]},
'bar': {'color': "darkblue"},
'steps': [
{'range': [0, 3], 'color': "red"},
{'range': [3, 7], 'color': "yellow"},
{'range': [7, 10], 'color': "green"}
],
'threshold': {
'line': {'color': "black", 'width': 4},
'thickness': 0.75,
'value': health_score
}
}
),
row=2, col=1
)
# 4. Recommendation Indicator
recommendation = self.generate_recommendation(metrics)
color_map = {
'Strong Buy': 'green',
'Buy': 'lightgreen',
'Hold': 'yellow',
'Sell': 'orange',
'Strong Sell': 'red'
}
fig.add_trace(
go.Indicator(
mode="number",
value=health_score,
title={'text': f"Recommendation: {recommendation}"},
number={'font': {'color': color_map.get(recommendation, 'black'), 'size': 24}},
domain={'row': 2, 'column': 2}
),
row=2, col=2
)
# Update layout
fig.update_layout(
height=700,
showlegend=True,
title_text=f"πŸ“Š Financial Dashboard - {ticker}",
title_font_size=20,
template="plotly_white"
)
return fig
except Exception as e:
print(f"Error creating dashboard: {e}")
# Return simple figure
fig = go.Figure()
fig.add_annotation(
text="Dashboard generation failed<br>Try a different ticker",
xref="paper", yref="paper",
x=0.5, y=0.5,
showarrow=False,
font_size=16,
align="center"
)
fig.update_layout(
title=f"Error for {ticker}",
height=400
)
return fig
def calculate_health_score(self, metrics):
"""Calculate financial health score (1-10)"""
score = 5.0 # Start at neutral
try:
# ROE contribution
roe = metrics.get('roe', 0)
if isinstance(roe, (int, float)):
if roe > 20:
score += 2
elif roe > 10:
score += 1
elif roe < 5:
score -= 1
# Net Margin contribution
margin = metrics.get('net_margin', 0)
if isinstance(margin, (int, float)):
if margin > 15:
score += 1.5
elif margin > 5:
score += 0.5
elif margin < 0:
score -= 1.5
# Liquidity contribution
current = metrics.get('current_ratio', 0)
if isinstance(current, (int, float)):
if current > 2:
score += 1
elif current < 1:
score -= 1
# Leverage contribution
debt_eq = metrics.get('debt_to_equity', 0)
if isinstance(debt_eq, (int, float)):
if debt_eq > 2:
score -= 1.5
elif debt_eq < 0.5:
score += 0.5
# Cap score between 1 and 10
score = max(1, min(10, score))
except:
pass
return round(score, 1)
def generate_recommendation(self, metrics):
"""Generate investment recommendation"""
score = self.calculate_health_score(metrics)
if score >= 8:
return "Strong Buy"
elif score >= 6:
return "Buy"
elif score >= 4:
return "Hold"
elif score >= 2:
return "Sell"
else:
return "Strong Sell"
def generate_ai_analysis(self, ticker, data):
"""Generate AI analysis of company"""
try:
metrics = data.get('metrics', {})
# Create analysis
analysis = f"""
## πŸ€– AI Analysis for {ticker}
### πŸ“Š Key Metrics Analysis:
"""
# Add metric analysis
metric_analysis = {
'roe': "Return on Equity measures how effectively management is using shareholders' funds.",
'net_margin': "Net Profit Margin shows what percentage of revenue is actual profit.",
'current_ratio': "Current Ratio indicates short-term liquidity and ability to pay debts.",
'debt_to_equity': "Debt-to-Equity ratio shows the company's financial leverage."
}
for key, desc in metric_analysis.items():
val = metrics.get(key, 'N/A')
if isinstance(val, (int, float)):
analysis += f"**{key.replace('_', ' ').title()}**: {val:.1f} - {desc}\n\n"
# Add overall assessment
health_score = self.calculate_health_score(metrics)
recommendation = self.generate_recommendation(metrics)
analysis += f"""
### πŸ₯ Financial Health Score: **{health_score}/10**
### 🎯 Recommendation: **{recommendation}**
### πŸ“ˆ Market Outlook:
"""
# Add simple outlook based on metrics
if health_score >= 7:
analysis += "The company shows strong financial fundamentals with good profitability and manageable leverage."
elif health_score >= 5:
analysis += "The company has average financial health with room for improvement in some areas."
else:
analysis += "The company shows concerning financial metrics that warrant caution."
analysis += "\n\n*Note: This analysis is AI-generated for educational purposes only.*"
return analysis
except Exception as e:
return f"Error in AI analysis: {str(e)}"
def create_metrics_table(self, metrics):
"""Create a nice HTML table for metrics"""
if not metrics:
return "<p>No metrics available</p>"
table_html = """
<style>
.metrics-table {
width: 100%;
border-collapse: collapse;
margin: 10px 0;
font-family: Arial, sans-serif;
font-size: 14px;
}
.metrics-table th {
background-color: #2E86AB;
color: white;
padding: 10px;
text-align: left;
font-weight: bold;
}
.metrics-table td {
padding: 8px 10px;
border-bottom: 1px solid #ddd;
}
.metrics-table tr:hover {
background-color: #f5f5f5;
}
.good { color: #28a745; font-weight: bold; }
.warning { color: #ffc107; font-weight: bold; }
.poor { color: #dc3545; font-weight: bold; }
</style>
<table class="metrics-table">
<tr>
<th>Metric</th>
<th>Value</th>
<th>Assessment</th>
</tr>
"""
for key, value in metrics.items():
if isinstance(value, (int, float)):
# Format value
if 'margin' in key or 'roe' in key or 'yield' in key:
display_value = f"{value:.1f}%"
elif 'ratio' in key or 'beta' in key:
display_value = f"{value:.2f}"
else:
display_value = f"{value:,.0f}" if value > 1000 else f"{value:.1f}"
# Determine assessment
assessment = ""
css_class = ""
if key == 'roe':
if value > 15:
assessment = "Excellent"
css_class = "good"
elif value > 8:
assessment = "Good"
css_class = "good"
elif value > 0:
assessment = "Poor"
css_class = "warning"
else:
assessment = "Negative"
css_class = "poor"
elif key == 'net_margin':
if value > 15:
assessment = "Excellent"
css_class = "good"
elif value > 5:
assessment = "Good"
css_class = "good"
elif value > 0:
assessment = "Low"
css_class = "warning"
else:
assessment = "Negative"
css_class = "poor"
elif key == 'current_ratio':
if value > 2:
assessment = "Very Liquid"
css_class = "good"
elif value > 1:
assessment = "Adequate"
css_class = "good"
else:
assessment = "Risk"
css_class = "warning"
elif key == 'debt_to_equity':
if value < 0.5:
assessment = "Low Leverage"
css_class = "good"
elif value < 1:
assessment = "Moderate"
elif value < 2:
assessment = "High"
css_class = "warning"
else:
assessment = "Very High"
css_class = "poor"
elif key == 'pe_ratio' and isinstance(value, (int, float)):
if value < 15:
assessment = "Undervalued"
css_class = "good"
elif value < 25:
assessment = "Fair"
else:
assessment = "Overvalued"
css_class = "warning"
elif key == 'dividend_yield' and isinstance(value, (int, float)):
if value > 4:
assessment = "High Yield"
css_class = "good"
elif value > 2:
assessment = "Moderate"
else:
assessment = "Low"
table_html += f"""
<tr>
<td>{key.replace('_', ' ').title()}</td>
<td>{display_value}</td>
<td class="{css_class}">{assessment}</td>
</tr>
"""
table_html += "</table>"
return table_html
# Initialize agent
agent = FinancialSpacesAgent()
# Create Gradio interface functions
def analyze_company_gradio(ticker):
"""Main Gradio analysis function"""
if not ticker:
return "Please enter a ticker symbol", None, "", ""
ticker = ticker.upper().strip()
# Fetch data
data = agent.fetch_company_data(ticker)
if 'error' in data:
return f"❌ Error: {data['error']}", None, "", ""
# Generate analysis
analysis = agent.generate_ai_analysis(ticker, data)
# Create dashboard
dashboard = agent.create_dashboard(ticker, data)
# Create metrics table
metrics_table = agent.create_metrics_table(data.get('metrics', {}))
# Basic info
info = data.get('info', {})
basic_info = f"""
### πŸ“‹ Company Overview
**Name:** {info.get('longName', 'N/A')}
**Sector:** {info.get('sector', 'N/A')}
**Industry:** {info.get('industry', 'N/A')}
**Market Cap:** ${info.get('marketCap', 'N/A'):,}
**Current Price:** ${info.get('currentPrice', 'N/A')}
**52W High:** ${info.get('fiftyTwoWeekHigh', 'N/A')}
**52W Low:** ${info.get('fiftyTwoWeekLow', 'N/A')}
**Beta:** {info.get('beta', 'N/A')}
"""
return analysis, dashboard, metrics_table, basic_info
def compare_companies_gradio(ticker1, ticker2):
"""Compare two companies"""
if not ticker1 or not ticker2:
return "Please enter both ticker symbols", None
data1 = agent.fetch_company_data(ticker1.upper())
data2 = agent.fetch_company_data(ticker2.upper())
if 'error' in data1 or 'error' in data2:
return "Error fetching data for one or both companies.", None
metrics1 = data1.get('metrics', {})
metrics2 = data2.get('metrics', {})
# Create comparison table
comparison_metrics = ['roe', 'net_margin', 'current_ratio', 'debt_to_equity', 'pe_ratio', 'dividend_yield']
comparison_data = []
for metric in comparison_metrics:
val1 = metrics1.get(metric, 'N/A')
val2 = metrics2.get(metric, 'N/A')
comparison_data.append({
'Metric': metric.replace('_', ' ').title(),
ticker1: f"{val1:.2f}" if isinstance(val1, (int, float)) else val1,
ticker2: f"{val2:.2f}" if isinstance(val2, (int, float)) else val2
})
# Create comparison chart
fig = go.Figure()
# Get values for first 4 metrics
metric_keys = comparison_metrics[:4]
ticker1_vals = []
ticker2_vals = []
for metric in metric_keys:
val1 = metrics1.get(metric, 0)
val2 = metrics2.get(metric, 0)
if isinstance(val1, (int, float)) and isinstance(val2, (int, float)):
ticker1_vals.append(val1)
ticker2_vals.append(val2)
if ticker1_vals and ticker2_vals:
x_labels = [m.replace('_', ' ').title() for m in metric_keys[:len(ticker1_vals)]]
fig.add_trace(go.Bar(
name=ticker1,
x=x_labels,
y=ticker1_vals,
marker_color='#2E86AB'
))
fig.add_trace(go.Bar(
name=ticker2,
x=x_labels,
y=ticker2_vals,
marker_color='#F18F01'
))
fig.update_layout(
title=f"{ticker1} vs {ticker2} - Key Metrics Comparison",
barmode='group',
template="plotly_white",
height=400
)
# Create comparison text
comparison_text = f"## βš–οΈ {ticker1} vs {ticker2}\n\n"
comparison_text += "| Metric | " + ticker1 + " | " + ticker2 + " |\n"
comparison_text += "|--------|" + "-" * (len(ticker1) + 2) + "|" + "-" * (len(ticker2) + 2) + "|\n"
for comp in comparison_data:
comparison_text += f"| {comp['Metric']} | {comp[ticker1]} | {comp[ticker2]} |\n"
return comparison_text, fig
# Create Gradio Blocks interface
with gr.Blocks(
title="Financial Analysis AI Agent",
theme=gr.themes.Soft(primary_hue="blue"),
css="""
.gradio-container {max-width: 1200px !important; margin: auto !important;}
.metric-box {background: #f5f5f5; padding: 10px; border-radius: 5px; margin: 5px;}
"""
) as demo:
gr.Markdown("""
# πŸ€– Financial Analysis AI Agent
### Powered by Hugging Face & Yahoo Finance
Analyze any company's financial health using AI-powered insights.
""")
with gr.Tabs():
with gr.TabItem("πŸ“ˆ Company Analysis"):
with gr.Row():
with gr.Column(scale=1):
ticker_input = gr.Textbox(
label="Stock Ticker",
placeholder="AAPL, TSLA, GOOGL, etc.",
value="AAPL"
)
analyze_btn = gr.Button(
"πŸš€ Analyze Company",
variant="primary",
size="lg"
)
gr.Markdown("### πŸ“Š Popular Companies")
with gr.Row():
popular_tickers = ["AAPL", "MSFT", "GOOGL", "TSLA"]
for t in popular_tickers:
btn = gr.Button(t, size="sm")
# FIXED: Only update the ticker input, not other outputs
btn.click(
lambda t=t: t,
inputs=None,
outputs=ticker_input
)
with gr.Column(scale=2):
basic_info = gr.Markdown(label="Company Overview")
with gr.Row():
with gr.Column(scale=2):
plot_output = gr.Plot(label="Financial Dashboard")
with gr.Column(scale=1):
metrics_output = gr.HTML(label="Key Metrics")
with gr.Row():
analysis_output = gr.Markdown(label="AI Analysis Report")
with gr.TabItem("βš–οΈ Compare Companies"):
with gr.Row():
with gr.Column(scale=1):
ticker1_input = gr.Textbox(label="First Company", placeholder="AAPL", value="AAPL")
ticker2_input = gr.Textbox(label="Second Company", placeholder="MSFT", value="MSFT")
compare_btn = gr.Button("βš–οΈ Compare", variant="primary")
with gr.Column(scale=2):
comparison_plot = gr.Plot(label="Comparison Chart")
comparison_output = gr.Markdown(label="Comparison Results")
with gr.TabItem("πŸ“š How to Use"):
gr.Markdown("""
## πŸ“– User Guide
### πŸ” **Company Analysis Tab**
1. Enter a stock ticker symbol (e.g., AAPL for Apple)
2. Click "Analyze Company" or press Enter
3. View the financial dashboard with interactive charts
4. Read the AI-powered analysis
### βš–οΈ **Compare Companies Tab**
1. Enter two company tickers
2. Click "Compare"
3. View side-by-side financial metrics
### πŸ’‘ **Tips for Best Results**
- Use valid stock ticker symbols
- For international stocks, add exchange suffix (e.g., TSLA for Tesla)
- The AI analyzes available financial data from Yahoo Finance
### ⚠️ **Disclaimer**
- This tool is for **educational purposes only**
- Not financial advice
- Always do your own research before investing
- Data may have delays or inaccuracies
### πŸ› οΈ **Technical Details**
- **Data Source**: Yahoo Finance (free API)
- **AI Models**: Hugging Face transformers
- **Visualization**: Plotly interactive charts
- **Hosting**: Hugging Face Spaces
### πŸ› **Troubleshooting**
If a company isn't found:
1. Check the ticker symbol is correct
2. Try adding exchange suffix (e.g., .NS for NSE India)
3. Some companies may not have complete financial data
---
*Made with ❀️ for the financial analysis community*
""")
with gr.TabItem("ℹ️ About"):
gr.Markdown(f"""
## About This App
### πŸ€– **AI-Powered Financial Analysis**
This application uses state-of-the-art AI models from Hugging Face to analyze company financials.
### πŸ“Š **Features Included:**
- **Real-time Financial Data** from Yahoo Finance
- **AI Analysis** using financial NLP models
- **Interactive Dashboards** with Plotly
- **Company Comparison** tools
- **Financial Health Scoring**
### πŸ—οΈ **Technology Stack:**
- **Backend**: Python, Hugging Face Transformers
- **Frontend**: Gradio for interactive UI
- **Data**: Yahoo Finance API
- **Visualization**: Plotly, Matplotlib
### πŸš€ **Model Status:** {'βœ… Loaded' if agent.models_loaded else '⚠️ Limited Mode'}
### πŸ“ˆ **Data Coverage:**
- US Stocks: Full coverage
- International Stocks: Limited (depends on Yahoo Finance)
- Cryptocurrencies: Supported (e.g., BTC-USD)
### ⚠️ **Limitations:**
- Free tier has rate limits
- Some companies may have incomplete data
- AI analysis is probabilistic, not deterministic
### πŸ‘¨β€πŸ’» **Open Source**
This project is open source. Contributions welcome!
### πŸ“ž **Support**
For issues or feature requests, please open an issue on the GitHub repository.
---
**Version 1.0** | **Last Updated**: {datetime.now().strftime('%Y-%m-%d')}
""")
# Connect events
analyze_btn.click(
analyze_company_gradio,
inputs=ticker_input,
outputs=[analysis_output, plot_output, metrics_output, basic_info]
)
ticker_input.submit(
analyze_company_gradio,
inputs=ticker_input,
outputs=[analysis_output, plot_output, metrics_output, basic_info]
)
compare_btn.click(
compare_companies_gradio,
inputs=[ticker1_input, ticker2_input],
outputs=[comparison_output, comparison_plot]
)
# Auto-load example on startup
demo.load(
lambda: analyze_company_gradio("AAPL"),
inputs=None,
outputs=[analysis_output, plot_output, metrics_output, basic_info]
)
# For Hugging Face Spaces
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
show_error=True,
debug=False # Disable debug mode for production
)