cams-pollution-dashboard / templates /aurora_predict.html
aditya-me13's picture
No Emojii
808378f
raw
history blame
21.7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Aurora ML Predictions - CAMS Pollution Dashboard</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 40px;
color: white;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.header p {
font-size: 1.2em;
opacity: 0.9;
}
.form-container {
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
padding: 40px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
}
.form-group {
margin-bottom: 25px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: bold;
color: #555;
}
.form-group input, .form-group select {
width: 100%;
padding: 15px;
border: 2px solid #e1e1e1;
border-radius: 8px;
font-size: 16px;
transition: border-color 0.3s ease;
}
.form-group input:focus, .form-group select:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.info-box {
background: #f8f9ff;
border: 2px solid #e3e7ff;
border-radius: 10px;
padding: 20px;
margin-bottom: 25px;
}
.info-box h3 {
color: #4c63d2;
margin-bottom: 10px;
}
.info-box ul {
margin-left: 20px;
color: #666;
}
.info-box li {
margin-bottom: 5px;
}
.btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 15px 30px;
border: none;
border-radius: 8px;
font-size: 18px;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
width: 100%;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
}
.btn:active {
transform: translateY(0);
}
.btn:disabled {
background: #bdc3c7;
cursor: not-allowed;
transform: none;
}
/* Loading Animation Styles */
.loading-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
z-index: 9999;
justify-content: center;
align-items: center;
flex-direction: column;
}
.loading-content {
background: white;
padding: 40px;
border-radius: 20px;
text-align: center;
max-width: 500px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
.loading-spinner {
width: 80px;
height: 80px;
border: 8px solid #f3f3f3;
border-top: 8px solid #667eea;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.progress-bar {
width: 100%;
height: 20px;
background: #f0f0f0;
border-radius: 10px;
overflow: hidden;
margin: 20px 0;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2);
border-radius: 10px;
width: 0%;
transition: width 0.3s ease;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
.loading-steps {
text-align: left;
margin-top: 20px;
}
.loading-step {
padding: 8px 0;
display: flex;
align-items: center;
font-size: 14px;
}
.step-icon {
width: 20px;
height: 20px;
border-radius: 50%;
margin-right: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
.step-pending {
background: #f0f0f0;
color: #999;
}
.step-active {
background: #667eea;
color: white;
animation: pulse 1s infinite;
}
.step-complete {
background: #28a745;
color: white;
}
.aurora-icon {
font-size: 3em;
margin-bottom: 15px;
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}
.back-link {
display: inline-block;
margin-bottom: 20px;
color: white;
text-decoration: none;
font-size: 16px;
transition: opacity 0.3s ease;
}
.back-link:hover {
opacity: 0.8;
}
.back-link::before {
content: "← ";
}
.warning-box {
background: #fff8e1;
border: 2px solid #ffcc02;
border-radius: 10px;
padding: 20px;
margin-bottom: 25px;
}
.warning-box h3 {
color: #f57c00;
margin-bottom: 10px;
}
@media (max-width: 768px) {
.container {
padding: 10px;
}
.form-container {
padding: 20px;
}
.header h1 {
font-size: 2em;
}
}
</style>
</head>
<body>
<div class="container">
<a href="{{ url_for('index') }}" class="back-link">Back to Main Dashboard</a>
<div class="header">
<h1>Aurora ML Predictions</h1>
<p>Generate AI-powered air pollution forecasts using Microsoft's Aurora model</p>
</div>
<div class="form-container">
<div class="info-box">
<h3>Enhanced Aurora Features</h3>
<ul>
<li><strong>Dual Time Input:</strong> Uses both T-1 (00:00) and T (12:00) timestamps for better accuracy</li>
<li><strong>Forward Predictions:</strong> Generate 1-4 steps forward, each covering 12 hours</li>
<li><strong>Organized Storage:</strong> Results saved in dated folders for easy management</li>
<li><strong>Multiple Variables:</strong> Predicts PM1, PM2.5, PM10, O₃, NOβ‚‚, CO, SOβ‚‚ and meteorological variables</li>
<li><strong>Enhanced Visualization:</strong> Step-by-step analysis with time progression</li>
</ul>
</div>
<div class="warning-box">
<h3>Performance Notes</h3>
<p><strong>CPU Mode:</strong> Aurora will run on CPU for local testing. This is slower but doesn't require GPU.</p>
<p><strong>GPU Mode:</strong> If CUDA GPU is available, Aurora will use it for faster predictions.</p>
<p><strong>Processing Time:</strong> CPU: 5-15 minutes per step | GPU: 1-3 minutes total</p>
<p><strong>Memory:</strong> CPU mode automatically limits to 2 steps to prevent memory issues.</p>
<p><strong>Coverage:</strong> Each step predicts 12 hours forward (max 48 hours with 4 steps).</p>
</div>
<form method="POST">
<div class="form-group">
<label for="date">Select Date for Initial Conditions:</label>
<input type="date"
id="date"
name="date"
value="{{ current_date }}"
min="2015-01-01"
max="{{ current_date }}"
required>
<small style="color: #666; font-size: 14px;">
Aurora will download CAMS data for this date and generate forecasts
</small>
</div>
<div class="form-group">
<label for="steps">Number of Forward Prediction Steps:</label>
<select id="steps" name="steps" required>
<option value="1">1 step (12 hours forward) - Fastest</option>
<option value="2" selected>2 steps (24 hours forward) - CPU Friendly</option>
<option value="3">3 steps (36 hours forward) - Recommended</option>
<option value="4">4 steps (48 hours forward) - Maximum</option>
</select>
<small style="color: #666; font-size: 14px;">
Each step represents 12 hours forward from the initial conditions.
Aurora uses T-1 (00:00) and T (12:00) as input, then predicts forward.
</small>
</div>
<button type="submit" class="btn" id="predictBtn">
Generate Aurora Predictions
</button>
</form>
<!-- Loading Overlay -->
<div class="loading-overlay" id="loadingOverlay">
<div class="loading-content">
<div class="aurora-icon"></div>
<h2 style="color: #667eea; margin-bottom: 10px;">Aurora AI Processing</h2>
<p style="color: #666; margin-bottom: 20px;">Generating atmospheric predictions using Microsoft's Aurora model...</p>
<div class="loading-spinner"></div>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div id="currentStep" style="font-weight: bold; color: #667eea; margin-bottom: 20px;">
Initializing Aurora pipeline...
</div>
<div class="loading-steps">
<div class="loading-step">
<div class="step-icon step-pending" id="step1">1</div>
<span>Downloading CAMS atmospheric data</span>
</div>
<div class="loading-step">
<div class="step-icon step-pending" id="step2">2</div>
<span>Loading Aurora ML model</span>
</div>
<div class="loading-step">
<div class="step-icon step-pending" id="step3">3</div>
<span>Processing initial conditions</span>
</div>
<div class="loading-step">
<div class="step-icon step-pending" id="step4">4</div>
<span>Running AI predictions</span>
</div>
<div class="loading-step">
<div class="step-icon step-pending" id="step5">5</div>
<span>Saving results and preparing visualization</span>
</div>
</div>
<p style="margin-top: 20px; font-size: 12px; color: #999;">
<strong>Estimated time:</strong> <span id="estimatedTime">2-5 minutes</span><br>
This may take longer on CPU-only systems.
</p>
</div>
</div>
<div style="margin-top: 30px; padding: 20px; background: #f5f5f5; border-radius: 10px;">
<h3 style="color: #555; margin-bottom: 15px;">What You'll Get:</h3>
<ul style="color: #666; margin-left: 20px;">
<li>Interactive visualization of predicted air pollution concentrations</li>
<li>Step-by-step forecast evolution over time</li>
<li>Downloadable NetCDF files with all prediction data</li>
<li>Support for all major pollutants and meteorological variables</li>
</ul>
</div>
</div>
</div>
<script>
// Aurora Prediction Loading Animation
class AuroraLoadingManager {
constructor() {
this.form = document.querySelector('form');
this.predictBtn = document.getElementById('predictBtn');
this.overlay = document.getElementById('loadingOverlay');
this.progressFill = document.getElementById('progressFill');
this.currentStep = document.getElementById('currentStep');
this.estimatedTime = document.getElementById('estimatedTime');
this.steps = [
{ id: 'step1', text: 'Downloading CAMS atmospheric data...', duration: 20000 },
{ id: 'step2', text: 'Loading Aurora ML model into memory...', duration: 30000 },
{ id: 'step3', text: 'Processing initial atmospheric conditions...', duration: 15000 },
{ id: 'step4', text: 'Running AI predictions (this may take a while)...', duration: 60000 },
{ id: 'step5', text: 'Saving results and preparing visualization...', duration: 10000 }
];
this.currentStepIndex = 0;
this.startTime = null;
this.init();
}
init() {
this.form.addEventListener('submit', (e) => {
this.startLoading();
});
}
startLoading() {
this.startTime = Date.now();
this.overlay.style.display = 'flex';
this.predictBtn.disabled = true;
// Estimate time based on selected steps
const steps = parseInt(document.getElementById('steps').value);
const isCPU = this.detectCPUMode();
this.updateEstimatedTime(steps, isCPU);
// Start progress simulation
this.simulateProgress();
}
detectCPUMode() {
// Simple heuristic - if user selected fewer steps, likely CPU mode
const steps = parseInt(document.getElementById('steps').value);
return steps <= 2;
}
updateEstimatedTime(steps, isCPU) {
// Fetch actual system capabilities for better estimates
fetch('/api/aurora_status')
.then(response => response.json())
.then(data => {
if (data.available) {
const mode = data.cpu_only ? 'cpu' : 'gpu';
let estimatedMinutes;
if (mode === 'cpu') {
estimatedMinutes = steps <= 1 ? 5 : 8;
} else {
estimatedMinutes = Math.max(2, steps * 0.5 + 2);
}
this.estimatedTime.textContent = `${estimatedMinutes}-${estimatedMinutes + 2} minutes (${mode.toUpperCase()} mode)`;
} else {
this.estimatedTime.textContent = 'Aurora not available';
}
})
.catch(() => {
// Fallback to original logic
let baseTime = steps * (isCPU ? 5 : 1);
baseTime += 2;
this.estimatedTime.textContent = `${baseTime}-${baseTime + 2} minutes`;
});
}
simulateProgress() {
let totalDuration = this.steps.reduce((sum, step) => sum + step.duration, 0);
let elapsed = 0;
this.progressSteps(0);
}
progressSteps(stepIndex) {
if (stepIndex >= this.steps.length) {
return; // Let the actual response handle completion
}
const step = this.steps[stepIndex];
const stepElement = document.getElementById(step.id);
// Mark previous steps as complete
for (let i = 0; i < stepIndex; i++) {
const prevStep = document.getElementById(this.steps[i].id);
prevStep.className = 'step-icon step-complete';
prevStep.innerHTML = 'βœ“';
}
// Mark current step as active
stepElement.className = 'step-icon step-active';
this.currentStep.textContent = step.text;
// Update progress bar
const progress = ((stepIndex + 1) / this.steps.length) * 100;
this.progressFill.style.width = `${progress}%`;
// Move to next step after duration
setTimeout(() => {
this.progressSteps(stepIndex + 1);
}, step.duration);
}
// Call this when the actual response is received
completeLoading() {
// Mark all steps as complete
this.steps.forEach((step, index) => {
const stepElement = document.getElementById(step.id);
stepElement.className = 'step-icon step-complete';
stepElement.innerHTML = 'βœ“';
});
this.progressFill.style.width = '100%';
this.currentStep.textContent = 'Complete! Redirecting to results...';
// Hide overlay after a short delay
setTimeout(() => {
this.overlay.style.display = 'none';
this.predictBtn.disabled = false;
}, 2000);
}
}
// Initialize loading manager when page loads
document.addEventListener('DOMContentLoaded', function() {
window.auroraLoader = new AuroraLoadingManager();
// Handle form validation
const form = document.querySelector('form');
const dateInput = document.getElementById('date');
const stepsSelect = document.getElementById('steps');
form.addEventListener('submit', function(e) {
if (!dateInput.value) {
e.preventDefault();
alert('Please select a date for the prediction.');
return;
}
const selectedDate = new Date(dateInput.value);
const today = new Date();
const minDate = new Date('2015-01-01');
if (selectedDate > today || selectedDate < minDate) {
e.preventDefault();
alert('Please select a date between 2015-01-01 and today.');
return;
}
});
// Update step recommendations based on selection
stepsSelect.addEventListener('change', function() {
const steps = parseInt(this.value);
const recommendations = {
1: 'Fastest option - good for testing',
2: 'CPU-friendly - recommended for local development',
4: 'Standard forecast - good for GPU systems',
6: 'Extended forecast - GPU recommended',
8: 'Long-range forecast - GPU required',
10: 'Maximum forecast - GPU required'
};
const small = this.parentNode.querySelector('small');
small.textContent = `Each step represents 6 hours. ${recommendations[steps] || 'Custom selection'}`;
});
});
</script>
</body>
</html>