Navada25 commited on
Commit
54a17ba
·
verified ·
1 Parent(s): beb208c

Update market_intelligence_dashboard.py - Voice Streaming & AI Coaching Features

Browse files
Files changed (1) hide show
  1. market_intelligence_dashboard.py +966 -0
market_intelligence_dashboard.py ADDED
@@ -0,0 +1,966 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Real-time Market Intelligence Dashboard for NAVADA
3
+ Provides comprehensive market data, trends, and competitive intelligence
4
+ """
5
+
6
+ import asyncio
7
+ import json
8
+ import logging
9
+ import os
10
+ from typing import Dict, Any, List, Optional
11
+ from datetime import datetime, timedelta
12
+ import yfinance as yf
13
+ import pandas as pd
14
+ import plotly.graph_objects as go
15
+ import plotly.express as px
16
+ from plotly.subplots import make_subplots
17
+ import requests
18
+ from openai import AsyncOpenAI
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ class MarketIntelligenceEngine:
23
+ """Core engine for gathering and analyzing market intelligence data"""
24
+
25
+ def __init__(self):
26
+ self.client = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))
27
+ self.search_api_key = os.getenv("SEARCH_API_KEY")
28
+ self.data_cache = {}
29
+ self.cache_expiry = {}
30
+
31
+ async def get_market_overview(self, sector: str = "technology") -> Dict[str, Any]:
32
+ """Get comprehensive market overview for a specific sector"""
33
+ try:
34
+ cache_key = f"market_overview_{sector}"
35
+ if self._is_cache_valid(cache_key):
36
+ return self.data_cache[cache_key]
37
+
38
+ # Get major sector ETFs and indices
39
+ sector_symbols = self._get_sector_symbols(sector)
40
+
41
+ market_data = {}
42
+ for symbol, name in sector_symbols.items():
43
+ try:
44
+ ticker = yf.Ticker(symbol)
45
+ hist = ticker.history(period="1y")
46
+ info = ticker.info
47
+
48
+ if not hist.empty:
49
+ current_price = hist['Close'].iloc[-1]
50
+ ytd_change = ((current_price - hist['Close'].iloc[0]) / hist['Close'].iloc[0]) * 100
51
+
52
+ market_data[symbol] = {
53
+ "name": name,
54
+ "current_price": float(current_price),
55
+ "ytd_change": float(ytd_change),
56
+ "volume": float(hist['Volume'].iloc[-1]),
57
+ "market_cap": info.get('totalAssets', 0),
58
+ "52_week_high": float(hist['High'].max()),
59
+ "52_week_low": float(hist['Low'].min())
60
+ }
61
+ except Exception as e:
62
+ logger.warning(f"Error fetching data for {symbol}: {e}")
63
+ continue
64
+
65
+ # Generate market insights using AI
66
+ market_insights = await self._generate_market_insights(market_data, sector)
67
+
68
+ result = {
69
+ "sector": sector,
70
+ "timestamp": datetime.now().isoformat(),
71
+ "market_data": market_data,
72
+ "insights": market_insights,
73
+ "total_symbols": len(market_data)
74
+ }
75
+
76
+ self._cache_data(cache_key, result, hours=1)
77
+ return result
78
+
79
+ except Exception as e:
80
+ logger.error(f"Error getting market overview: {e}")
81
+ return {"status": "error", "message": str(e)}
82
+
83
+ def _get_sector_symbols(self, sector: str) -> Dict[str, str]:
84
+ """Get relevant ETF and index symbols for a sector"""
85
+ sector_mappings = {
86
+ "technology": {
87
+ "QQQ": "NASDAQ-100 Technology",
88
+ "XLK": "Technology Select Sector SPDR",
89
+ "VGT": "Vanguard Information Technology ETF",
90
+ "SOXX": "iShares Semiconductor ETF",
91
+ "ARKK": "ARK Innovation ETF"
92
+ },
93
+ "healthcare": {
94
+ "XLV": "Health Care Select Sector SPDR",
95
+ "VHT": "Vanguard Health Care ETF",
96
+ "IBB": "iShares Biotechnology ETF",
97
+ "XBI": "SPDR Biotech ETF"
98
+ },
99
+ "finance": {
100
+ "XLF": "Financial Select Sector SPDR",
101
+ "VFH": "Vanguard Financials ETF",
102
+ "KBE": "SPDR Banking ETF",
103
+ "KRE": "SPDR Regional Banking ETF"
104
+ },
105
+ "energy": {
106
+ "XLE": "Energy Select Sector SPDR",
107
+ "VDE": "Vanguard Energy ETF",
108
+ "XOP": "SPDR Oil & Gas Exploration ETF",
109
+ "ICLN": "iShares Clean Energy ETF"
110
+ },
111
+ "retail": {
112
+ "XRT": "SPDR Retail ETF",
113
+ "RTH": "VanEck Retail ETF",
114
+ "ONLN": "ProShares Online Retail ETF",
115
+ "XLY": "Consumer Discretionary SPDR"
116
+ }
117
+ }
118
+
119
+ return sector_mappings.get(sector, sector_mappings["technology"])
120
+
121
+ async def _generate_market_insights(self, market_data: Dict, sector: str) -> str:
122
+ """Generate AI-powered insights from market data"""
123
+ try:
124
+ system_prompt = f"""
125
+ You are a senior market analyst providing insights on the {sector} sector.
126
+ Analyze the provided market data and generate 3-4 key insights covering:
127
+ 1. Overall sector performance and trends
128
+ 2. Notable winners and losers
129
+ 3. Market sentiment and outlook
130
+ 4. Potential opportunities or risks
131
+
132
+ Keep insights concise, data-driven, and actionable for startup founders.
133
+ """
134
+
135
+ user_prompt = f"""
136
+ Sector: {sector}
137
+ Market Data Summary:
138
+ {json.dumps(market_data, indent=2)}
139
+
140
+ Provide professional market analysis with specific insights for startup founders in this sector.
141
+ """
142
+
143
+ response = await self.client.chat.completions.create(
144
+ model="gpt-4",
145
+ messages=[
146
+ {"role": "system", "content": system_prompt},
147
+ {"role": "user", "content": user_prompt}
148
+ ],
149
+ max_tokens=400,
150
+ temperature=0.3
151
+ )
152
+
153
+ return response.choices[0].message.content
154
+
155
+ except Exception as e:
156
+ logger.error(f"Error generating market insights: {e}")
157
+ return "Market insights temporarily unavailable."
158
+
159
+ async def get_competitive_landscape(self, company_name: str, industry: str) -> Dict[str, Any]:
160
+ """Analyze competitive landscape for a specific company/industry"""
161
+ try:
162
+ cache_key = f"competitive_{company_name}_{industry}"
163
+ if self._is_cache_valid(cache_key):
164
+ return self.data_cache[cache_key]
165
+
166
+ # Get industry leaders and competitors
167
+ competitors = await self._identify_competitors(company_name, industry)
168
+
169
+ competitive_data = {}
170
+ for competitor in competitors[:10]: # Limit to top 10
171
+ try:
172
+ ticker = yf.Ticker(competitor["symbol"])
173
+ info = ticker.info
174
+ hist = ticker.history(period="1y")
175
+
176
+ if not hist.empty:
177
+ competitive_data[competitor["symbol"]] = {
178
+ "name": competitor["name"],
179
+ "market_cap": info.get('marketCap', 0),
180
+ "revenue": info.get('totalRevenue', 0),
181
+ "employees": info.get('fullTimeEmployees', 0),
182
+ "pe_ratio": info.get('trailingPE', 0),
183
+ "profit_margin": info.get('profitMargins', 0),
184
+ "revenue_growth": info.get('revenueGrowth', 0),
185
+ "current_price": float(hist['Close'].iloc[-1]),
186
+ "ytd_performance": ((hist['Close'].iloc[-1] - hist['Close'].iloc[0]) / hist['Close'].iloc[0]) * 100
187
+ }
188
+ except Exception as e:
189
+ logger.warning(f"Error fetching competitor data for {competitor}: {e}")
190
+ continue
191
+
192
+ # Generate competitive analysis
193
+ analysis = await self._generate_competitive_analysis(competitive_data, company_name, industry)
194
+
195
+ result = {
196
+ "company": company_name,
197
+ "industry": industry,
198
+ "timestamp": datetime.now().isoformat(),
199
+ "competitors": competitive_data,
200
+ "analysis": analysis,
201
+ "market_leaders": self._identify_market_leaders(competitive_data)
202
+ }
203
+
204
+ self._cache_data(cache_key, result, hours=6)
205
+ return result
206
+
207
+ except Exception as e:
208
+ logger.error(f"Error getting competitive landscape: {e}")
209
+ return {"status": "error", "message": str(e)}
210
+
211
+ async def _identify_competitors(self, company_name: str, industry: str) -> List[Dict[str, str]]:
212
+ """Identify key competitors using AI and market data"""
213
+ try:
214
+ # Use AI to identify competitors
215
+ system_prompt = """
216
+ You are a market research analyst. Identify the top public competitors for the given company and industry.
217
+ Return a JSON list of competitors with their stock symbols and full company names.
218
+ Format: [{"symbol": "AAPL", "name": "Apple Inc."}, ...]
219
+ Focus on direct competitors that are publicly traded.
220
+ """
221
+
222
+ user_prompt = f"""
223
+ Company: {company_name}
224
+ Industry: {industry}
225
+
226
+ Identify 8-12 key public competitors with their stock symbols.
227
+ """
228
+
229
+ response = await self.client.chat.completions.create(
230
+ model="gpt-4",
231
+ messages=[
232
+ {"role": "system", "content": system_prompt},
233
+ {"role": "user", "content": user_prompt}
234
+ ],
235
+ max_tokens=300,
236
+ temperature=0.3
237
+ )
238
+
239
+ try:
240
+ competitors = json.loads(response.choices[0].message.content)
241
+ return competitors if isinstance(competitors, list) else []
242
+ except json.JSONDecodeError:
243
+ logger.warning("Failed to parse competitors JSON")
244
+ return []
245
+
246
+ except Exception as e:
247
+ logger.error(f"Error identifying competitors: {e}")
248
+ return []
249
+
250
+ async def _generate_competitive_analysis(self, competitive_data: Dict, company_name: str, industry: str) -> str:
251
+ """Generate AI-powered competitive analysis"""
252
+ try:
253
+ system_prompt = f"""
254
+ You are a senior business analyst providing competitive intelligence for {company_name} in the {industry} industry.
255
+
256
+ Analyze the competitive landscape and provide insights on:
257
+ 1. Market positioning and differentiation opportunities
258
+ 2. Financial performance benchmarks
259
+ 3. Strategic threats and opportunities
260
+ 4. Market dynamics and trends
261
+
262
+ Be specific and actionable for startup strategy.
263
+ """
264
+
265
+ user_prompt = f"""
266
+ Company: {company_name}
267
+ Industry: {industry}
268
+
269
+ Competitive Data:
270
+ {json.dumps(competitive_data, indent=2)}
271
+
272
+ Provide strategic competitive analysis with actionable insights.
273
+ """
274
+
275
+ response = await self.client.chat.completions.create(
276
+ model="gpt-4",
277
+ messages=[
278
+ {"role": "system", "content": system_prompt},
279
+ {"role": "user", "content": user_prompt}
280
+ ],
281
+ max_tokens=500,
282
+ temperature=0.3
283
+ )
284
+
285
+ return response.choices[0].message.content
286
+
287
+ except Exception as e:
288
+ logger.error(f"Error generating competitive analysis: {e}")
289
+ return "Competitive analysis temporarily unavailable."
290
+
291
+ def _identify_market_leaders(self, competitive_data: Dict) -> List[Dict[str, Any]]:
292
+ """Identify market leaders based on key metrics"""
293
+ try:
294
+ if not competitive_data:
295
+ return []
296
+
297
+ # Sort by market cap and revenue
298
+ sorted_by_market_cap = sorted(
299
+ competitive_data.items(),
300
+ key=lambda x: x[1].get('market_cap', 0),
301
+ reverse=True
302
+ )
303
+
304
+ leaders = []
305
+ for symbol, data in sorted_by_market_cap[:5]:
306
+ leaders.append({
307
+ "symbol": symbol,
308
+ "name": data.get('name', symbol),
309
+ "market_cap": data.get('market_cap', 0),
310
+ "revenue": data.get('revenue', 0),
311
+ "market_position": "Leader" if len(leaders) == 0 else "Major Player"
312
+ })
313
+
314
+ return leaders
315
+
316
+ except Exception as e:
317
+ logger.error(f"Error identifying market leaders: {e}")
318
+ return []
319
+
320
+ async def get_trend_analysis(self, keywords: List[str], timeframe: str = "1y") -> Dict[str, Any]:
321
+ """Analyze market trends for specific keywords/topics"""
322
+ try:
323
+ cache_key = f"trends_{'_'.join(keywords)}_{timeframe}"
324
+ if self._is_cache_valid(cache_key):
325
+ return self.data_cache[cache_key]
326
+
327
+ # Analyze related stocks and ETFs
328
+ trend_data = {}
329
+ for keyword in keywords:
330
+ related_symbols = await self._find_related_symbols(keyword)
331
+
332
+ keyword_performance = {}
333
+ for symbol in related_symbols[:5]: # Top 5 related symbols
334
+ try:
335
+ ticker = yf.Ticker(symbol)
336
+ hist = ticker.history(period=timeframe)
337
+
338
+ if not hist.empty:
339
+ performance = ((hist['Close'].iloc[-1] - hist['Close'].iloc[0]) / hist['Close'].iloc[0]) * 100
340
+ keyword_performance[symbol] = {
341
+ "performance": float(performance),
342
+ "volatility": float(hist['Close'].std()),
343
+ "volume_avg": float(hist['Volume'].mean())
344
+ }
345
+ except Exception as e:
346
+ logger.warning(f"Error analyzing {symbol}: {e}")
347
+ continue
348
+
349
+ trend_data[keyword] = keyword_performance
350
+
351
+ # Generate trend insights
352
+ insights = await self._generate_trend_insights(trend_data, keywords, timeframe)
353
+
354
+ result = {
355
+ "keywords": keywords,
356
+ "timeframe": timeframe,
357
+ "timestamp": datetime.now().isoformat(),
358
+ "trend_data": trend_data,
359
+ "insights": insights
360
+ }
361
+
362
+ self._cache_data(cache_key, result, hours=2)
363
+ return result
364
+
365
+ except Exception as e:
366
+ logger.error(f"Error getting trend analysis: {e}")
367
+ return {"status": "error", "message": str(e)}
368
+
369
+ async def _find_related_symbols(self, keyword: str) -> List[str]:
370
+ """Find stock symbols related to a keyword"""
371
+ # This is a simplified implementation
372
+ # In production, you might use more sophisticated symbol mapping
373
+ keyword_mappings = {
374
+ "ai": ["NVDA", "GOOGL", "MSFT", "AMD", "INTC"],
375
+ "cloud": ["AMZN", "MSFT", "GOOGL", "CRM", "SNOW"],
376
+ "fintech": ["SQ", "PYPL", "V", "MA", "COIN"],
377
+ "biotech": ["GILD", "AMGN", "BIIB", "REGN", "VRTX"],
378
+ "ev": ["TSLA", "F", "GM", "NIO", "RIVN"],
379
+ "crypto": ["COIN", "MSTR", "RIOT", "MARA", "HOOD"]
380
+ }
381
+
382
+ return keyword_mappings.get(keyword.lower(), ["SPY"])
383
+
384
+ async def _generate_trend_insights(self, trend_data: Dict, keywords: List[str], timeframe: str) -> str:
385
+ """Generate AI insights about market trends"""
386
+ try:
387
+ system_prompt = f"""
388
+ You are a market trend analyst providing insights on emerging trends and market dynamics.
389
+
390
+ Analyze the trend data for the keywords: {', '.join(keywords)} over {timeframe}.
391
+
392
+ Provide insights on:
393
+ 1. Overall trend momentum and direction
394
+ 2. Investment themes and opportunities
395
+ 3. Risk factors and market dynamics
396
+ 4. Implications for startups in these sectors
397
+
398
+ Keep insights concise and actionable.
399
+ """
400
+
401
+ user_prompt = f"""
402
+ Keywords: {keywords}
403
+ Timeframe: {timeframe}
404
+
405
+ Trend Performance Data:
406
+ {json.dumps(trend_data, indent=2)}
407
+
408
+ Provide trend analysis with startup implications.
409
+ """
410
+
411
+ response = await self.client.chat.completions.create(
412
+ model="gpt-4",
413
+ messages=[
414
+ {"role": "system", "content": system_prompt},
415
+ {"role": "user", "content": user_prompt}
416
+ ],
417
+ max_tokens=400,
418
+ temperature=0.3
419
+ )
420
+
421
+ return response.choices[0].message.content
422
+
423
+ except Exception as e:
424
+ logger.error(f"Error generating trend insights: {e}")
425
+ return "Trend insights temporarily unavailable."
426
+
427
+ def _is_cache_valid(self, cache_key: str) -> bool:
428
+ """Check if cached data is still valid"""
429
+ if cache_key not in self.cache_expiry:
430
+ return False
431
+ return datetime.now() < self.cache_expiry[cache_key]
432
+
433
+ def _cache_data(self, cache_key: str, data: Any, hours: int = 1):
434
+ """Cache data with expiry"""
435
+ self.data_cache[cache_key] = data
436
+ self.cache_expiry[cache_key] = datetime.now() + timedelta(hours=hours)
437
+
438
+ class DashboardVisualizer:
439
+ """Creates interactive visualizations for market intelligence dashboard"""
440
+
441
+ def __init__(self):
442
+ self.theme_colors = {
443
+ "primary": "#667eea",
444
+ "secondary": "#764ba2",
445
+ "success": "#4CAF50",
446
+ "danger": "#f44336",
447
+ "warning": "#ff9800",
448
+ "info": "#2196F3"
449
+ }
450
+
451
+ def create_market_overview_chart(self, market_data: Dict[str, Any]) -> str:
452
+ """Create market overview visualization"""
453
+ try:
454
+ symbols = list(market_data["market_data"].keys())
455
+ names = [data["name"] for data in market_data["market_data"].values()]
456
+ ytd_changes = [data["ytd_change"] for data in market_data["market_data"].values()]
457
+
458
+ # Create bar chart
459
+ fig = go.Figure()
460
+
461
+ colors = [self.theme_colors["success"] if change >= 0 else self.theme_colors["danger"]
462
+ for change in ytd_changes]
463
+
464
+ fig.add_trace(go.Bar(
465
+ x=symbols,
466
+ y=ytd_changes,
467
+ text=[f"{change:.1f}%" for change in ytd_changes],
468
+ textposition='auto',
469
+ marker_color=colors,
470
+ hovertemplate='<b>%{x}</b><br>YTD Change: %{y:.1f}%<extra></extra>'
471
+ ))
472
+
473
+ fig.update_layout(
474
+ title=f"{market_data['sector'].title()} Sector Performance (YTD)",
475
+ xaxis_title="ETFs/Indices",
476
+ yaxis_title="YTD Change (%)",
477
+ template="plotly_white",
478
+ font=dict(family="Inter, sans-serif"),
479
+ height=400
480
+ )
481
+
482
+ return fig.to_html(include_plotlyjs=True, div_id="market-overview-chart")
483
+
484
+ except Exception as e:
485
+ logger.error(f"Error creating market overview chart: {e}")
486
+ return "<div>Error creating market overview chart</div>"
487
+
488
+ def create_competitive_comparison(self, competitive_data: Dict[str, Any]) -> str:
489
+ """Create competitive landscape comparison"""
490
+ try:
491
+ competitors = competitive_data["competitors"]
492
+ if not competitors:
493
+ return "<div>No competitive data available</div>"
494
+
495
+ # Create subplot with multiple metrics
496
+ fig = make_subplots(
497
+ rows=2, cols=2,
498
+ subplot_titles=('Market Cap', 'Revenue Growth', 'Profit Margin', 'P/E Ratio'),
499
+ specs=[[{"secondary_y": False}, {"secondary_y": False}],
500
+ [{"secondary_y": False}, {"secondary_y": False}]]
501
+ )
502
+
503
+ symbols = list(competitors.keys())
504
+ market_caps = [competitors[s].get('market_cap', 0) / 1e9 for s in symbols] # In billions
505
+ revenue_growth = [competitors[s].get('revenue_growth', 0) * 100 for s in symbols]
506
+ profit_margins = [competitors[s].get('profit_margin', 0) * 100 for s in symbols]
507
+ pe_ratios = [competitors[s].get('pe_ratio', 0) for s in symbols]
508
+
509
+ # Market Cap
510
+ fig.add_trace(go.Bar(x=symbols, y=market_caps, name="Market Cap (B)",
511
+ marker_color=self.theme_colors["primary"]), row=1, col=1)
512
+
513
+ # Revenue Growth
514
+ fig.add_trace(go.Bar(x=symbols, y=revenue_growth, name="Revenue Growth (%)",
515
+ marker_color=self.theme_colors["success"]), row=1, col=2)
516
+
517
+ # Profit Margin
518
+ fig.add_trace(go.Bar(x=symbols, y=profit_margins, name="Profit Margin (%)",
519
+ marker_color=self.theme_colors["info"]), row=2, col=1)
520
+
521
+ # P/E Ratio
522
+ fig.add_trace(go.Bar(x=symbols, y=pe_ratios, name="P/E Ratio",
523
+ marker_color=self.theme_colors["warning"]), row=2, col=2)
524
+
525
+ fig.update_layout(
526
+ title="Competitive Landscape Analysis",
527
+ template="plotly_white",
528
+ font=dict(family="Inter, sans-serif"),
529
+ height=600,
530
+ showlegend=False
531
+ )
532
+
533
+ return fig.to_html(include_plotlyjs=True, div_id="competitive-chart")
534
+
535
+ except Exception as e:
536
+ logger.error(f"Error creating competitive comparison: {e}")
537
+ return "<div>Error creating competitive comparison</div>"
538
+
539
+ def create_trend_heatmap(self, trend_data: Dict[str, Any]) -> str:
540
+ """Create trend analysis heatmap"""
541
+ try:
542
+ keywords = trend_data["keywords"]
543
+ trends = trend_data["trend_data"]
544
+
545
+ if not trends:
546
+ return "<div>No trend data available</div>"
547
+
548
+ # Prepare data for heatmap
549
+ symbols = set()
550
+ for keyword_data in trends.values():
551
+ symbols.update(keyword_data.keys())
552
+
553
+ symbols = list(symbols)
554
+ performance_matrix = []
555
+
556
+ for keyword in keywords:
557
+ row = []
558
+ for symbol in symbols:
559
+ performance = trends.get(keyword, {}).get(symbol, {}).get('performance', 0)
560
+ row.append(performance)
561
+ performance_matrix.append(row)
562
+
563
+ # Create heatmap
564
+ fig = go.Figure(data=go.Heatmap(
565
+ z=performance_matrix,
566
+ x=symbols,
567
+ y=keywords,
568
+ colorscale='RdYlGn',
569
+ text=[[f"{val:.1f}%" for val in row] for row in performance_matrix],
570
+ texttemplate="%{text}",
571
+ textfont={"size": 10},
572
+ hoverongaps=False
573
+ ))
574
+
575
+ fig.update_layout(
576
+ title=f"Trend Performance Heatmap ({trend_data['timeframe']})",
577
+ xaxis_title="Symbols",
578
+ yaxis_title="Keywords",
579
+ template="plotly_white",
580
+ font=dict(family="Inter, sans-serif"),
581
+ height=400
582
+ )
583
+
584
+ return fig.to_html(include_plotlyjs=True, div_id="trend-heatmap")
585
+
586
+ except Exception as e:
587
+ logger.error(f"Error creating trend heatmap: {e}")
588
+ return "<div>Error creating trend heatmap</div>"
589
+
590
+ class MarketIntelligenceDashboard:
591
+ """Main dashboard class that orchestrates market intelligence features"""
592
+
593
+ def __init__(self):
594
+ self.engine = MarketIntelligenceEngine()
595
+ self.visualizer = DashboardVisualizer()
596
+
597
+ async def create_dashboard_interface(self) -> str:
598
+ """Create the main dashboard HTML interface"""
599
+ return """
600
+ <div id="market-intelligence-dashboard" class="dashboard-container">
601
+ <div class="dashboard-header">
602
+ <h1>📊 Market Intelligence Dashboard</h1>
603
+ <p>Real-time market data, competitive intelligence, and trend analysis</p>
604
+ </div>
605
+
606
+ <div class="dashboard-controls">
607
+ <div class="control-group">
608
+ <label>Sector Analysis:</label>
609
+ <select id="sector-select">
610
+ <option value="technology">Technology</option>
611
+ <option value="healthcare">Healthcare</option>
612
+ <option value="finance">Finance</option>
613
+ <option value="energy">Energy</option>
614
+ <option value="retail">Retail</option>
615
+ </select>
616
+ <button onclick="loadMarketOverview()" class="dashboard-btn">Analyze Sector</button>
617
+ </div>
618
+
619
+ <div class="control-group">
620
+ <label>Competitive Analysis:</label>
621
+ <input type="text" id="company-input" placeholder="Company name" />
622
+ <input type="text" id="industry-input" placeholder="Industry" />
623
+ <button onclick="loadCompetitiveAnalysis()" class="dashboard-btn">Analyze Competition</button>
624
+ </div>
625
+
626
+ <div class="control-group">
627
+ <label>Trend Analysis:</label>
628
+ <input type="text" id="keywords-input" placeholder="Keywords (comma-separated)" />
629
+ <select id="timeframe-select">
630
+ <option value="1y">1 Year</option>
631
+ <option value="6mo">6 Months</option>
632
+ <option value="3mo">3 Months</option>
633
+ <option value="1mo">1 Month</option>
634
+ </select>
635
+ <button onclick="loadTrendAnalysis()" class="dashboard-btn">Analyze Trends</button>
636
+ </div>
637
+ </div>
638
+
639
+ <div class="dashboard-content">
640
+ <div id="market-overview-section" class="dashboard-section">
641
+ <h2>Market Overview</h2>
642
+ <div id="market-overview-chart"></div>
643
+ <div id="market-insights" class="insights-panel"></div>
644
+ </div>
645
+
646
+ <div id="competitive-section" class="dashboard-section">
647
+ <h2>Competitive Landscape</h2>
648
+ <div id="competitive-chart"></div>
649
+ <div id="competitive-insights" class="insights-panel"></div>
650
+ </div>
651
+
652
+ <div id="trends-section" class="dashboard-section">
653
+ <h2>Market Trends</h2>
654
+ <div id="trend-heatmap"></div>
655
+ <div id="trend-insights" class="insights-panel"></div>
656
+ </div>
657
+ </div>
658
+
659
+ <div class="dashboard-footer">
660
+ <p>Last updated: <span id="last-updated">Never</span></p>
661
+ <button onclick="refreshAllData()" class="refresh-btn">🔄 Refresh All Data</button>
662
+ </div>
663
+ </div>
664
+
665
+ <style>
666
+ .dashboard-container {
667
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
668
+ border-radius: 20px;
669
+ padding: 30px;
670
+ margin: 20px 0;
671
+ font-family: 'Inter', sans-serif;
672
+ }
673
+
674
+ .dashboard-header {
675
+ text-align: center;
676
+ margin-bottom: 30px;
677
+ }
678
+
679
+ .dashboard-header h1 {
680
+ color: #2d3748;
681
+ margin-bottom: 10px;
682
+ }
683
+
684
+ .dashboard-controls {
685
+ display: grid;
686
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
687
+ gap: 20px;
688
+ margin-bottom: 30px;
689
+ padding: 20px;
690
+ background: white;
691
+ border-radius: 15px;
692
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
693
+ }
694
+
695
+ .control-group {
696
+ display: flex;
697
+ flex-direction: column;
698
+ gap: 10px;
699
+ }
700
+
701
+ .control-group label {
702
+ font-weight: 600;
703
+ color: #4a5568;
704
+ }
705
+
706
+ .control-group input,
707
+ .control-group select {
708
+ padding: 10px;
709
+ border: 2px solid #e2e8f0;
710
+ border-radius: 8px;
711
+ font-size: 14px;
712
+ }
713
+
714
+ .dashboard-btn {
715
+ padding: 12px 20px;
716
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
717
+ color: white;
718
+ border: none;
719
+ border-radius: 8px;
720
+ font-weight: 600;
721
+ cursor: pointer;
722
+ transition: opacity 0.3s ease;
723
+ }
724
+
725
+ .dashboard-btn:hover {
726
+ opacity: 0.9;
727
+ }
728
+
729
+ .dashboard-content {
730
+ display: flex;
731
+ flex-direction: column;
732
+ gap: 30px;
733
+ }
734
+
735
+ .dashboard-section {
736
+ background: white;
737
+ border-radius: 15px;
738
+ padding: 25px;
739
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
740
+ }
741
+
742
+ .dashboard-section h2 {
743
+ color: #2d3748;
744
+ margin-bottom: 20px;
745
+ padding-bottom: 10px;
746
+ border-bottom: 2px solid #e2e8f0;
747
+ }
748
+
749
+ .insights-panel {
750
+ background: #f7fafc;
751
+ border-radius: 10px;
752
+ padding: 20px;
753
+ margin-top: 20px;
754
+ border-left: 4px solid #667eea;
755
+ }
756
+
757
+ .dashboard-footer {
758
+ display: flex;
759
+ justify-content: space-between;
760
+ align-items: center;
761
+ margin-top: 30px;
762
+ padding: 20px;
763
+ background: rgba(255, 255, 255, 0.8);
764
+ border-radius: 10px;
765
+ }
766
+
767
+ .refresh-btn {
768
+ padding: 10px 20px;
769
+ background: #4CAF50;
770
+ color: white;
771
+ border: none;
772
+ border-radius: 8px;
773
+ cursor: pointer;
774
+ font-weight: 600;
775
+ }
776
+
777
+ .loading {
778
+ text-align: center;
779
+ padding: 40px;
780
+ color: #718096;
781
+ }
782
+
783
+ .error {
784
+ background: #fed7d7;
785
+ color: #c53030;
786
+ padding: 15px;
787
+ border-radius: 8px;
788
+ margin: 10px 0;
789
+ }
790
+ </style>
791
+
792
+ <script>
793
+ async function loadMarketOverview() {
794
+ const sector = document.getElementById('sector-select').value;
795
+ const chartDiv = document.getElementById('market-overview-chart');
796
+ const insightsDiv = document.getElementById('market-insights');
797
+
798
+ chartDiv.innerHTML = '<div class="loading">Loading market overview...</div>';
799
+ insightsDiv.innerHTML = '';
800
+
801
+ try {
802
+ const response = await sendDashboardRequest('market_overview', { sector });
803
+ if (response.status === 'success') {
804
+ chartDiv.innerHTML = response.chart;
805
+ insightsDiv.innerHTML = `<h3>Market Insights</h3><p>${response.insights}</p>`;
806
+ updateLastUpdated();
807
+ } else {
808
+ chartDiv.innerHTML = `<div class="error">Error: ${response.message}</div>`;
809
+ }
810
+ } catch (error) {
811
+ chartDiv.innerHTML = `<div class="error">Error loading market data</div>`;
812
+ }
813
+ }
814
+
815
+ async function loadCompetitiveAnalysis() {
816
+ const company = document.getElementById('company-input').value;
817
+ const industry = document.getElementById('industry-input').value;
818
+
819
+ if (!company || !industry) {
820
+ alert('Please enter both company name and industry');
821
+ return;
822
+ }
823
+
824
+ const chartDiv = document.getElementById('competitive-chart');
825
+ const insightsDiv = document.getElementById('competitive-insights');
826
+
827
+ chartDiv.innerHTML = '<div class="loading">Loading competitive analysis...</div>';
828
+ insightsDiv.innerHTML = '';
829
+
830
+ try {
831
+ const response = await sendDashboardRequest('competitive_analysis', { company, industry });
832
+ if (response.status === 'success') {
833
+ chartDiv.innerHTML = response.chart;
834
+ insightsDiv.innerHTML = `<h3>Competitive Analysis</h3><p>${response.analysis}</p>`;
835
+ updateLastUpdated();
836
+ } else {
837
+ chartDiv.innerHTML = `<div class="error">Error: ${response.message}</div>`;
838
+ }
839
+ } catch (error) {
840
+ chartDiv.innerHTML = `<div class="error">Error loading competitive data</div>`;
841
+ }
842
+ }
843
+
844
+ async function loadTrendAnalysis() {
845
+ const keywordsInput = document.getElementById('keywords-input').value;
846
+ const timeframe = document.getElementById('timeframe-select').value;
847
+
848
+ if (!keywordsInput) {
849
+ alert('Please enter keywords for trend analysis');
850
+ return;
851
+ }
852
+
853
+ const keywords = keywordsInput.split(',').map(k => k.trim());
854
+ const chartDiv = document.getElementById('trend-heatmap');
855
+ const insightsDiv = document.getElementById('trend-insights');
856
+
857
+ chartDiv.innerHTML = '<div class="loading">Loading trend analysis...</div>';
858
+ insightsDiv.innerHTML = '';
859
+
860
+ try {
861
+ const response = await sendDashboardRequest('trend_analysis', { keywords, timeframe });
862
+ if (response.status === 'success') {
863
+ chartDiv.innerHTML = response.chart;
864
+ insightsDiv.innerHTML = `<h3>Trend Insights</h3><p>${response.insights}</p>`;
865
+ updateLastUpdated();
866
+ } else {
867
+ chartDiv.innerHTML = `<div class="error">Error: ${response.message}</div>`;
868
+ }
869
+ } catch (error) {
870
+ chartDiv.innerHTML = `<div class="error">Error loading trend data</div>`;
871
+ }
872
+ }
873
+
874
+ async function refreshAllData() {
875
+ await loadMarketOverview();
876
+ if (document.getElementById('company-input').value && document.getElementById('industry-input').value) {
877
+ await loadCompetitiveAnalysis();
878
+ }
879
+ if (document.getElementById('keywords-input').value) {
880
+ await loadTrendAnalysis();
881
+ }
882
+ }
883
+
884
+ async function sendDashboardRequest(type, data) {
885
+ if (window.chainlitAPI) {
886
+ return await window.chainlitAPI.sendMessage({
887
+ type: 'dashboard_request',
888
+ request_type: type,
889
+ data: data
890
+ });
891
+ }
892
+ throw new Error('Chainlit API not available');
893
+ }
894
+
895
+ function updateLastUpdated() {
896
+ document.getElementById('last-updated').textContent = new Date().toLocaleString();
897
+ }
898
+
899
+ // Auto-load technology sector overview on page load
900
+ document.addEventListener('DOMContentLoaded', function() {
901
+ setTimeout(loadMarketOverview, 1000);
902
+ });
903
+ </script>
904
+ """
905
+
906
+ async def handle_dashboard_request(self, request_type: str, data: Dict[str, Any]) -> Dict[str, Any]:
907
+ """Handle different types of dashboard requests"""
908
+ try:
909
+ if request_type == "market_overview":
910
+ sector = data.get("sector", "technology")
911
+ market_data = await self.engine.get_market_overview(sector)
912
+
913
+ if "status" in market_data and market_data["status"] == "error":
914
+ return market_data
915
+
916
+ chart_html = self.visualizer.create_market_overview_chart(market_data)
917
+
918
+ return {
919
+ "status": "success",
920
+ "chart": chart_html,
921
+ "insights": market_data["insights"],
922
+ "data": market_data
923
+ }
924
+
925
+ elif request_type == "competitive_analysis":
926
+ company = data.get("company", "")
927
+ industry = data.get("industry", "")
928
+
929
+ competitive_data = await self.engine.get_competitive_landscape(company, industry)
930
+
931
+ if "status" in competitive_data and competitive_data["status"] == "error":
932
+ return competitive_data
933
+
934
+ chart_html = self.visualizer.create_competitive_comparison(competitive_data)
935
+
936
+ return {
937
+ "status": "success",
938
+ "chart": chart_html,
939
+ "analysis": competitive_data["analysis"],
940
+ "data": competitive_data
941
+ }
942
+
943
+ elif request_type == "trend_analysis":
944
+ keywords = data.get("keywords", [])
945
+ timeframe = data.get("timeframe", "1y")
946
+
947
+ trend_data = await self.engine.get_trend_analysis(keywords, timeframe)
948
+
949
+ if "status" in trend_data and trend_data["status"] == "error":
950
+ return trend_data
951
+
952
+ chart_html = self.visualizer.create_trend_heatmap(trend_data)
953
+
954
+ return {
955
+ "status": "success",
956
+ "chart": chart_html,
957
+ "insights": trend_data["insights"],
958
+ "data": trend_data
959
+ }
960
+
961
+ else:
962
+ return {"status": "error", "message": "Unknown request type"}
963
+
964
+ except Exception as e:
965
+ logger.error(f"Error handling dashboard request: {e}")
966
+ return {"status": "error", "message": str(e)}