Sujatha commited on
Commit
4382d3d
Β·
verified Β·
1 Parent(s): 37dec1f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +276 -168
app.py CHANGED
@@ -1,34 +1,50 @@
 
 
1
  import gradio as gr
2
  import pandas as pd
3
  import numpy as np
4
  import plotly.graph_objects as go
5
  from datetime import datetime
6
- import os
7
  import json
8
  from typing import Dict, List, Tuple, Optional
9
 
10
- # LangChain imports for conversational AI
11
- from langchain.schema import HumanMessage, AIMessage, SystemMessage
12
- from langchain_openai import ChatOpenAI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- # Import our modules
15
- from index_calculator import IndexCalculator
16
- from data_sources import RealTimeIndexCalculator, IndianStockAPI, GlobalStockAPI
17
 
18
- # Initialize memory for conversation context using a custom memory handler
19
  class SimpleMemory:
20
  def __init__(self):
21
  self.messages = []
22
-
23
  def add_message(self, message: str, role: str):
24
  self.messages.append({'role': role, 'content': message})
25
-
26
  def get_history(self):
27
  return self.messages
28
 
29
  memory = SimpleMemory()
30
 
31
- # System prompt for the AI assistant
32
  SYSTEM_PROMPT = """You are an expert financial analyst specializing in index numbers and real-time market data.
33
  You help users understand, calculate, and analyze various types of indices including:
34
  - Laspeyres, Paasche, and Fisher price indices
@@ -41,174 +57,199 @@ You have access to:
41
  3. A powerful index calculator for custom analysis
42
  When users ask about stocks or indices, fetch live data. Provide clear explanations with numbers."""
43
 
44
- # Initialize LLM
45
- def get_llm():
46
- """Initialize LLM with OpenRouter for free access"""
47
- return ChatOpenAI(
48
- base_url="https://openrouter.ai/api/v1",
49
- api_key=os.getenv("OPENROUTER_API_KEY", "sk-or-v1-64e1068c3d61c7c1d7f5d9b8a2e3f4c5d6e7f8g9h0i1j2k3l4m5n6o7p8q9r0"),
50
- model="openai/gpt-3.5-turbo:free",
51
- temperature=0.3,
52
- )
53
-
54
- # Initialize real-time calculator
55
- rt_calc = RealTimeIndexCalculator()
56
- indian_api = IndianStockAPI()
57
- global_api = GlobalStockAPI()
58
-
59
  def process_query(query: str, history: List, exchange: str) -> Tuple[str, List, pd.DataFrame, str]:
60
  """
61
  Process user query with real-time data awareness
62
  """
63
- llm = get_llm()
64
 
65
- # Check if query is about real-time data
66
  response_text = ""
67
  data_preview = pd.DataFrame()
68
 
69
- # Detect Indian stocks (common patterns)
70
  indian_stocks = ['RELIANCE', 'TCS', 'INFY', 'HDFCBANK', 'ICICIBANK', 'SBIN',
71
  'ITC', 'BHARTIARTL', 'KOTAKBANK', 'LT', 'WIPRO', 'AXISBANK']
72
 
73
  query_lower = query.lower()
74
 
75
- # Handle real-time queries
76
  if any(stock.lower() in query_lower for stock in indian_stocks) or 'nifty' in query_lower or 'sensex' in query_lower:
77
- # Extract stock symbol from query
78
  for stock in indian_stocks:
79
  if stock.lower() in query_lower:
80
- data = indian_api.get_stock_price(stock, exchange)
81
- if data and 'data' in data:
82
- formatted = indian_api.format_for_index(data)
83
- response_text = f"**{formatted['company_name']}**\n\n"
84
- response_text += f"πŸ’° Current Price: β‚Ή{formatted['last_price']:,.2f}\n"
85
- response_text += f"πŸ“Š Change: {formatted['change']:+.2f} ({formatted['percent_change']:+.2f}%)\n"
86
- response_text += f"πŸ“ˆ Day Range: β‚Ή{formatted['day_low']} - β‚Ή{formatted['day_high']}\n"
87
- response_text += f"πŸ“‰ 52-Week Range: β‚Ή{formatted['year_low']} - β‚Ή{formatted['year_high']}\n"
88
- response_text += f"πŸ’Ή Market Cap: β‚Ή{formatted['market_cap']:,.0f} Cr\n"
89
- response_text += f"πŸ“Š P/E Ratio: {formatted['pe_ratio']:.2f}\n"
90
-
91
- # Create preview DataFrame
92
- data_preview = pd.DataFrame([formatted])
 
