A newer version of the Gradio SDK is available: 6.13.0
Now I have a comprehensive understanding of the ecosystem. Let me create a detailed implementation plan for your time series forecasting Hugging Face Space.
Time Series Forecasting HF Space - Implementation Plan Overview Build a Gradio-based Hugging Face Space that allows users to upload time series data, run predictions using multiple foundation models (starting with Toto), compare model outputs visually, and optionally evaluate against ground truth.
Phase 1: Core Infrastructure & Toto Model Integration Step 1.1: Project Setup Create the basic HF Space structure: timeseries-forecasting-space/ โโโ app.py # Main Gradio application โโโ requirements.txt # Dependencies โโโ models/ โ โโโ init.py โ โโโ base_model.py # Abstract base class for all models โ โโโ toto_model.py # Toto model wrapper โโโ utils/ โ โโโ init.py โ โโโ data_processing.py # Data loading, validation, preprocessing โ โโโ visualization.py # Plotting functions โ โโโ metrics.py # Evaluation metrics (MAE, RMSE, MASE, sMAPE, etc.) โโโ README.md โโโ examples/ # Sample CSV files for users to try โโโ sample_univariate.csv โโโ sample_multivariate.csv Step 1.2: Data Processing Module (utils/data_processing.py) Implement functions to:
load_timeseries_from_file(file)
Accept CSV/Excel uploads Auto-detect timestamp column (look for datetime-like columns) Auto-detect target column(s) (numeric columns) Handle both univariate and multivariate data Return pandas DataFrame with standardized format
validate_timeseries(df)
Check for missing values (offer interpolation options) Validate timestamp continuity Check minimum length requirements for models Return validation report
preprocess_for_model(df, model_name, prediction_length)
Convert to model-specific input format Handle frequency inference Split into context (history) and optional holdout
infer_frequency(df, timestamp_col)
Auto-detect time series frequency (hourly, daily, etc.)
Step 1.3: Base Model Interface (models/base_model.py) Create abstract base class: pythonfrom abc import ABC, abstractmethod
class BaseForecastModel(ABC): @abstractmethod def load_model(self): """Load/initialize the model""" pass
@abstractmethod
def predict(self, context_data, prediction_length, **kwargs):
"""
Generate forecasts
Returns: dict with keys:
- 'mean': point forecast (array)
- 'quantiles': dict of quantile forecasts (optional)
- 'samples': raw samples if available (optional)
"""
pass
@abstractmethod
def get_model_info(self):
"""Return model metadata (name, description, supports_multivariate, etc.)"""
pass
Step 1.4: Toto Model Wrapper (models/toto_model.py) Implement Toto integration: pythonclass TotoModel(BaseForecastModel): def init(self, device='cuda' if torch.cuda.is_available() else 'cpu'): self.device = device self.model = None self.forecaster = None
def load_model(self):
from toto.model.toto import Toto
from toto.inference.forecaster import TotoForecaster
self.model = Toto.from_pretrained('Datadog/Toto-Open-Base-1.0').to(self.device)
self.forecaster = TotoForecaster(self.model.model)
def predict(self, context_data, prediction_length, num_samples=256, **kwargs):
# Convert pandas DataFrame to MaskedTimeseries format
# context_data: DataFrame with timestamp index, numeric columns as variates
from toto.data.util.dataset import MaskedTimeseries
# Prepare input tensors
series = torch.tensor(context_data.values.T, dtype=torch.float32).to(self.device)
# ... handle timestamp_seconds, time_interval_seconds
inputs = MaskedTimeseries(
series=series,
padding_mask=torch.full_like(series, True, dtype=torch.bool),
id_mask=torch.zeros_like(series),
timestamp_seconds=timestamp_seconds,
time_interval_seconds=time_interval_seconds,
)
forecast = self.forecaster.forecast(
inputs,
prediction_length=prediction_length,
num_samples=num_samples,
samples_per_batch=min(num_samples, 256),
)
return {
'mean': forecast.median.cpu().numpy(), # or use median
'quantiles': {
0.1: forecast.quantile(0.1).cpu().numpy(),
0.5: forecast.quantile(0.5).cpu().numpy(),
0.9: forecast.quantile(0.9).cpu().numpy(),
},
'samples': forecast.samples.cpu().numpy() if hasattr(forecast, 'samples') else None
}
def get_model_info(self):
return {
'name': 'Toto',
'full_name': 'Toto-Open-Base-1.0',
'description': 'Time Series Optimized Transformer for Observability by Datadog',
'supports_multivariate': True,
'supports_covariates': False,
'max_context_length': 4096,
'parameters': '151M',
}
Step 1.5: Visualization Module (utils/visualization.py) Implement plotting functions using Plotly (for interactive plots):
plot_forecast(history_df, forecast_dict, ground_truth=None, model_name='Model')
Plot historical data Plot point forecast with confidence intervals (quantiles) Optionally overlay ground truth Support multivariate (subplot per variable or selectable)
plot_model_comparison(history_df, forecasts_dict, ground_truth=None)
forecasts_dict: {model_name: forecast_dict} Overlay multiple model predictions Color-code by model
plot_residuals(ground_truth, predictions, model_name)
Error distribution plot Residuals over time
Step 1.6: Metrics Module (utils/metrics.py) Implement evaluation metrics: pythondef calculate_metrics(y_true, y_pred, seasonality=1): """ Returns dict of metrics: - MAE, RMSE, MAPE, sMAPE, MASE, WAPE """ pass
def create_metrics_table(ground_truth, predictions_dict): """ predictions_dict: {model_name: predictions_array} Returns pandas DataFrame comparison table """ pass
Phase 2: Gradio Interface (app.py) Step 2.1: Main Layout Structure Use gr.Blocks() for complex layout: pythonimport gradio as gr
with gr.Blocks(title="Time Series Forecasting Playground") as demo: gr.Markdown("# ๐ฎ Time Series Forecasting Playground") gr.Markdown("Upload your time series data and compare predictions from state-of-the-art models")
with gr.Row():
# Left column: Data Upload & Configuration
with gr.Column(scale=1):
# Data upload section
# Model selection section
# Parameters section
# Right column: Visualization & Results
with gr.Column(scale=2):
# Plots
# Metrics tables
Step 2.2: Data Upload Section pythonwith gr.Group(): gr.Markdown("### ๐ Data Upload")
file_upload = gr.File(
label="Upload Time Series (CSV/Excel)",
file_types=[".csv", ".xlsx", ".xls"]
)
# After upload, show data preview
data_preview = gr.DataFrame(
label="Data Preview (first 10 rows)",
interactive=False
)
# Column configuration (auto-detected but editable)
with gr.Row():
timestamp_col = gr.Dropdown(label="Timestamp Column", choices=[])
target_cols = gr.Dropdown(
label="Target Column(s)",
choices=[],
multiselect=True
)
# Optional: Upload ground truth for evaluation
with gr.Accordion("๐ Upload Ground Truth (Optional)", open=False):
ground_truth_file = gr.File(
label="Ground Truth for Evaluation",
file_types=[".csv", ".xlsx"]
)
Step 2.3: Model Selection Section pythonwith gr.Group(): gr.Markdown("### ๐ค Model Selection")
model_checkboxes = gr.CheckboxGroup(
choices=["Toto"], # Will expand: ["Toto", "Chronos-2", "Chronos-Bolt", ...]
value=["Toto"],
label="Select Models to Run"
)
# Model info accordion
with gr.Accordion("Model Information", open=False):
model_info_display = gr.Markdown()
Step 2.4: Forecast Parameters Section pythonwith gr.Group(): gr.Markdown("### โ๏ธ Forecast Parameters")
prediction_length = gr.Slider(
minimum=1,
maximum=720,
value=24,
step=1,
label="Prediction Horizon (steps)"
)
num_samples = gr.Slider(
minimum=50,
maximum=500,
value=256,
step=50,
label="Number of Samples (for probabilistic forecast)"
)
with gr.Row():
show_confidence = gr.Checkbox(
value=True,
label="Show Confidence Intervals"
)
confidence_level = gr.Dropdown(
choices=["80%", "90%", "95%"],
value="90%",
label="Confidence Level"
)
run_button = gr.Button("๐ Generate Forecasts", variant="primary")
Step 2.5: Results Display Section pythonwith gr.Group(): gr.Markdown("### ๐ Results")
# Main forecast plot
forecast_plot = gr.Plot(label="Forecast Visualization")
# Variable selector for multivariate
variable_selector = gr.Dropdown(
label="Select Variable to Display",
choices=[],
visible=False # Show only for multivariate
)
# Tabs for different views
with gr.Tabs():
with gr.Tab("Comparison Plot"):
comparison_plot = gr.Plot(label="Model Comparison")
with gr.Tab("Metrics"):
metrics_table = gr.DataFrame(
label="Evaluation Metrics",
interactive=False
)
with gr.Tab("Residuals"):
residuals_plot = gr.Plot(label="Residual Analysis")
# Download results
with gr.Row():
download_predictions = gr.File(label="Download Predictions (CSV)")
download_metrics = gr.File(label="Download Metrics (CSV)")
Step 2.6: Event Handlers python# On file upload: parse and preview data file_upload.change( fn=handle_file_upload, inputs=[file_upload], outputs=[data_preview, timestamp_col, target_cols, ...] )
On run button click
run_button.click( fn=run_forecasts, inputs=[ file_upload, timestamp_col, target_cols, model_checkboxes, prediction_length, num_samples, ground_truth_file, show_confidence, confidence_level ], outputs=[ forecast_plot, comparison_plot, metrics_table, residuals_plot, download_predictions, download_metrics, variable_selector ] )
Variable selector for multivariate update
variable_selector.change( fn=update_plot_for_variable, inputs=[variable_selector, ...], outputs=[forecast_plot] ) Step 2.7: Core Function Implementations pythondef handle_file_upload(file): """ Parse uploaded file, detect columns, return preview """ df = load_timeseries_from_file(file) validation = validate_timeseries(df)
# Auto-detect timestamp and target columns
timestamp_col = detect_timestamp_column(df)
target_cols = detect_numeric_columns(df)
return (
df.head(10), # preview
timestamp_col, # dropdown selection
target_cols, # dropdown choices
validation['report'] # any warnings
)
def run_forecasts(file, ts_col, target_cols, models, pred_len, n_samples, gt_file, show_ci, ci_level): """ Main orchestration function """ # 1. Load and preprocess data df = load_timeseries_from_file(file)
# 2. Load ground truth if provided
ground_truth = None
if gt_file:
ground_truth = load_timeseries_from_file(gt_file)
# 3. Run each selected model
results = {}
for model_name in models:
model = MODEL_REGISTRY[model_name]()
model.load_model()
context_data = preprocess_for_model(df, model_name, pred_len)
forecast = model.predict(context_data, pred_len, num_samples=n_samples)
results[model_name] = forecast
# 4. Generate visualizations
forecast_fig = plot_forecast(df, results[models[0]], ground_truth, models[0])
comparison_fig = plot_model_comparison(df, results, ground_truth)
# 5. Calculate metrics if ground truth provided
metrics_df = None
residuals_fig = None
if ground_truth is not None:
metrics_df = create_metrics_table(ground_truth, results)
residuals_fig = plot_residuals(ground_truth, results)
# 6. Prepare downloadable files
predictions_csv = create_predictions_csv(results)
metrics_csv = metrics_df.to_csv() if metrics_df is not None else None
return (
forecast_fig, comparison_fig, metrics_df,
residuals_fig, predictions_csv, metrics_csv,
target_cols # for variable selector
)
Phase 3: Add More Models (Incremental) Step 3.1: Chronos-2 Model (models/chronos_model.py) pythonclass Chronos2Model(BaseForecastModel): def load_model(self): from chronos import Chronos2Pipeline self.pipeline = Chronos2Pipeline.from_pretrained( "amazon/chronos-2", device_map="cuda" if torch.cuda.is_available() else "cpu" )
def predict(self, context_df, prediction_length, **kwargs):
# Chronos-2 uses DataFrame format directly
pred_df = self.pipeline.predict_df(
context_df,
prediction_length=prediction_length,
quantile_levels=[0.1, 0.5, 0.9],
id_column='id',
timestamp_column='timestamp',
target='target'
)
# Convert to standard format
return self._format_output(pred_df)
def get_model_info(self):
return {
'name': 'Chronos-2',
'description': 'Universal forecasting model by Amazon',
'supports_multivariate': True,
'supports_covariates': True,
}
Step 3.2: Chronos-Bolt Model (models/chronos_bolt_model.py) Similar wrapper for faster inference. Step 3.3: Statistical Baselines (models/baselines.py) Add simple baselines for comparison:
Naive (last value repeat) Seasonal Naive Moving Average AutoARIMA (via statsforecast)
Step 3.4: Update Model Registry pythonMODEL_REGISTRY = { 'Toto': TotoModel, 'Chronos-2': Chronos2Model, 'Chronos-Bolt': ChronosBoltModel, 'Naive': NaiveModel, 'AutoARIMA': AutoARIMAModel, } Step 3.5: Update UI pythonmodel_checkboxes = gr.CheckboxGroup( choices=list(MODEL_REGISTRY.keys()), value=["Toto"], label="Select Models to Run" )
Phase 4: Enhanced Features Step 4.1: Covariate Support For models that support covariates (Chronos-2): pythonwith gr.Accordion("๐ Covariates (Optional)", open=False): covariate_cols = gr.Dropdown( label="Known Future Covariates", choices=[], multiselect=True ) past_covariate_cols = gr.Dropdown( label="Past-only Covariates", choices=[], multiselect=True ) Step 4.2: Batch Processing For multiple time series in one file: pythonwith gr.Accordion("๐ Batch Mode", open=False): id_column = gr.Dropdown( label="Time Series ID Column (for batch)", choices=[] ) # Process each series independently Step 4.3: Export & Sharing pythonwith gr.Row(): export_config = gr.Button("๐ Export Configuration") share_link = gr.Button("๐ Generate Shareable Link") Step 4.4: Example Datasets pythongr.Examples( examples=[ ["examples/sample_univariate.csv", "timestamp", ["value"], ["Toto"], 24], ["examples/sample_multivariate.csv", "date", ["temp", "sales"], ["Toto", "Chronos-2"], 48], ], inputs=[file_upload, timestamp_col, target_cols, model_checkboxes, prediction_length] )
---
## **Phase 5: Deployment & Requirements**
### **Step 5.1: requirements.txt**
gradio>=4.0.0 pandas>=2.0.0 numpy>=1.24.0 plotly>=5.18.0 torch>=2.0.0 toto-ts>=0.1.0 chronos-forecasting>=1.0.0 autogluon.timeseries>=1.5.0 statsforecast>=1.7.0 scikit-learn>=1.3.0 openpyxl>=3.1.0 # For Excel support Step 5.2: README.md for HF Space yaml--- title: Time Series Forecasting Playground emoji: ๐ฎ colorFrom: blue colorTo: purple sdk: gradio sdk_version: 4.44.0 app_file: app.py pinned: true license: apache-2.0 suggested_hardware: t4-small # GPU for Toto
Step 5.3: Hardware Considerations
CPU Mode: Enable fallback for Toto/Chronos with warning about slower inference GPU Mode: Use T4 or better for reasonable inference speed Memory: Toto requires ~2-3GB VRAM, Chronos-2 similar
Summary: Implementation Order StepDescriptionPriority1Project structure + data processing utilsHigh2Base model interface + Toto wrapperHigh3Basic Gradio UI (upload + single model)High4Visualization (forecast plot)High5Metrics module + ground truth comparisonMedium6Model comparison visualizationMedium7Add Chronos-2 modelMedium8Add statistical baselinesLow9Covariate supportLow10Batch processingLow11Example datasets + documentationMedium
This plan gives your coder agent everything needed to build the Space incrementally, starting with Toto as the first model, then expanding to support model comparison and additional models like Chronos-2.