abhaypratapsingh111 commited on
Commit
15b68db
·
verified ·
1 Parent(s): 88ca8e0

Upload folder using huggingface_hub

Browse files
components/__init__.py ADDED
File without changes
components/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (166 Bytes). View file
 
components/__pycache__/chart.cpython-311.pyc ADDED
Binary file (11.8 kB). View file
 
components/__pycache__/controls.cpython-311.pyc ADDED
Binary file (9.05 kB). View file
 
components/__pycache__/upload.cpython-311.pyc ADDED
Binary file (14.3 kB). View file
 
components/chart.py ADDED
@@ -0,0 +1,309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Chart generation for forecast visualization
3
+ """
4
+
5
+ import plotly.graph_objs as go
6
+ from plotly.subplots import make_subplots
7
+ import pandas as pd
8
+ from typing import List
9
+ from config.constants import COLORS, CHART_CONFIG
10
+
11
+
12
+ def create_forecast_chart(
13
+ historical_data: pd.DataFrame,
14
+ forecast_data: pd.DataFrame,
15
+ confidence_levels: List[int],
16
+ title: str = "Time Series Forecast",
17
+ y_axis_label: str = "Value",
18
+ backtest_data: pd.DataFrame = None
19
+ ) -> go.Figure:
20
+ """
21
+ Create an interactive forecast chart with confidence intervals
22
+
23
+ Args:
24
+ historical_data: DataFrame with columns ['ds', 'y']
25
+ forecast_data: DataFrame with forecast and confidence intervals
26
+ confidence_levels: List of confidence levels to plot
27
+ title: Chart title
28
+ y_axis_label: Label for y-axis (variable name being forecasted)
29
+ backtest_data: Optional DataFrame with backtest results
30
+
31
+ Returns:
32
+ Plotly figure
33
+ """
34
+ fig = go.Figure()
35
+
36
+ # Add historical data
37
+ fig.add_trace(go.Scatter(
38
+ x=historical_data['ds'],
39
+ y=historical_data['y'],
40
+ mode='lines',
41
+ name='Historical',
42
+ line=dict(color=COLORS['historical'], width=2),
43
+ hovertemplate=f'<b>Date:</b> %{{x}}<br><b>{y_axis_label}:</b> %{{y:.2f}}<extra></extra>'
44
+ ))
45
+
46
+ # Add backtest data if provided (shows model performance on historical data)
47
+ if backtest_data is not None and len(backtest_data) > 0:
48
+ # Add actual values from backtest period
49
+ fig.add_trace(go.Scatter(
50
+ x=backtest_data['timestamp'],
51
+ y=backtest_data['actual'],
52
+ mode='lines',
53
+ name='Backtest Actual',
54
+ line=dict(color='rgba(100, 100, 100, 0.6)', width=2, dash='dot'),
55
+ hovertemplate=f'<b>Date:</b> %{{x}}<br><b>{y_axis_label} (Actual):</b> %{{y:.2f}}<extra></extra>'
56
+ ))
57
+
58
+ # Add predicted values from backtest period
59
+ fig.add_trace(go.Scatter(
60
+ x=backtest_data['timestamp'],
61
+ y=backtest_data['predicted'],
62
+ mode='lines',
63
+ name='Backtest Predicted',
64
+ line=dict(color='rgba(255, 100, 100, 0.8)', width=2),
65
+ hovertemplate=f'<b>Date:</b> %{{x}}<br><b>{y_axis_label} (Predicted):</b> %{{y:.2f}}<extra></extra>'
66
+ ))
67
+
68
+ # Add confidence bands (from widest to narrowest)
69
+ for cl in sorted(confidence_levels, reverse=True):
70
+ lower_col = f'lower_{cl}'
71
+ upper_col = f'upper_{cl}'
72
+
73
+ if lower_col in forecast_data.columns and upper_col in forecast_data.columns:
74
+ # Add filled area for confidence interval
75
+ fig.add_trace(go.Scatter(
76
+ x=forecast_data['ds'].tolist() + forecast_data['ds'].tolist()[::-1],
77
+ y=forecast_data[upper_col].tolist() + forecast_data[lower_col].tolist()[::-1],
78
+ fill='toself',
79
+ fillcolor=COLORS['confidence'][cl],
80
+ line=dict(width=0),
81
+ name=f'{cl}% Confidence',
82
+ showlegend=True,
83
+ hoverinfo='skip'
84
+ ))
85
+
86
+ # Add forecast line
87
+ fig.add_trace(go.Scatter(
88
+ x=forecast_data['ds'],
89
+ y=forecast_data['forecast'],
90
+ mode='lines',
91
+ name='Forecast',
92
+ line=dict(color=COLORS['forecast'], width=2),
93
+ hovertemplate=f'<b>Date:</b> %{{x}}<br><b>{y_axis_label} (Forecast):</b> %{{y:.2f}}<extra></extra>'
94
+ ))
95
+
96
+ # Add vertical separator line
97
+ if len(historical_data) > 0:
98
+ last_historical_date = historical_data['ds'].iloc[-1]
99
+ # Use add_shape instead of add_vline to avoid Timestamp arithmetic issues
100
+ fig.add_shape(
101
+ type="line",
102
+ x0=last_historical_date,
103
+ x1=last_historical_date,
104
+ y0=0,
105
+ y1=1,
106
+ yref="paper",
107
+ line=dict(color=COLORS['separator'], dash="dash", width=1)
108
+ )
109
+ # Add annotation
110
+ fig.add_annotation(
111
+ x=last_historical_date,
112
+ y=1.0,
113
+ yref="paper",
114
+ text="Forecast Start",
115
+ showarrow=False,
116
+ yanchor="bottom"
117
+ )
118
+
119
+ # Update layout
120
+ fig.update_layout(
121
+ title=dict(text=title, x=0.5, xanchor='center'),
122
+ xaxis_title="Date",
123
+ yaxis_title=y_axis_label,
124
+ hovermode='x unified',
125
+ template='plotly_white',
126
+ height=700, # Increased height to accommodate rangeslider
127
+ showlegend=True,
128
+ legend=dict(
129
+ orientation="h",
130
+ yanchor="bottom",
131
+ y=1.02,
132
+ xanchor="right",
133
+ x=1
134
+ ),
135
+ margin=dict(l=50, r=50, t=80, b=150), # Increased bottom margin for larger rangeslider
136
+ xaxis=dict(
137
+ rangeslider=dict(
138
+ visible=True,
139
+ thickness=0.12 # Wider slider (12% of chart height)
140
+ ),
141
+ type='date'
142
+ )
143
+ )
144
+
145
+ # Update config
146
+ fig.update_layout(
147
+ modebar_add=['v1hovermode', 'toggleSpikelines']
148
+ )
149
+
150
+ return fig
151
+
152
+
153
+ def create_empty_chart(message: str = "No data available") -> go.Figure:
154
+ """
155
+ Create an empty placeholder chart
156
+
157
+ Args:
158
+ message: Message to display
159
+
160
+ Returns:
161
+ Plotly figure
162
+ """
163
+ fig = go.Figure()
164
+
165
+ fig.add_annotation(
166
+ text=message,
167
+ xref="paper",
168
+ yref="paper",
169
+ x=0.5,
170
+ y=0.5,
171
+ showarrow=False,
172
+ font=dict(size=20, color='gray')
173
+ )
174
+
175
+ fig.update_layout(
176
+ template='plotly_white',
177
+ height=600,
178
+ xaxis=dict(visible=False),
179
+ yaxis=dict(visible=False)
180
+ )
181
+
182
+ return fig
183
+
184
+
185
+ def create_metrics_display(metrics: dict, inference_time: float = None) -> list:
186
+ """
187
+ Create metrics display components
188
+
189
+ Args:
190
+ metrics: Dictionary of metric values
191
+ inference_time: Time taken for inference in seconds
192
+
193
+ Returns:
194
+ List of Dash components
195
+ """
196
+ import dash_bootstrap_components as dbc
197
+ from dash import html
198
+
199
+ metric_cards = []
200
+
201
+ # Add inference time if available
202
+ if inference_time is not None:
203
+ metric_cards.append(
204
+ dbc.Col([
205
+ dbc.Card([
206
+ dbc.CardBody([
207
+ html.H6("Inference Time", className="text-muted mb-2"),
208
+ html.H4(f"{inference_time:.2f}s")
209
+ ])
210
+ ], className="text-center")
211
+ ], md=2)
212
+ )
213
+
214
+ # Add other metrics
215
+ metric_names = {
216
+ 'MAE': 'Mean Absolute Error',
217
+ 'RMSE': 'Root Mean Squared Error',
218
+ 'MAPE': 'Mean Absolute % Error',
219
+ 'R2': 'R-Squared'
220
+ }
221
+
222
+ for key, name in metric_names.items():
223
+ if key in metrics and metrics[key] is not None:
224
+ value = metrics[key]
225
+ if key in ['MAPE']:
226
+ formatted_value = f"{value:.2f}%"
227
+ elif key == 'R2':
228
+ formatted_value = f"{value:.4f}"
229
+ else:
230
+ formatted_value = f"{value:.2f}"
231
+
232
+ metric_cards.append(
233
+ dbc.Col([
234
+ dbc.Card([
235
+ dbc.CardBody([
236
+ html.H6(name, className="text-muted mb-2"),
237
+ html.H4(formatted_value)
238
+ ])
239
+ ], className="text-center")
240
+ ], md=2)
241
+ )
242
+
243
+ return metric_cards
244
+
245
+
246
+ def create_backtest_metrics_display(metrics: dict) -> list:
247
+ """
248
+ Create backtest metrics display components
249
+
250
+ Args:
251
+ metrics: Dictionary of backtest metric values (MAE, RMSE, MAPE, R2)
252
+
253
+ Returns:
254
+ Dash component card
255
+ """
256
+ import dash_bootstrap_components as dbc
257
+ from dash import html
258
+
259
+ return dbc.Card([
260
+ dbc.CardHeader([
261
+ html.I(className="fas fa-chart-bar me-2"),
262
+ html.Span("Backtest Performance Metrics", className="fw-bold")
263
+ ]),
264
+ dbc.CardBody([
265
+ html.P("Model performance on historical data validation:", className="text-muted small mb-3"),
266
+ dbc.Row([
267
+ dbc.Col([
268
+ html.Small("MAE", className="text-muted"),
269
+ html.H5(f"{metrics.get('MAE', 0):.2f}", className="mb-0")
270
+ ], md=3),
271
+ dbc.Col([
272
+ html.Small("RMSE", className="text-muted"),
273
+ html.H5(f"{metrics.get('RMSE', 0):.2f}", className="mb-0")
274
+ ], md=3),
275
+ dbc.Col([
276
+ html.Small("MAPE", className="text-muted"),
277
+ html.H5(f"{metrics.get('MAPE', 0):.2f}%", className="mb-0")
278
+ ], md=3),
279
+ dbc.Col([
280
+ html.Small("R²", className="text-muted"),
281
+ html.H5(f"{metrics.get('R2', 0):.4f}", className="mb-0")
282
+ ], md=3),
283
+ ]),
284
+ html.Hr(),
285
+ html.Small([
286
+ html.I(className="fas fa-info-circle me-1"),
287
+ "Lower MAE/RMSE/MAPE and higher R² (closer to 1.0) indicate better model performance"
288
+ ], className="text-muted")
289
+ ])
290
+ ], className="mt-3")
291
+
292
+
293
+ def decimate_data(df: pd.DataFrame, max_points: int = 10000) -> pd.DataFrame:
294
+ """
295
+ Reduce number of data points for visualization
296
+
297
+ Args:
298
+ df: Input DataFrame
299
+ max_points: Maximum number of points to keep
300
+
301
+ Returns:
302
+ Decimated DataFrame
303
+ """
304
+ if len(df) <= max_points:
305
+ return df
306
+
307
+ # Use systematic sampling
308
+ step = len(df) // max_points
309
+ return df.iloc[::step].reset_index(drop=True)
components/controls.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Control components for forecast parameters
3
+ """
4
+
5
+ import dash
6
+ from dash import dcc, html
7
+ import dash_bootstrap_components as dbc
8
+ from config.constants import FORECAST_HORIZONS, CONFIDENCE_LEVELS
9
+
10
+
11
+ def create_forecast_controls():
12
+ """
13
+ Create forecast parameter controls
14
+
15
+ Returns:
16
+ Dash component
17
+ """
18
+ return dbc.Card([
19
+ dbc.CardHeader(html.H5("Forecasting Parameters", className="mb-0")),
20
+ dbc.CardBody([
21
+ # Forecast Horizon Slider
22
+ html.Label("Forecast Horizon (Days)", className="fw-bold"),
23
+ dcc.Slider(
24
+ id='horizon-slider',
25
+ min=1,
26
+ max=365,
27
+ step=1,
28
+ value=30,
29
+ marks={
30
+ 1: '1D',
31
+ 7: '1W',
32
+ 30: '1M',
33
+ 90: '3M',
34
+ 180: '6M',
35
+ 365: '1Y'
36
+ },
37
+ tooltip={"placement": "bottom", "always_visible": True},
38
+ className='mb-4'
39
+ ),
40
+
41
+ # Confidence Levels
42
+ html.Label("Confidence Levels", className="fw-bold mt-3"),
43
+ dbc.Checklist(
44
+ id='confidence-checklist',
45
+ options=[
46
+ {'label': '80%', 'value': 80},
47
+ {'label': '90%', 'value': 90},
48
+ {'label': '95%', 'value': 95},
49
+ {'label': '99%', 'value': 99},
50
+ ],
51
+ value=[80, 95],
52
+ inline=True,
53
+ className='mb-4'
54
+ ),
55
+
56
+ # Backtesting Section
57
+ html.Hr(),
58
+ html.Label("Model Performance Validation", className="fw-bold mt-3"),
59
+ dbc.Checklist(
60
+ id='backtest-enable',
61
+ options=[
62
+ {'label': ' Enable backtesting (show model performance on historical data)', 'value': 'enabled'}
63
+ ],
64
+ value=[],
65
+ className='mb-3'
66
+ ),
67
+
68
+ # Backtest Size Slider (only visible when backtest is enabled)
69
+ html.Div([
70
+ html.Label("Backtest Period (Days)", className="fw-bold"),
71
+ html.Small(" - Amount of historical data to use for validation", className="text-muted"),
72
+ dcc.Slider(
73
+ id='backtest-size-slider',
74
+ min=5,
75
+ max=180,
76
+ step=5,
77
+ value=30,
78
+ marks={
79
+ 5: '5D',
80
+ 30: '1M',
81
+ 60: '2M',
82
+ 90: '3M',
83
+ 180: '6M'
84
+ },
85
+ tooltip={"placement": "bottom", "always_visible": True},
86
+ className='mb-3'
87
+ ),
88
+ ], id='backtest-controls', style={'display': 'none'}),
89
+
90
+ # Generate Button
91
+ dbc.Button(
92
+ [
93
+ html.I(className="fas fa-chart-line me-2"),
94
+ "Generate Forecast"
95
+ ],
96
+ id='generate-forecast-btn',
97
+ color='primary',
98
+ size='lg',
99
+ className='w-100 mt-3',
100
+ disabled=True
101
+ ),
102
+
103
+ # Loading indicator
104
+ dcc.Loading(
105
+ id="loading-forecast",
106
+ type="default",
107
+ children=html.Div(id="loading-output")
108
+ )
109
+ ])
110
+ ], className='mb-4')
111
+
112
+
113
+ def create_model_status_bar(status: str = 'loading'):
114
+ """
115
+ Create model status indicator
116
+
117
+ Args:
118
+ status: 'loading', 'ready', 'error'
119
+
120
+ Returns:
121
+ Dash component
122
+ """
123
+ if status == 'loading':
124
+ return dbc.Alert([
125
+ dbc.Spinner(size="sm", className="me-2"),
126
+ html.Span("Loading Chronos 2 model...")
127
+ ], color='info', className='mb-4')
128
+ elif status == 'ready':
129
+ return dbc.Alert([
130
+ html.I(className="fas fa-check-circle me-2"),
131
+ html.Span("Model loaded and ready")
132
+ ], color='success', className='mb-4', dismissable=True)
133
+ elif status == 'error':
134
+ return dbc.Alert([
135
+ html.I(className="fas fa-exclamation-circle me-2"),
136
+ html.Span("Failed to load model. Please check logs.")
137
+ ], color='danger', className='mb-4')
138
+ else:
139
+ return html.Div()
140
+
141
+
142
+ def create_results_section():
143
+ """
144
+ Create the results visualization section
145
+
146
+ Returns:
147
+ Dash component
148
+ """
149
+ return dbc.Card([
150
+ dbc.CardHeader(html.H5("Forecast Results", className="mb-0")),
151
+ dbc.CardBody([
152
+ # Chart container
153
+ dcc.Graph(
154
+ id='forecast-chart',
155
+ config=create_chart_config(),
156
+ style={'height': '600px'}
157
+ ),
158
+
159
+ # Metrics row
160
+ html.Div(id='metrics-display', className='mt-4')
161
+ ])
162
+ ], className='mb-4', id='results-card', style={'display': 'none'})
163
+
164
+
165
+ def create_chart_config():
166
+ """
167
+ Create Plotly chart configuration
168
+
169
+ Returns:
170
+ Configuration dictionary
171
+ """
172
+ from config.constants import CHART_CONFIG
173
+ return CHART_CONFIG
174
+
175
+
176
+ def create_app_header():
177
+ """
178
+ Create application header
179
+
180
+ Returns:
181
+ Dash component
182
+ """
183
+ from config.settings import APP_METADATA
184
+
185
+ return dbc.Navbar(
186
+ dbc.Container([
187
+ dbc.Row([
188
+ dbc.Col([
189
+ html.Div([
190
+ html.H2(APP_METADATA['title'], className="mb-0 text-white"),
191
+ html.P(APP_METADATA['subtitle'], className="mb-0 text-white-50 small")
192
+ ])
193
+ ])
194
+ ], align="center", className="g-0 w-100")
195
+ ], fluid=True),
196
+ color="primary",
197
+ dark=True,
198
+ className="mb-4"
199
+ )
200
+
201
+
202
+ def create_footer():
203
+ """
204
+ Create application footer
205
+
206
+ Returns:
207
+ Dash component
208
+ """
209
+ from config.settings import APP_METADATA
210
+
211
+ return html.Footer([
212
+ html.Hr(),
213
+ dbc.Container([
214
+ dbc.Row([
215
+ dbc.Col([
216
+ html.Div([
217
+ html.P([
218
+ "Created by ",
219
+ html.A([
220
+ html.I(className="fab fa-linkedin me-1"),
221
+ "Abhay Pratap Singh"
222
+ ],
223
+ href="https://www.linkedin.com/in/mindful-abhay/",
224
+ target="_blank",
225
+ className="text-primary fw-bold",
226
+ style={'textDecoration': 'none'}
227
+ )
228
+ ], className="text-center mb-2"),
229
+ html.P([
230
+ html.A([
231
+ html.I(className="fas fa-coffee me-2"),
232
+ "Buy me a coffee"
233
+ ],
234
+ href="https://buymeacoffee.com/abhaypratapsingh",
235
+ target="_blank",
236
+ className="btn btn-outline-warning btn-sm"
237
+ )
238
+ ], className="text-center mb-2"),
239
+ html.P([
240
+ f"Version {APP_METADATA['version']}"
241
+ ], className="text-center text-muted small mb-0")
242
+ ])
243
+ ])
244
+ ])
245
+ ])
246
+ ], className="mt-5 mb-3")
247
+
248
+
249
+ def create_progress_indicator(progress: int, message: str = "Processing..."):
250
+ """
251
+ Create a progress indicator
252
+
253
+ Args:
254
+ progress: Progress percentage (0-100)
255
+ message: Progress message
256
+
257
+ Returns:
258
+ Dash component
259
+ """
260
+ return dbc.Card([
261
+ dbc.CardBody([
262
+ html.H6(message, className="mb-3"),
263
+ dbc.Progress(value=progress, striped=True, animated=True)
264
+ ])
265
+ ])
components/upload.py ADDED
@@ -0,0 +1,347 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ File upload component
3
+ """
4
+
5
+ import dash
6
+ from dash import dcc, html
7
+ import dash_bootstrap_components as dbc
8
+
9
+
10
+ def create_upload_component():
11
+ """
12
+ Create the file upload component with drag-and-drop
13
+
14
+ Returns:
15
+ Dash component
16
+ """
17
+ return dbc.Card([
18
+ dbc.CardHeader(html.H5("Data Input", className="mb-0")),
19
+ dbc.CardBody([
20
+ dcc.Upload(
21
+ id='upload-data',
22
+ children=html.Div([
23
+ html.I(className="fas fa-cloud-upload-alt fa-3x mb-3"),
24
+ html.H5('Drag and Drop or Click to Select File'),
25
+ html.P('Supported formats: CSV, Excel (max 100MB)', className='text-muted')
26
+ ]),
27
+ style={
28
+ 'width': '100%',
29
+ 'height': '150px',
30
+ 'lineHeight': '150px',
31
+ 'borderWidth': '2px',
32
+ 'borderStyle': 'dashed',
33
+ 'borderRadius': '10px',
34
+ 'textAlign': 'center',
35
+ 'backgroundColor': '#f8f9fa'
36
+ },
37
+ multiple=False
38
+ ),
39
+ html.Div(id='upload-status', className='mt-3'),
40
+ ])
41
+ ], className='mb-4')
42
+
43
+
44
+ def create_column_selector():
45
+ """
46
+ Create column mapping dropdowns with support for multivariate and covariate-informed forecasting
47
+
48
+ Returns:
49
+ Dash component
50
+ """
51
+ return dbc.Card([
52
+ dbc.CardHeader(html.H5("Data Configuration", className="mb-0")),
53
+ dbc.CardBody([
54
+ # Forecasting Mode Selector
55
+ dbc.Row([
56
+ dbc.Col([
57
+ dbc.Label("Forecasting Mode", className="fw-bold"),
58
+ dcc.RadioItems(
59
+ id='forecasting-mode',
60
+ options=[
61
+ {'label': ' Univariate (Single target)', 'value': 'univariate'},
62
+ {'label': ' Multivariate (Multiple targets)', 'value': 'multivariate'},
63
+ {'label': ' Covariate-informed (With external variables)', 'value': 'covariate'}
64
+ ],
65
+ value='univariate',
66
+ className='mt-2',
67
+ labelStyle={'display': 'block', 'marginBottom': '8px'}
68
+ ),
69
+ html.Small("Chronos-2 supports all three modes with zero-shot learning",
70
+ className='text-muted')
71
+ ], md=12),
72
+ ], className='mb-3'),
73
+
74
+ html.Hr(),
75
+
76
+ # Column Selection
77
+ dbc.Row([
78
+ dbc.Col([
79
+ dbc.Label("Date/Timestamp Column"),
80
+ dcc.Dropdown(
81
+ id='date-column-dropdown',
82
+ placeholder='Select date column...',
83
+ clearable=False
84
+ )
85
+ ], md=4),
86
+ dbc.Col([
87
+ dbc.Label("Target Variable(s)"),
88
+ dcc.Dropdown(
89
+ id='target-column-dropdown',
90
+ placeholder='Select target column(s)...',
91
+ clearable=False,
92
+ multi=True # Enable multi-select
93
+ ),
94
+ html.Small(id='target-help-text', className='text-muted')
95
+ ], md=4),
96
+ dbc.Col([
97
+ dbc.Label("ID Column (Optional)"),
98
+ dcc.Dropdown(
99
+ id='id-column-dropdown',
100
+ placeholder='Select ID column (optional)...',
101
+ clearable=True
102
+ ),
103
+ html.Small("For multiple time series", className='text-muted')
104
+ ], md=4),
105
+ ], className='mb-3'),
106
+
107
+ # Covariate Selection (shown only for covariate-informed mode)
108
+ html.Div([
109
+ dbc.Row([
110
+ dbc.Col([
111
+ dbc.Label("Covariate Columns"),
112
+ dcc.Dropdown(
113
+ id='covariate-columns-dropdown',
114
+ placeholder='Select covariate column(s)...',
115
+ clearable=True,
116
+ multi=True
117
+ ),
118
+ html.Small("External variables that may influence the forecast",
119
+ className='text-muted')
120
+ ], md=12),
121
+ ], className='mb-3'),
122
+ ], id='covariate-section', style={'display': 'none'}),
123
+
124
+ html.Hr(),
125
+ html.Div(id='data-preview-container', className='mt-3'),
126
+ html.Div(id='data-quality-report', className='mt-3')
127
+ ])
128
+ ], className='mb-4', id='column-selector-card', style={'display': 'none'})
129
+
130
+
131
+ def create_sample_data_loader():
132
+ """
133
+ Create sample data loader component
134
+
135
+ Returns:
136
+ Dash component
137
+ """
138
+ return dbc.Card([
139
+ dbc.CardBody([
140
+ html.H6("Quick Start with Sample Data"),
141
+ dbc.Row([
142
+ dbc.Col([
143
+ dbc.Button(
144
+ "Weather Stations",
145
+ id='load-weather',
146
+ color='outline-primary',
147
+ size='sm',
148
+ className='w-100 mb-2'
149
+ ),
150
+ ], md=4),
151
+ dbc.Col([
152
+ dbc.Button(
153
+ "Air Quality UCI",
154
+ id='load-airquality',
155
+ color='outline-primary',
156
+ size='sm',
157
+ className='w-100 mb-2'
158
+ ),
159
+ ], md=4),
160
+ dbc.Col([
161
+ dbc.Button(
162
+ "Bitcoin Price",
163
+ id='load-bitcoin',
164
+ color='outline-primary',
165
+ size='sm',
166
+ className='w-100 mb-2'
167
+ ),
168
+ ], md=4),
169
+ ]),
170
+ dbc.Row([
171
+ dbc.Col([
172
+ dbc.Button(
173
+ "S&P 500 Stock",
174
+ id='load-stock',
175
+ color='outline-primary',
176
+ size='sm',
177
+ className='w-100 mb-2'
178
+ ),
179
+ ], md=4),
180
+ dbc.Col([
181
+ dbc.Button(
182
+ "Traffic Speeds",
183
+ id='load-traffic',
184
+ color='outline-primary',
185
+ size='sm',
186
+ className='w-100 mb-2'
187
+ ),
188
+ ], md=4),
189
+ dbc.Col([
190
+ dbc.Button(
191
+ "Electricity Consumption",
192
+ id='load-electricity',
193
+ color='outline-primary',
194
+ size='sm',
195
+ className='w-100 mb-2'
196
+ ),
197
+ ], md=4),
198
+ ]),
199
+ ])
200
+ ], className='mb-4')
201
+
202
+
203
+ def format_upload_status(status: str, message: str, is_error: bool = False):
204
+ """
205
+ Format upload status message
206
+
207
+ Args:
208
+ status: Status type ('success', 'error', 'info')
209
+ message: Message to display
210
+ is_error: Whether this is an error message
211
+
212
+ Returns:
213
+ Dash component
214
+ """
215
+ if is_error or status == 'error':
216
+ return dbc.Alert([
217
+ html.I(className="fas fa-exclamation-circle me-2"),
218
+ message
219
+ ], color='danger', dismissable=True)
220
+ elif status == 'success':
221
+ return dbc.Alert([
222
+ html.I(className="fas fa-check-circle me-2"),
223
+ message
224
+ ], color='success', dismissable=True)
225
+ elif status == 'warning':
226
+ return dbc.Alert([
227
+ html.I(className="fas fa-exclamation-triangle me-2"),
228
+ message
229
+ ], color='warning', dismissable=True)
230
+ else:
231
+ return dbc.Alert([
232
+ html.I(className="fas fa-info-circle me-2"),
233
+ message
234
+ ], color='info', dismissable=True)
235
+
236
+
237
+ def create_data_preview_table(df, n_rows=10):
238
+ """
239
+ Create a data preview table
240
+
241
+ Args:
242
+ df: DataFrame to preview
243
+ n_rows: Number of rows to show
244
+
245
+ Returns:
246
+ Dash component
247
+ """
248
+ if df is None or df.empty:
249
+ return html.Div()
250
+
251
+ return html.Div([
252
+ html.H6("Data Preview"),
253
+ dbc.Table.from_dataframe(
254
+ df.head(n_rows),
255
+ striped=True,
256
+ bordered=True,
257
+ hover=True,
258
+ responsive=True,
259
+ size='sm'
260
+ ),
261
+ html.P(
262
+ f"Showing first {min(n_rows, len(df))} of {len(df)} rows",
263
+ className='text-muted small'
264
+ )
265
+ ])
266
+
267
+
268
+ def create_quality_report(report: dict):
269
+ """
270
+ Create a data quality report display
271
+
272
+ Args:
273
+ report: Quality report dictionary
274
+
275
+ Returns:
276
+ Dash component
277
+ """
278
+ if not report:
279
+ return html.Div()
280
+
281
+ # Build warning messages if needed
282
+ warnings = []
283
+ if report.get('sampled', False):
284
+ warnings.append(
285
+ dbc.Alert(
286
+ f"⚠️ Large dataset detected: Sampled from {report.get('original_points', 0):,} to {report.get('total_points', 0):,} rows (most recent data retained)",
287
+ color="warning",
288
+ className="mb-2"
289
+ )
290
+ )
291
+ if report.get('duplicates_removed', 0) > 0:
292
+ warnings.append(
293
+ dbc.Alert(
294
+ f"⚠️ Removed {report.get('duplicates_removed', 0):,} duplicate timestamps",
295
+ color="info",
296
+ className="mb-2"
297
+ )
298
+ )
299
+
300
+ return dbc.Card([
301
+ dbc.CardHeader(html.H6("Data Quality Report", className="mb-0")),
302
+ dbc.CardBody([
303
+ html.Div(warnings) if warnings else None,
304
+ dbc.Row([
305
+ dbc.Col([
306
+ html.Small("Total Points", className='text-muted'),
307
+ html.H6(f"{report.get('total_points', 0):,}")
308
+ ], md=3),
309
+ dbc.Col([
310
+ html.Small("Date Range", className='text-muted'),
311
+ html.H6(f"{report.get('date_range', {}).get('start', 'N/A')} to {report.get('date_range', {}).get('end', 'N/A')}",
312
+ style={'fontSize': '0.9rem'})
313
+ ], md=3),
314
+ dbc.Col([
315
+ html.Small("Frequency", className='text-muted'),
316
+ html.H6(report.get('frequency', 'Unknown'))
317
+ ], md=2),
318
+ dbc.Col([
319
+ html.Small("Missing Filled", className='text-muted'),
320
+ html.H6(str(report.get('missing_filled', 0)))
321
+ ], md=2),
322
+ dbc.Col([
323
+ html.Small("Outliers", className='text-muted'),
324
+ html.H6(str(report.get('outliers_detected', 0)))
325
+ ], md=2),
326
+ ]),
327
+ html.Hr(),
328
+ dbc.Row([
329
+ dbc.Col([
330
+ html.Small("Mean", className='text-muted'),
331
+ html.P(f"{report.get('statistics', {}).get('mean', 0):.2f}")
332
+ ], md=3),
333
+ dbc.Col([
334
+ html.Small("Std Dev", className='text-muted'),
335
+ html.P(f"{report.get('statistics', {}).get('std', 0):.2f}")
336
+ ], md=3),
337
+ dbc.Col([
338
+ html.Small("Min", className='text-muted'),
339
+ html.P(f"{report.get('statistics', {}).get('min', 0):.2f}")
340
+ ], md=3),
341
+ dbc.Col([
342
+ html.Small("Max", className='text-muted'),
343
+ html.P(f"{report.get('statistics', {}).get('max', 0):.2f}")
344
+ ], md=3),
345
+ ])
346
+ ])
347
+ ], className='mt-3')