93
  break
94
 
95
- if 'nifty' in query_lower:
96
- nifty_data = global_api.get_stock_info('^NSEI')
97
- if nifty_data:
98
- response_text += f"\n\n**Nifty 50 Index**\n"
99
- response_text += f"Current: {nifty_data['last_price']:,.2f}\n"
100
- response_text += f"Change: {nifty_data['change']:+.2f} ({nifty_data['percent_change']:+.2f}%)"
 
 
101
 
102
- # Handle global stocks
103
  elif any(ticker in query.upper() for ticker in ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA']):
104
  tickers = ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA']
105
  for ticker in tickers:
106
  if ticker in query.upper():
107
- data = global_api.get_stock_info(ticker)
108
- if data:
109
- response_text = f"**{data['company_name']} ({ticker})**\n\n"
110
- response_text += f"πŸ’° Current Price: ${data['last_price']:,.2f}\n"
111
- response_text += f"πŸ“Š Change: ${data['change']:+.2f} ({data['percent_change']:+.2f}%)\n"
112
- response_text += f"πŸ“ˆ Day Range: ${data['day_low']} - ${data['day_high']}\n"
113
- response_text += f"πŸ’Ή Market Cap: ${data['market_cap']/1e9:,.2f}B\n"
114
- data_preview = pd.DataFrame([data])
 
 
 
115
  break
116
 
117
  # If no real-time match, use LLM
118
  if not response_text:
119
- messages = [
120
- SystemMessage(content=SYSTEM_PROMPT),
121
- ] + [
122
- HumanMessage(content=msg) if i % 2 == 0 else AIMessage(content=msg)
123
- for i, msg in enumerate(history)
124
- ] if history else [] + [HumanMessage(content=query)]
125
-
126
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  response = llm.invoke(messages)
128
  response_text = response.content
129
  except Exception as e:
130
- response_text = f"I encountered an error: {str(e)}"
131
 
132
- # Update history
133
  updated_history = history + [query, response_text]
 
 
134
 
135
  return response_text, updated_history, data_preview, ""
136
 
137
- def create_realtime_ui():
138
- """Create the real-time market data tab UI"""
139
- with gr.Row():
140
- with gr.Column(scale=1):
141
- gr.Markdown("""
142
- ### πŸ“‘ Real-Time Market Data
143
-
144
- Fetch live stock prices from:
145
- - **NSE** (National Stock Exchange of India) [citation:1]
146
- - **BSE** (Bombay Stock Exchange) [citation:1]
147
- - **Global Markets** via Yahoo Finance [citation:2]
148
- """)
149
-
150
- exchange = gr.Radio(
151
- choices=["NSE", "BSE", "Global"],
152
- value="NSE",
153
- label="Select Exchange"
154
- )
155
-
156
- symbol_input = gr.Textbox(
157
- label="Stock Symbol",
158
- placeholder="RELIANCE, TCS, INFY, or AAPL, GOOGL for global"
159
- )
160
-
161
- fetch_btn = gr.Button("Fetch Live Data", variant="primary")
162
-
163
- gr.Markdown("""
164
- ### πŸ“Š Build Custom Index
165
- Enter up to 5 symbols to create your own index
166
- """)
167
-
168
- symbols_list = gr.Dataframe(
169
- headers=["Symbol", "Weight (%)"],
170
- datatype=["str", "number"],
171
- row_count=5,
172
- col_count=2,
173
- value=[["RELIANCE", 20], ["TCS", 20], ["INFY", 20], ["HDFCBANK", 20], ["ITC", 20]]
174
- )
175
-
176
- index_type = gr.Dropdown(
177
- choices=["Price-Weighted", "Market Cap-Weighted", "Equal-Weighted"],
178
- value="Market Cap-Weighted",
179
- label="Index Type"
180
- )
181
-
182
- build_index_btn = gr.Button("Build Custom Index", variant="secondary")
183
-
184
- with gr.Column(scale=1):
185
- stock_output = gr.JSON(label="Stock Details")
186
-
187
- with gr.Row():
188
- price = gr.Number(label="Current Price")
189
- change = gr.Number(label="Change")
190
- pct_change = gr.Number(label="% Change")
191
-
192
- chart_output = gr.Plot(label="Price Chart")
193
-
194
- index_result = gr.JSON(label="Custom Index Result")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
 
196
- return {
197
- "exchange": exchange,
198
- "symbol": symbol_input,
199
- "fetch_btn": fetch_btn,
200
- "symbols_list": symbols_list,
201
- "index_type": index_type,
202
- "build_btn": build_index_btn,
203
- "stock_output": stock_output,
204
- "price": price,
205
- "change": change,
206
- "pct_change": pct_change,
207
- "chart": chart_output,
208
- "index_result": index_result
209
- }
210
 
211
- # Build the main Gradio interface
212
  with gr.Blocks(title="AI-Powered Index Analyst with Real-Time Data", theme=gr.themes.Soft()) as demo:
213
  gr.Markdown("""
214
  # πŸ“ˆ AI-Powered Index Analyst with Real-Time Market Data
@@ -243,6 +284,7 @@ with gr.Blocks(title="AI-Powered Index Analyst with Real-Time Data", theme=gr.th
243
  data_output = gr.DataFrame(label="Data Preview")
244
  calc_output = gr.Textbox(label="Calculation Results", lines=3)
245
 
 
246
  submit.click(
247
  process_query,
248
  inputs=[msg, chat_history, exchange_selector],
@@ -261,42 +303,108 @@ with gr.Blocks(title="AI-Powered Index Analyst with Real-Time Data", theme=gr.th
261
  )
262
 
263
  with gr.Tab("πŸ“‘ Real-Time Market Data"):
264
- rt_ui = create_realtime_ui()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
 
266
- rt_ui["fetch_btn"].click(
267
  fetch_live_stock,
268
- inputs=[rt_ui["symbol"], rt_ui["exchange"]],
269
- outputs=[rt_ui["stock_output"], rt_ui["price"], rt_ui["change"], rt_ui["pct_change"], rt_ui["chart"]]
270
  )
271
 
272
- rt_ui["build_btn"].click(
273
  build_custom_index,
274
- inputs=[rt_ui["symbols_list"], rt_ui["index_type"], rt_ui["exchange"]],
275
- outputs=[rt_ui["index_result"]]
276
  )
277
 
278
  with gr.Tab("πŸ“Š Index Calculator"):
279
- # Import from original app
280
- from app import create_index_ui, calculate_indices
 
 
 
 
 
 
 
 
 
281
  calc_ui = create_index_ui()
282
- calc_ui["btn"].click(
283
- calculate_indices,
284
- inputs=[
285
- calc_ui["file"],
286
- calc_ui["items"],
287
- calc_ui["p0"],
288
- calc_ui["q0"],
289
- calc_ui["p1"],
290
- calc_ui["q1"]
291
- ],
292
- outputs=[
293
- calc_ui["results"],
294
- calc_ui["laspeyres"],
295
- calc_ui["paasche"],
296
- calc_ui["fisher"],
297
- calc_ui["plot"]
298
- ]
299
- )
 
 
300
 
301
  with gr.Tab("πŸ”„ Index Comparison"):
302
  comp_ui = create_comparison_ui()
 
1
+ import os
2
+ import sys
3
  import gradio as gr
4
  import pandas as pd
5
  import numpy as np
6
  import plotly.graph_objects as go
7
  from datetime import datetime
 
8
  import json
9
  from typing import Dict, List, Tuple, Optional
10
 
11
+ # ========== Optional memory monitoring ==========
12
+ try:
13
+ import psutil
14
+ print(f"🧠 Memory at startup: {psutil.virtual_memory().percent}% used, "
15
+ f"{psutil.virtual_memory().available / 1e9:.2f} GB free")
16
+ except ImportError:
17
+ pass
18
+
19
+ # ========== Lazy imports for heavy modules ==========
20
+ def get_llm():
21
+ from langchain_openai import ChatOpenAI
22
+ from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
23
+ api_key = os.getenv("OPENROUTER_API_KEY")
24
+ if not api_key:
25
+ raise ValueError("OPENROUTER_API_KEY environment variable not set.")
26
+ return ChatOpenAI(
27
+ base_url="https://openrouter.ai/api/v1",
28
+ api_key=api_key,
29
+ model="openai/gpt-3.5-turbo:free",
30
+ temperature=0.3,
31
+ )
32
 
33
+ def get_realtime_calculator():
34
+ from data_sources import RealTimeIndexCalculator, IndianStockAPI, GlobalStockAPI
35
+ return RealTimeIndexCalculator(), IndianStockAPI(), GlobalStockAPI()
36
 
37
+ # ========== Simple memory (optional, not heavily used) ==========
38
  class SimpleMemory:
39
  def __init__(self):
40
  self.messages = []
 
41
  def add_message(self, message: str, role: str):
42
  self.messages.append({'role': role, 'content': message})
 
43
  def get_history(self):
44
  return self.messages
45
 
46
  memory = SimpleMemory()
47
 
 
48
  SYSTEM_PROMPT = """You are an expert financial analyst specializing in index numbers and real-time market data.
49
  You help users understand, calculate, and analyze various types of indices including:
50
  - Laspeyres, Paasche, and Fisher price indices
 
57
  3. A powerful index calculator for custom analysis
58
  When users ask about stocks or indices, fetch live data. Provide clear explanations with numbers."""
59
 
60
+ # ========== Core conversational function ==========
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  def process_query(query: str, history: List, exchange: str) -> Tuple[str, List, pd.DataFrame, str]:
62
  """
63
  Process user query with real-time data awareness
64
  """
65
+ rt_calc, indian_api, global_api = get_realtime_calculator()
66
 
 
67
  response_text = ""
68
  data_preview = pd.DataFrame()
69
 
70
+ # Common Indian stocks
71
  indian_stocks = ['RELIANCE', 'TCS', 'INFY', 'HDFCBANK', 'ICICIBANK', 'SBIN',
72
  'ITC', 'BHARTIARTL', 'KOTAKBANK', 'LT', 'WIPRO', 'AXISBANK']
73
 
74
  query_lower = query.lower()
75
 
76
+ # Real-time data handling
77
  if any(stock.lower() in query_lower for stock in indian_stocks) or 'nifty' in query_lower or 'sensex' in query_lower:
 
78
  for stock in indian_stocks:
79
  if stock.lower() in query_lower:
80
+ try:
81
+ data = indian_api.get_stock_price(stock, exchange)
82
+ if data and 'data' in data:
83
+ formatted = indian_api.format_for_index(data)
84
+ response_text = f"**{formatted['company_name']}**\n\n"
85
+ response_text += f"πŸ’° Current Price: β‚Ή{formatted['last_price']:,.2f}\n"
86
+ response_text += f"πŸ“Š Change: {formatted['change']:+.2f} ({formatted['percent_change']:+.2f}%)\n"
87
+ response_text += f"πŸ“ˆ Day Range: β‚Ή{formatted['day_low']} - β‚Ή{formatted['day_high']}\n"
88
+ response_text += f"πŸ“‰ 52-Week Range: β‚Ή{formatted['year_low']} - β‚Ή{formatted['year_high']}\n"
89
+ response_text += f"πŸ’Ή Market Cap: β‚Ή{formatted['market_cap']:,.0f} Cr\n"
90
+ response_text += f"πŸ“Š P/E Ratio: {formatted['pe_ratio']:.2f}\n"
91
+ data_preview = pd.DataFrame([formatted])
92
+ except Exception as e:
93
+ response_text = f"Error fetching data: {str(e)}"
94
  break
95
 
96
+ if 'nifty' in query_lower and not response_text:
97
+ try:
98
+ nifty_data = global_api.get_stock_info('^NSEI')
99
+ if nifty_data:
100
+ response_text = f"**Nifty 50 Index**\nCurrent: {nifty_data['last_price']:,.2f}\n"
101
+ response_text += f"Change: {nifty_data['change']:+.2f} ({nifty_data['percent_change']:+.2f}%)"
102
+ except Exception as e:
103
+ response_text = f"Error fetching Nifty: {str(e)}"
104
 
 
105
  elif any(ticker in query.upper() for ticker in ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA']):
106
  tickers = ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA']
107
  for ticker in tickers:
108
  if ticker in query.upper():
109
+ try:
110
+ data = global_api.get_stock_info(ticker)
111
+ if data:
112
+ response_text = f"**{data['company_name']} ({ticker})**\n\n"
113
+ response_text += f"πŸ’° Current Price: ${data['last_price']:,.2f}\n"
114
+ response_text += f"πŸ“Š Change: ${data['change']:+.2f} ({data['percent_change']:+.2f}%)\n"
115
+ response_text += f"πŸ“ˆ Day Range: ${data['day_low']} - ${data['day_high']}\n"
116
+ response_text += f"πŸ’Ή Market Cap: ${data['market_cap']/1e9:,.2f}B\n"
117
+ data_preview = pd.DataFrame([data])
118
+ except Exception as e:
119
+ response_text = f"Error fetching data: {str(e)}"
120
  break
121
 
122
  # If no real-time match, use LLM
123
  if not response_text:
 
 
 
 
 
 
 
124
  try:
125
+ llm = get_llm()
126
+ from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
127
+
128
+ messages = [SystemMessage(content=SYSTEM_PROMPT)]
129
+ if history:
130
+ # history is a flat list: [user1, assistant1, user2, assistant2, ...]
131
+ for i in range(0, len(history), 2):
132
+ if i < len(history):
133
+ messages.append(HumanMessage(content=history[i]))
134
+ if i+1 < len(history):
135
+ messages.append(AIMessage(content=history[i+1]))
136
+ messages.append(HumanMessage(content=query))
137
+
138
  response = llm.invoke(messages)
139
  response_text = response.content
140
  except Exception as e:
141
+ response_text = f"LLM error: {str(e)}"
142
 
143
+ # Update history (keep last 10 exchanges to avoid memory bloat)
144
  updated_history = history + [query, response_text]
145
+ if len(updated_history) > 20:
146
+ updated_history = updated_history[-20:]
147
 
148
  return response_text, updated_history, data_preview, ""
149
 
150
+ # ========== Real-time UI functions ==========
151
+ def fetch_live_stock(symbol: str, exchange: str):
152
+ """Fetch live stock data and return JSON, price, change, pct, chart"""
153
+ _, indian_api, global_api = get_realtime_calculator()
154
+ if exchange in ["NSE", "BSE"]:
155
+ data = indian_api.get_stock_price(symbol, exchange)
156
+ if data and 'data' in data:
157
+ formatted = indian_api.format_for_index(data)
158
+ # Simple chart
159
+ fig = go.Figure()
160
+ fig.add_trace(go.Indicator(
161
+ mode="number+delta",
162
+ value=formatted['last_price'],
163
+ number={'prefix': 'β‚Ή'},
164
+ delta={'reference': formatted['last_price'] - formatted['change']}
165
+ ))
166
+ fig.update_layout(height=300)
167
+ return formatted, formatted['last_price'], formatted['change'], formatted['percent_change'], fig
168
+ else:
169
+ data = global_api.get_stock_info(symbol)
170
+ if data:
171
+ fig = go.Figure()
172
+ fig.add_trace(go.Indicator(
173
+ mode="number+delta",
174
+ value=data['last_price'],
175
+ number={'prefix': '$'},
176
+ delta={'reference': data['last_price'] - data['change']}
177
+ ))
178
+ fig.update_layout(height=300)
179
+ return data, data['last_price'], data['change'], data['percent_change'], fig
180
+ return {}, 0, 0, 0, go.Figure()
181
+
182
+ def build_custom_index(symbols_df: pd.DataFrame, index_type: str, exchange: str):
183
+ """Build custom index from symbols and weights"""
184
+ _, indian_api, global_api = get_realtime_calculator()
185
+ weights = []
186
+ prices = []
187
+ total_weight = 0
188
+ for _, row in symbols_df.iterrows():
189
+ symbol = row['Symbol']
190
+ weight = float(row['Weight (%)']) / 100.0
191
+ if exchange in ["NSE", "BSE"]:
192
+ data = indian_api.get_stock_price(symbol, exchange)
193
+ if data and 'data' in data:
194
+ # Adjust based on actual API structure
195
+ price = data['data'][0]['last_price'] if 'data' in data and data['data'] else 0
196
+ else:
197
+ price = 0
198
+ else:
199
+ data = global_api.get_stock_info(symbol)
200
+ price = data.get('last_price', 0) if data else 0
201
+ weights.append(weight)
202
+ prices.append(price)
203
+ total_weight += weight
204
+
205
+ # Normalize weights if total != 1
206
+ if total_weight != 1:
207
+ weights = [w/total_weight for w in weights]
208
+
209
+ if index_type == "Price-Weighted":
210
+ index_value = sum(prices) / len(prices) if prices else 0
211
+ elif index_type == "Equal-Weighted":
212
+ index_value = sum(prices) / len(prices) if prices else 0
213
+ elif index_type == "Market Cap-Weighted":
214
+ index_value = sum(w * p for w, p in zip(weights, prices)) if prices else 0
215
+ else:
216
+ index_value = 0
217
+
218
+ return {"index_value": round(index_value, 2), "components": prices, "weights": weights}
219
+
220
+ # ========== Comparison UI functions ==========
221
+ def create_comparison_ui():
222
+ """Return UI components for index comparison tab"""
223
+ with gr.Blocks() as comp_ui:
224
+ with gr.Row():
225
+ symbols_input = gr.Textbox(label="Symbols (comma-separated)", placeholder="RELIANCE, TCS, INFY")
226
+ exchange = gr.Radio(["NSE", "BSE", "Global"], value="NSE", label="Exchange")
227
+ compare_btn = gr.Button("Compare Indices")
228
+ results_output = gr.JSON(label="Comparison Results")
229
+ chart_output = gr.Plot(label="Comparison Chart")
230
+ return {"symbols": symbols_input, "exchange": exchange, "btn": compare_btn,
231
+ "results": results_output, "chart": chart_output}
232
+
233
+ def compare_live_indices(symbols_str: str, exchange: str):
234
+ """Compare multiple indices"""
235
+ symbols = [s.strip() for s in symbols_str.split(",") if s.strip()]
236
+ _, indian_api, global_api = get_realtime_calculator()
237
+ data = {}
238
+ for sym in symbols:
239
+ if exchange in ["NSE", "BSE"]:
240
+ d = indian_api.get_stock_price(sym, exchange)
241
+ if d and 'data' in d and d['data']:
242
+ data[sym] = d['data'][0]['last_price']
243
+ else:
244
+ d = global_api.get_stock_info(sym)
245
+ if d:
246
+ data[sym] = d['last_price']
247
 
248
+ fig = go.Figure(data=[go.Bar(x=list(data.keys()), y=list(data.values()))])
249
+ fig.update_layout(title="Index Comparison", yaxis_title="Price")
250
+ return data, fig
 
 
 
 
 
 
 
 
 
 
 
251
 
252
+ # ========== Main Gradio interface ==========
253
  with gr.Blocks(title="AI-Powered Index Analyst with Real-Time Data", theme=gr.themes.Soft()) as demo:
254
  gr.Markdown("""
255
  # πŸ“ˆ AI-Powered Index Analyst with Real-Time Market Data
 
284
  data_output = gr.DataFrame(label="Data Preview")
285
  calc_output = gr.Textbox(label="Calculation Results", lines=3)
286
 
287
+ # Output mapping: (response, updated_history, data_preview, status)
288
  submit.click(
289
  process_query,
290
  inputs=[msg, chat_history, exchange_selector],
 
303
  )
304
 
305
  with gr.Tab("πŸ“‘ Real-Time Market Data"):
306
+ with gr.Row():
307
+ with gr.Column(scale=1):
308
+ gr.Markdown("""
309
+ ### πŸ“‘ Real-Time Market Data
310
+
311
+ Fetch live stock prices from:
312
+ - **NSE** (National Stock Exchange of India) [citation:1]
313
+ - **BSE** (Bombay Stock Exchange) [citation:1]
314
+ - **Global Markets** via Yahoo Finance [citation:2]
315
+ """)
316
+
317
+ exchange = gr.Radio(
318
+ choices=["NSE", "BSE", "Global"],
319
+ value="NSE",
320
+ label="Select Exchange"
321
+ )
322
+
323
+ symbol_input = gr.Textbox(
324
+ label="Stock Symbol",
325
+ placeholder="RELIANCE, TCS, INFY, or AAPL, GOOGL for global"
326
+ )
327
+
328
+ fetch_btn = gr.Button("Fetch Live Data", variant="primary")
329
+
330
+ gr.Markdown("""
331
+ ### πŸ“Š Build Custom Index
332
+ Enter up to 5 symbols to create your own index
333
+ """)
334
+
335
+ symbols_list = gr.Dataframe(
336
+ headers=["Symbol", "Weight (%)"],
337
+ datatype=["str", "number"],
338
+ row_count=5,
339
+ col_count=2,
340
+ value=[["RELIANCE", 20], ["TCS", 20], ["INFY", 20], ["HDFCBANK", 20], ["ITC", 20]]
341
+ )
342
+
343
+ index_type = gr.Dropdown(
344
+ choices=["Price-Weighted", "Market Cap-Weighted", "Equal-Weighted"],
345
+ value="Market Cap-Weighted",
346
+ label="Index Type"
347
+ )
348
+
349
+ build_index_btn = gr.Button("Build Custom Index", variant="secondary")
350
+
351
+ with gr.Column(scale=1):
352
+ stock_output = gr.JSON(label="Stock Details")
353
+
354
+ with gr.Row():
355
+ price = gr.Number(label="Current Price")
356
+ change = gr.Number(label="Change")
357
+ pct_change = gr.Number(label="% Change")
358
+
359
+ chart_output = gr.Plot(label="Price Chart")
360
+
361
+ index_result = gr.JSON(label="Custom Index Result")
362
 
363
+ fetch_btn.click(
364
  fetch_live_stock,
365
+ inputs=[symbol_input, exchange],
366
+ outputs=[stock_output, price, change, pct_change, chart_output]
367
  )
368
 
369
+ build_index_btn.click(
370
  build_custom_index,
371
+ inputs=[symbols_list, index_type, exchange],
372
+ outputs=[index_result]
373
  )
374
 
375
  with gr.Tab("πŸ“Š Index Calculator"):
376
+ try:
377
+ from app import create_index_ui, calculate_indices
378
+ except ImportError:
379
+ # Stub functions if module not available
380
+ def create_index_ui():
381
+ with gr.Blocks():
382
+ gr.Markdown("Index Calculator placeholder – implement if needed.")
383
+ return {}
384
+ def calculate_indices(file, items, p0, q0, p1, q1):
385
+ return "Calculation placeholder", 0, 0, 0, go.Figure()
386
+
387
  calc_ui = create_index_ui()
388
+ if calc_ui and 'btn' in calc_ui:
389
+ # Connect the calculator button if UI defined
390
+ calc_ui["btn"].click(
391
+ calculate_indices,
392
+ inputs=[
393
+ calc_ui.get("file"),
394
+ calc_ui.get("items"),
395
+ calc_ui.get("p0"),
396
+ calc_ui.get("q0"),
397
+ calc_ui.get("p1"),
398
+ calc_ui.get("q1")
399
+ ],
400
+ outputs=[
401
+ calc_ui.get("results"),
402
+ calc_ui.get("laspeyres"),
403
+ calc_ui.get("paasche"),
404
+ calc_ui.get("fisher"),
405
+ calc_ui.get("plot")
406
+ ]
407
+ )
408
 
409
  with gr.Tab("πŸ”„ Index Comparison"):
410
  comp_ui = create_comparison_ui()