Start-Up_Viability_Agent / market_intelligence_dashboard.py
Navada25's picture
Update market_intelligence_dashboard.py - Voice Streaming & AI Coaching Features
54a17ba verified
"""
Real-time Market Intelligence Dashboard for NAVADA
Provides comprehensive market data, trends, and competitive intelligence
"""
import asyncio
import json
import logging
import os
from typing import Dict, Any, List, Optional
from datetime import datetime, timedelta
import yfinance as yf
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import requests
from openai import AsyncOpenAI
logger = logging.getLogger(__name__)
class MarketIntelligenceEngine:
"""Core engine for gathering and analyzing market intelligence data"""
def __init__(self):
self.client = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))
self.search_api_key = os.getenv("SEARCH_API_KEY")
self.data_cache = {}
self.cache_expiry = {}
async def get_market_overview(self, sector: str = "technology") -> Dict[str, Any]:
"""Get comprehensive market overview for a specific sector"""
try:
cache_key = f"market_overview_{sector}"
if self._is_cache_valid(cache_key):
return self.data_cache[cache_key]
# Get major sector ETFs and indices
sector_symbols = self._get_sector_symbols(sector)
market_data = {}
for symbol, name in sector_symbols.items():
try:
ticker = yf.Ticker(symbol)
hist = ticker.history(period="1y")
info = ticker.info
if not hist.empty:
current_price = hist['Close'].iloc[-1]
ytd_change = ((current_price - hist['Close'].iloc[0]) / hist['Close'].iloc[0]) * 100
market_data[symbol] = {
"name": name,
"current_price": float(current_price),
"ytd_change": float(ytd_change),
"volume": float(hist['Volume'].iloc[-1]),
"market_cap": info.get('totalAssets', 0),
"52_week_high": float(hist['High'].max()),
"52_week_low": float(hist['Low'].min())
}
except Exception as e:
logger.warning(f"Error fetching data for {symbol}: {e}")
continue
# Generate market insights using AI
market_insights = await self._generate_market_insights(market_data, sector)
result = {
"sector": sector,
"timestamp": datetime.now().isoformat(),
"market_data": market_data,
"insights": market_insights,
"total_symbols": len(market_data)
}
self._cache_data(cache_key, result, hours=1)
return result
except Exception as e:
logger.error(f"Error getting market overview: {e}")
return {"status": "error", "message": str(e)}
def _get_sector_symbols(self, sector: str) -> Dict[str, str]:
"""Get relevant ETF and index symbols for a sector"""
sector_mappings = {
"technology": {
"QQQ": "NASDAQ-100 Technology",
"XLK": "Technology Select Sector SPDR",
"VGT": "Vanguard Information Technology ETF",
"SOXX": "iShares Semiconductor ETF",
"ARKK": "ARK Innovation ETF"
},
"healthcare": {
"XLV": "Health Care Select Sector SPDR",
"VHT": "Vanguard Health Care ETF",
"IBB": "iShares Biotechnology ETF",
"XBI": "SPDR Biotech ETF"
},
"finance": {
"XLF": "Financial Select Sector SPDR",
"VFH": "Vanguard Financials ETF",
"KBE": "SPDR Banking ETF",
"KRE": "SPDR Regional Banking ETF"
},
"energy": {
"XLE": "Energy Select Sector SPDR",
"VDE": "Vanguard Energy ETF",
"XOP": "SPDR Oil & Gas Exploration ETF",
"ICLN": "iShares Clean Energy ETF"
},
"retail": {
"XRT": "SPDR Retail ETF",
"RTH": "VanEck Retail ETF",
"ONLN": "ProShares Online Retail ETF",
"XLY": "Consumer Discretionary SPDR"
}
}
return sector_mappings.get(sector, sector_mappings["technology"])
async def _generate_market_insights(self, market_data: Dict, sector: str) -> str:
"""Generate AI-powered insights from market data"""
try:
system_prompt = f"""
You are a senior market analyst providing insights on the {sector} sector.
Analyze the provided market data and generate 3-4 key insights covering:
1. Overall sector performance and trends
2. Notable winners and losers
3. Market sentiment and outlook
4. Potential opportunities or risks
Keep insights concise, data-driven, and actionable for startup founders.
"""
user_prompt = f"""
Sector: {sector}
Market Data Summary:
{json.dumps(market_data, indent=2)}
Provide professional market analysis with specific insights for startup founders in this sector.
"""
response = await self.client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
max_tokens=400,
temperature=0.3
)
return response.choices[0].message.content
except Exception as e:
logger.error(f"Error generating market insights: {e}")
return "Market insights temporarily unavailable."
async def get_competitive_landscape(self, company_name: str, industry: str) -> Dict[str, Any]:
"""Analyze competitive landscape for a specific company/industry"""
try:
cache_key = f"competitive_{company_name}_{industry}"
if self._is_cache_valid(cache_key):
return self.data_cache[cache_key]
# Get industry leaders and competitors
competitors = await self._identify_competitors(company_name, industry)
competitive_data = {}
for competitor in competitors[:10]: # Limit to top 10
try:
ticker = yf.Ticker(competitor["symbol"])
info = ticker.info
hist = ticker.history(period="1y")
if not hist.empty:
competitive_data[competitor["symbol"]] = {
"name": competitor["name"],
"market_cap": info.get('marketCap', 0),
"revenue": info.get('totalRevenue', 0),
"employees": info.get('fullTimeEmployees', 0),
"pe_ratio": info.get('trailingPE', 0),
"profit_margin": info.get('profitMargins', 0),
"revenue_growth": info.get('revenueGrowth', 0),
"current_price": float(hist['Close'].iloc[-1]),
"ytd_performance": ((hist['Close'].iloc[-1] - hist['Close'].iloc[0]) / hist['Close'].iloc[0]) * 100
}
except Exception as e:
logger.warning(f"Error fetching competitor data for {competitor}: {e}")
continue
# Generate competitive analysis
analysis = await self._generate_competitive_analysis(competitive_data, company_name, industry)
result = {
"company": company_name,
"industry": industry,
"timestamp": datetime.now().isoformat(),
"competitors": competitive_data,
"analysis": analysis,
"market_leaders": self._identify_market_leaders(competitive_data)
}
self._cache_data(cache_key, result, hours=6)
return result
except Exception as e:
logger.error(f"Error getting competitive landscape: {e}")
return {"status": "error", "message": str(e)}
async def _identify_competitors(self, company_name: str, industry: str) -> List[Dict[str, str]]:
"""Identify key competitors using AI and market data"""
try:
# Use AI to identify competitors
system_prompt = """
You are a market research analyst. Identify the top public competitors for the given company and industry.
Return a JSON list of competitors with their stock symbols and full company names.
Format: [{"symbol": "AAPL", "name": "Apple Inc."}, ...]
Focus on direct competitors that are publicly traded.
"""
user_prompt = f"""
Company: {company_name}
Industry: {industry}
Identify 8-12 key public competitors with their stock symbols.
"""
response = await self.client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
max_tokens=300,
temperature=0.3
)
try:
competitors = json.loads(response.choices[0].message.content)
return competitors if isinstance(competitors, list) else []
except json.JSONDecodeError:
logger.warning("Failed to parse competitors JSON")
return []
except Exception as e:
logger.error(f"Error identifying competitors: {e}")
return []
async def _generate_competitive_analysis(self, competitive_data: Dict, company_name: str, industry: str) -> str:
"""Generate AI-powered competitive analysis"""
try:
system_prompt = f"""
You are a senior business analyst providing competitive intelligence for {company_name} in the {industry} industry.
Analyze the competitive landscape and provide insights on:
1. Market positioning and differentiation opportunities
2. Financial performance benchmarks
3. Strategic threats and opportunities
4. Market dynamics and trends
Be specific and actionable for startup strategy.
"""
user_prompt = f"""
Company: {company_name}
Industry: {industry}
Competitive Data:
{json.dumps(competitive_data, indent=2)}
Provide strategic competitive analysis with actionable insights.
"""
response = await self.client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
max_tokens=500,
temperature=0.3
)
return response.choices[0].message.content
except Exception as e:
logger.error(f"Error generating competitive analysis: {e}")
return "Competitive analysis temporarily unavailable."
def _identify_market_leaders(self, competitive_data: Dict) -> List[Dict[str, Any]]:
"""Identify market leaders based on key metrics"""
try:
if not competitive_data:
return []
# Sort by market cap and revenue
sorted_by_market_cap = sorted(
competitive_data.items(),
key=lambda x: x[1].get('market_cap', 0),
reverse=True
)
leaders = []
for symbol, data in sorted_by_market_cap[:5]:
leaders.append({
"symbol": symbol,
"name": data.get('name', symbol),
"market_cap": data.get('market_cap', 0),
"revenue": data.get('revenue', 0),
"market_position": "Leader" if len(leaders) == 0 else "Major Player"
})
return leaders
except Exception as e:
logger.error(f"Error identifying market leaders: {e}")
return []
async def get_trend_analysis(self, keywords: List[str], timeframe: str = "1y") -> Dict[str, Any]:
"""Analyze market trends for specific keywords/topics"""
try:
cache_key = f"trends_{'_'.join(keywords)}_{timeframe}"
if self._is_cache_valid(cache_key):
return self.data_cache[cache_key]
# Analyze related stocks and ETFs
trend_data = {}
for keyword in keywords:
related_symbols = await self._find_related_symbols(keyword)
keyword_performance = {}
for symbol in related_symbols[:5]: # Top 5 related symbols
try:
ticker = yf.Ticker(symbol)
hist = ticker.history(period=timeframe)
if not hist.empty:
performance = ((hist['Close'].iloc[-1] - hist['Close'].iloc[0]) / hist['Close'].iloc[0]) * 100
keyword_performance[symbol] = {
"performance": float(performance),
"volatility": float(hist['Close'].std()),
"volume_avg": float(hist['Volume'].mean())
}
except Exception as e:
logger.warning(f"Error analyzing {symbol}: {e}")
continue
trend_data[keyword] = keyword_performance
# Generate trend insights
insights = await self._generate_trend_insights(trend_data, keywords, timeframe)
result = {
"keywords": keywords,
"timeframe": timeframe,
"timestamp": datetime.now().isoformat(),
"trend_data": trend_data,
"insights": insights
}
self._cache_data(cache_key, result, hours=2)
return result
except Exception as e:
logger.error(f"Error getting trend analysis: {e}")
return {"status": "error", "message": str(e)}
async def _find_related_symbols(self, keyword: str) -> List[str]:
"""Find stock symbols related to a keyword"""
# This is a simplified implementation
# In production, you might use more sophisticated symbol mapping
keyword_mappings = {
"ai": ["NVDA", "GOOGL", "MSFT", "AMD", "INTC"],
"cloud": ["AMZN", "MSFT", "GOOGL", "CRM", "SNOW"],
"fintech": ["SQ", "PYPL", "V", "MA", "COIN"],
"biotech": ["GILD", "AMGN", "BIIB", "REGN", "VRTX"],
"ev": ["TSLA", "F", "GM", "NIO", "RIVN"],
"crypto": ["COIN", "MSTR", "RIOT", "MARA", "HOOD"]
}
return keyword_mappings.get(keyword.lower(), ["SPY"])
async def _generate_trend_insights(self, trend_data: Dict, keywords: List[str], timeframe: str) -> str:
"""Generate AI insights about market trends"""
try:
system_prompt = f"""
You are a market trend analyst providing insights on emerging trends and market dynamics.
Analyze the trend data for the keywords: {', '.join(keywords)} over {timeframe}.
Provide insights on:
1. Overall trend momentum and direction
2. Investment themes and opportunities
3. Risk factors and market dynamics
4. Implications for startups in these sectors
Keep insights concise and actionable.
"""
user_prompt = f"""
Keywords: {keywords}
Timeframe: {timeframe}
Trend Performance Data:
{json.dumps(trend_data, indent=2)}
Provide trend analysis with startup implications.
"""
response = await self.client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
max_tokens=400,
temperature=0.3
)
return response.choices[0].message.content
except Exception as e:
logger.error(f"Error generating trend insights: {e}")
return "Trend insights temporarily unavailable."
def _is_cache_valid(self, cache_key: str) -> bool:
"""Check if cached data is still valid"""
if cache_key not in self.cache_expiry:
return False
return datetime.now() < self.cache_expiry[cache_key]
def _cache_data(self, cache_key: str, data: Any, hours: int = 1):
"""Cache data with expiry"""
self.data_cache[cache_key] = data
self.cache_expiry[cache_key] = datetime.now() + timedelta(hours=hours)
class DashboardVisualizer:
"""Creates interactive visualizations for market intelligence dashboard"""
def __init__(self):
self.theme_colors = {
"primary": "#667eea",
"secondary": "#764ba2",
"success": "#4CAF50",
"danger": "#f44336",
"warning": "#ff9800",
"info": "#2196F3"
}
def create_market_overview_chart(self, market_data: Dict[str, Any]) -> str:
"""Create market overview visualization"""
try:
symbols = list(market_data["market_data"].keys())
names = [data["name"] for data in market_data["market_data"].values()]
ytd_changes = [data["ytd_change"] for data in market_data["market_data"].values()]
# Create bar chart
fig = go.Figure()
colors = [self.theme_colors["success"] if change >= 0 else self.theme_colors["danger"]
for change in ytd_changes]
fig.add_trace(go.Bar(
x=symbols,
y=ytd_changes,
text=[f"{change:.1f}%" for change in ytd_changes],
textposition='auto',
marker_color=colors,
hovertemplate='<b>%{x}</b><br>YTD Change: %{y:.1f}%<extra></extra>'
))
fig.update_layout(
title=f"{market_data['sector'].title()} Sector Performance (YTD)",
xaxis_title="ETFs/Indices",
yaxis_title="YTD Change (%)",
template="plotly_white",
font=dict(family="Inter, sans-serif"),
height=400
)
return fig.to_html(include_plotlyjs=True, div_id="market-overview-chart")
except Exception as e:
logger.error(f"Error creating market overview chart: {e}")
return "<div>Error creating market overview chart</div>"
def create_competitive_comparison(self, competitive_data: Dict[str, Any]) -> str:
"""Create competitive landscape comparison"""
try:
competitors = competitive_data["competitors"]
if not competitors:
return "<div>No competitive data available</div>"
# Create subplot with multiple metrics
fig = make_subplots(
rows=2, cols=2,
subplot_titles=('Market Cap', 'Revenue Growth', 'Profit Margin', 'P/E Ratio'),
specs=[[{"secondary_y": False}, {"secondary_y": False}],
[{"secondary_y": False}, {"secondary_y": False}]]
)
symbols = list(competitors.keys())
market_caps = [competitors[s].get('market_cap', 0) / 1e9 for s in symbols] # In billions
revenue_growth = [competitors[s].get('revenue_growth', 0) * 100 for s in symbols]
profit_margins = [competitors[s].get('profit_margin', 0) * 100 for s in symbols]
pe_ratios = [competitors[s].get('pe_ratio', 0) for s in symbols]
# Market Cap
fig.add_trace(go.Bar(x=symbols, y=market_caps, name="Market Cap (B)",
marker_color=self.theme_colors["primary"]), row=1, col=1)
# Revenue Growth
fig.add_trace(go.Bar(x=symbols, y=revenue_growth, name="Revenue Growth (%)",
marker_color=self.theme_colors["success"]), row=1, col=2)
# Profit Margin
fig.add_trace(go.Bar(x=symbols, y=profit_margins, name="Profit Margin (%)",
marker_color=self.theme_colors["info"]), row=2, col=1)
# P/E Ratio
fig.add_trace(go.Bar(x=symbols, y=pe_ratios, name="P/E Ratio",
marker_color=self.theme_colors["warning"]), row=2, col=2)
fig.update_layout(
title="Competitive Landscape Analysis",
template="plotly_white",
font=dict(family="Inter, sans-serif"),
height=600,
showlegend=False
)
return fig.to_html(include_plotlyjs=True, div_id="competitive-chart")
except Exception as e:
logger.error(f"Error creating competitive comparison: {e}")
return "<div>Error creating competitive comparison</div>"
def create_trend_heatmap(self, trend_data: Dict[str, Any]) -> str:
"""Create trend analysis heatmap"""
try:
keywords = trend_data["keywords"]
trends = trend_data["trend_data"]
if not trends:
return "<div>No trend data available</div>"
# Prepare data for heatmap
symbols = set()
for keyword_data in trends.values():
symbols.update(keyword_data.keys())
symbols = list(symbols)
performance_matrix = []
for keyword in keywords:
row = []
for symbol in symbols:
performance = trends.get(keyword, {}).get(symbol, {}).get('performance', 0)
row.append(performance)
performance_matrix.append(row)
# Create heatmap
fig = go.Figure(data=go.Heatmap(
z=performance_matrix,
x=symbols,
y=keywords,
colorscale='RdYlGn',
text=[[f"{val:.1f}%" for val in row] for row in performance_matrix],
texttemplate="%{text}",
textfont={"size": 10},
hoverongaps=False
))
fig.update_layout(
title=f"Trend Performance Heatmap ({trend_data['timeframe']})",
xaxis_title="Symbols",
yaxis_title="Keywords",
template="plotly_white",
font=dict(family="Inter, sans-serif"),
height=400
)
return fig.to_html(include_plotlyjs=True, div_id="trend-heatmap")
except Exception as e:
logger.error(f"Error creating trend heatmap: {e}")
return "<div>Error creating trend heatmap</div>"
class MarketIntelligenceDashboard:
"""Main dashboard class that orchestrates market intelligence features"""
def __init__(self):
self.engine = MarketIntelligenceEngine()
self.visualizer = DashboardVisualizer()
async def create_dashboard_interface(self) -> str:
"""Create the main dashboard HTML interface"""
return """
<div id="market-intelligence-dashboard" class="dashboard-container">
<div class="dashboard-header">
<h1>📊 Market Intelligence Dashboard</h1>
<p>Real-time market data, competitive intelligence, and trend analysis</p>
</div>
<div class="dashboard-controls">
<div class="control-group">
<label>Sector Analysis:</label>
<select id="sector-select">
<option value="technology">Technology</option>
<option value="healthcare">Healthcare</option>
<option value="finance">Finance</option>
<option value="energy">Energy</option>
<option value="retail">Retail</option>
</select>
<button onclick="loadMarketOverview()" class="dashboard-btn">Analyze Sector</button>
</div>
<div class="control-group">
<label>Competitive Analysis:</label>
<input type="text" id="company-input" placeholder="Company name" />
<input type="text" id="industry-input" placeholder="Industry" />
<button onclick="loadCompetitiveAnalysis()" class="dashboard-btn">Analyze Competition</button>
</div>
<div class="control-group">
<label>Trend Analysis:</label>
<input type="text" id="keywords-input" placeholder="Keywords (comma-separated)" />
<select id="timeframe-select">
<option value="1y">1 Year</option>
<option value="6mo">6 Months</option>
<option value="3mo">3 Months</option>
<option value="1mo">1 Month</option>
</select>
<button onclick="loadTrendAnalysis()" class="dashboard-btn">Analyze Trends</button>
</div>
</div>
<div class="dashboard-content">
<div id="market-overview-section" class="dashboard-section">
<h2>Market Overview</h2>
<div id="market-overview-chart"></div>
<div id="market-insights" class="insights-panel"></div>
</div>
<div id="competitive-section" class="dashboard-section">
<h2>Competitive Landscape</h2>
<div id="competitive-chart"></div>
<div id="competitive-insights" class="insights-panel"></div>
</div>
<div id="trends-section" class="dashboard-section">
<h2>Market Trends</h2>
<div id="trend-heatmap"></div>
<div id="trend-insights" class="insights-panel"></div>
</div>
</div>
<div class="dashboard-footer">
<p>Last updated: <span id="last-updated">Never</span></p>
<button onclick="refreshAllData()" class="refresh-btn">🔄 Refresh All Data</button>
</div>
</div>
<style>
.dashboard-container {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
border-radius: 20px;
padding: 30px;
margin: 20px 0;
font-family: 'Inter', sans-serif;
}
.dashboard-header {
text-align: center;
margin-bottom: 30px;
}
.dashboard-header h1 {
color: #2d3748;
margin-bottom: 10px;
}
.dashboard-controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 30px;
padding: 20px;
background: white;
border-radius: 15px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.control-group {
display: flex;
flex-direction: column;
gap: 10px;
}
.control-group label {
font-weight: 600;
color: #4a5568;
}
.control-group input,
.control-group select {
padding: 10px;
border: 2px solid #e2e8f0;
border-radius: 8px;
font-size: 14px;
}
.dashboard-btn {
padding: 12px 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: opacity 0.3s ease;
}
.dashboard-btn:hover {
opacity: 0.9;
}
.dashboard-content {
display: flex;
flex-direction: column;
gap: 30px;
}
.dashboard-section {
background: white;
border-radius: 15px;
padding: 25px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.dashboard-section h2 {
color: #2d3748;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 2px solid #e2e8f0;
}
.insights-panel {
background: #f7fafc;
border-radius: 10px;
padding: 20px;
margin-top: 20px;
border-left: 4px solid #667eea;
}
.dashboard-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 30px;
padding: 20px;
background: rgba(255, 255, 255, 0.8);
border-radius: 10px;
}
.refresh-btn {
padding: 10px 20px;
background: #4CAF50;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
}
.loading {
text-align: center;
padding: 40px;
color: #718096;
}
.error {
background: #fed7d7;
color: #c53030;
padding: 15px;
border-radius: 8px;
margin: 10px 0;
}
</style>
<script>
async function loadMarketOverview() {
const sector = document.getElementById('sector-select').value;
const chartDiv = document.getElementById('market-overview-chart');
const insightsDiv = document.getElementById('market-insights');
chartDiv.innerHTML = '<div class="loading">Loading market overview...</div>';
insightsDiv.innerHTML = '';
try {
const response = await sendDashboardRequest('market_overview', { sector });
if (response.status === 'success') {
chartDiv.innerHTML = response.chart;
insightsDiv.innerHTML = `<h3>Market Insights</h3><p>${response.insights}</p>`;
updateLastUpdated();
} else {
chartDiv.innerHTML = `<div class="error">Error: ${response.message}</div>`;
}
} catch (error) {
chartDiv.innerHTML = `<div class="error">Error loading market data</div>`;
}
}
async function loadCompetitiveAnalysis() {
const company = document.getElementById('company-input').value;
const industry = document.getElementById('industry-input').value;
if (!company || !industry) {
alert('Please enter both company name and industry');
return;
}
const chartDiv = document.getElementById('competitive-chart');
const insightsDiv = document.getElementById('competitive-insights');
chartDiv.innerHTML = '<div class="loading">Loading competitive analysis...</div>';
insightsDiv.innerHTML = '';
try {
const response = await sendDashboardRequest('competitive_analysis', { company, industry });
if (response.status === 'success') {
chartDiv.innerHTML = response.chart;
insightsDiv.innerHTML = `<h3>Competitive Analysis</h3><p>${response.analysis}</p>`;
updateLastUpdated();
} else {
chartDiv.innerHTML = `<div class="error">Error: ${response.message}</div>`;
}
} catch (error) {
chartDiv.innerHTML = `<div class="error">Error loading competitive data</div>`;
}
}
async function loadTrendAnalysis() {
const keywordsInput = document.getElementById('keywords-input').value;
const timeframe = document.getElementById('timeframe-select').value;
if (!keywordsInput) {
alert('Please enter keywords for trend analysis');
return;
}
const keywords = keywordsInput.split(',').map(k => k.trim());
const chartDiv = document.getElementById('trend-heatmap');
const insightsDiv = document.getElementById('trend-insights');
chartDiv.innerHTML = '<div class="loading">Loading trend analysis...</div>';
insightsDiv.innerHTML = '';
try {
const response = await sendDashboardRequest('trend_analysis', { keywords, timeframe });
if (response.status === 'success') {
chartDiv.innerHTML = response.chart;
insightsDiv.innerHTML = `<h3>Trend Insights</h3><p>${response.insights}</p>`;
updateLastUpdated();
} else {
chartDiv.innerHTML = `<div class="error">Error: ${response.message}</div>`;
}
} catch (error) {
chartDiv.innerHTML = `<div class="error">Error loading trend data</div>`;
}
}
async function refreshAllData() {
await loadMarketOverview();
if (document.getElementById('company-input').value && document.getElementById('industry-input').value) {
await loadCompetitiveAnalysis();
}
if (document.getElementById('keywords-input').value) {
await loadTrendAnalysis();
}
}
async function sendDashboardRequest(type, data) {
if (window.chainlitAPI) {
return await window.chainlitAPI.sendMessage({
type: 'dashboard_request',
request_type: type,
data: data
});
}
throw new Error('Chainlit API not available');
}
function updateLastUpdated() {
document.getElementById('last-updated').textContent = new Date().toLocaleString();
}
// Auto-load technology sector overview on page load
document.addEventListener('DOMContentLoaded', function() {
setTimeout(loadMarketOverview, 1000);
});
</script>
"""
async def handle_dashboard_request(self, request_type: str, data: Dict[str, Any]) -> Dict[str, Any]:
"""Handle different types of dashboard requests"""
try:
if request_type == "market_overview":
sector = data.get("sector", "technology")
market_data = await self.engine.get_market_overview(sector)
if "status" in market_data and market_data["status"] == "error":
return market_data
chart_html = self.visualizer.create_market_overview_chart(market_data)
return {
"status": "success",
"chart": chart_html,
"insights": market_data["insights"],
"data": market_data
}
elif request_type == "competitive_analysis":
company = data.get("company", "")
industry = data.get("industry", "")
competitive_data = await self.engine.get_competitive_landscape(company, industry)
if "status" in competitive_data and competitive_data["status"] == "error":
return competitive_data
chart_html = self.visualizer.create_competitive_comparison(competitive_data)
return {
"status": "success",
"chart": chart_html,
"analysis": competitive_data["analysis"],
"data": competitive_data
}
elif request_type == "trend_analysis":
keywords = data.get("keywords", [])
timeframe = data.get("timeframe", "1y")
trend_data = await self.engine.get_trend_analysis(keywords, timeframe)
if "status" in trend_data and trend_data["status"] == "error":
return trend_data
chart_html = self.visualizer.create_trend_heatmap(trend_data)
return {
"status": "success",
"chart": chart_html,
"insights": trend_data["insights"],
"data": trend_data
}
else:
return {"status": "error", "message": "Unknown request type"}
except Exception as e:
logger.error(f"Error handling dashboard request: {e}")
return {"status": "error", "message": str(e)}