File size: 5,766 Bytes
12f45c0
 
 
 
e1f5207
 
12f45c0
 
13db9d8
 
 
 
 
 
73e9c10
 
 
 
 
 
 
 
7ff8b4c
 
 
13db9d8
7ff8b4c
12f45c0
 
7ff8b4c
 
 
 
 
 
 
 
 
 
 
12f45c0
 
 
 
 
 
 
 
7ff8b4c
 
12f45c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31352ec
 
12f45c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27ce714
069627f
27ce714
12f45c0
 
069627f
12f45c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#!/usr/bin/env python3
"""
FBMC Chronos-2 Forecasting API
HuggingFace Space Gradio Interface
Version: 1.6.0 - Extended Context Window (2,160 hours = 90 days / 3 months)
FORCE REBUILD: Optimized for 96GB VRAM with memory profiling diagnostics
"""

# CRITICAL: Set PyTorch memory allocator config BEFORE any imports
# This prevents memory fragmentation issues that cause OOM even with sufficient free memory
# Must be set before torch is imported the first time (including via gradio or other dependencies)
import os
os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'expandable_segments:True'

# Redirect ALL caches to /tmp to prevent 50GB storage limit exceeded
# This is the most common cause of "no logs" silent failures on A100 Spaces
# See: https://huggingface.co/static-proxy/discuss.huggingface.co/t/how-to-fix-workload-evicted-storage-limit-exceeded-50g-error-in-huggingface-spaces/169258
os.environ['TORCH_HOME'] = '/tmp/torch_cache'
os.environ['HF_HOME'] = '/tmp/hf_home'
os.environ['TRANSFORMERS_CACHE'] = '/tmp/transformers_cache'
os.environ['HUB_DIR'] = '/tmp/torch_hub'

import sys
print(f"[STARTUP] Python version: {sys.version}", flush=True)
print(f"[STARTUP] Python path: {sys.path[:3]}", flush=True)
print(f"[STARTUP] PyTorch memory config: {os.environ.get('PYTORCH_CUDA_ALLOC_CONF')}", flush=True)

import gradio as gr
from datetime import datetime

print("[STARTUP] Basic imports successful", flush=True)

try:
    from src.forecasting.chronos_inference import run_inference
    print("[STARTUP] chronos_inference import successful", flush=True)
except Exception as e:
    print(f"[ERROR] Failed to import chronos_inference: {e}", flush=True)
    import traceback
    traceback.print_exc()
    run_inference = None


# Global configuration
FORECAST_TYPES = {
    "smoke_test": "Smoke Test (1 border × 7 days)",
    "full_14day": "Full Forecast (All borders × 14 days)"
}

print("[STARTUP] Configuration loaded", flush=True)


def forecast_api(run_date_str, forecast_type):
    """
    API endpoint for triggering forecasts.

    Args:
        run_date_str: Date in YYYY-MM-DD format
        forecast_type: 'smoke_test' or 'full_14day'

    Returns:
        Path to downloadable forecast results file
    """
    try:
        # Validate run date
        run_date = datetime.strptime(run_date_str, "%Y-%m-%d")

        # Run inference
        result_path = run_inference(
            run_date=run_date_str,
            forecast_type=forecast_type,
            output_dir="/tmp"
        )

        return result_path

    except Exception as e:
        error_msg = f"Error: {str(e)}"
        print(error_msg)
        # Return error message as text file
        error_path = "/tmp/error.txt"
        with open(error_path, 'w') as f:
            f.write(error_msg)
        return error_path


# Build Gradio interface
with gr.Blocks(title="FBMC Chronos-2 Forecasting") as demo:
    gr.Markdown("""
    # FBMC Chronos-2 Zero-Shot Forecasting API

    **Flow-Based Market Coupling** electricity flow forecasting using Amazon Chronos-2.

    This Space provides GPU-accelerated zero-shot inference for cross-border electricity flows.
    """)

    with gr.Row():
        with gr.Column():
            gr.Markdown("### Configuration")

            run_date_input = gr.Textbox(
                label="Run Date (YYYY-MM-DD)",
                value="2025-09-30",
                placeholder="2025-09-30",
                info="Date when forecast is made (data up to this date is historical)"
            )

            forecast_type_input = gr.Radio(
                choices=list(FORECAST_TYPES.keys()),
                value="smoke_test",
                label="Forecast Type",
                info="Smoke test: Quick validation (1 border, 7 days). Full: Production forecast (all borders, 14 days)"
            )

            submit_btn = gr.Button("Run Forecast", variant="primary")

        with gr.Column():
            gr.Markdown("### Results")

            output_file = gr.File(
                label="Download Forecast Results",
                type="filepath"
            )

            gr.Markdown("""
            **Output format**: Parquet file with columns:
            - `timestamp`: Hourly timestamps (D+1 to D+7 or D+14)
            - `{border}_median`: Median forecast (MW)
            - `{border}_q10`: 10th percentile (MW)
            - `{border}_q90`: 90th percentile (MW)

            **Inference environment**:
            - GPU: HuggingFace Space GPU (accelerated inference)
            - Model: amazon/chronos-2 (120M parameters)
            - Precision: bfloat16
            """)

    # Wire up the interface
    submit_btn.click(
        fn=forecast_api,
        inputs=[run_date_input, forecast_type_input],
        outputs=output_file
    )

    gr.Markdown("""
    ---
    ### About

    **Zero-shot forecasting**: No model training required. The pre-trained Chronos-2 model
    generalizes directly to FBMC cross-border flows using historical patterns and future covariates.

    **Features**:
    - 2,514 engineered features using past-only covariate masking
    - Known-future: weather, generation, load forecasts (615 features)
    - Past-only masked: CNEC outages, volatility, flows (1,899 features)
    - 24-month historical context (Oct 2023 - Oct 2025)
    - Time-aware extraction (prevents data leakage)
    - Probabilistic forecasts (9 quantiles: 1st/5th/10th/25th/50th/75th/90th/95th/99th)

    **Performance**:
    - Smoke test: ~30 seconds (1 border × 168 hours)
    - Full forecast: ~5 minutes (38 borders × 336 hours)

    **Project**: FBMC Flow Forecasting MVP | **Author**: Evgueni Poloukarov
    """)

# Launch the app
if __name__ == "__main__":
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=False
    )