Spaces:
Sleeping
Sleeping
Download app.py from Sujatha/FinSight_AI: direct link, hf CLI and curl.
- Browser
- Download file 34.3 kB
-
https://huggingface.co/spaces/Sujatha/FinSight_AI/resolve/main/app.py
- Command line
-
hf download hf://spaces/Sujatha/FinSight_AI/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Sujatha/FinSight_AI/resolve/main/app.py
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 | |
| ) |