Files
gogo2/ANNOTATE/web/templates/components/inference_panel.html
Dobromir Popov a520ed7e39 folder rename
2025-10-18 16:39:15 +03:00

254 lines
9.8 KiB
HTML

<div class="inference-panel">
<!-- Inference Controls -->
<div class="row mb-3">
<div class="col-md-8">
<h6>Inference Simulation</h6>
<p class="text-muted small mb-0">
Replay annotated periods with model predictions to measure performance
</p>
</div>
<div class="col-md-4 text-end">
<div class="btn-group" role="group">
<button class="btn btn-sm btn-outline-primary" id="inference-play-btn">
<i class="fas fa-play"></i>
</button>
<button class="btn btn-sm btn-outline-primary" id="inference-pause-btn" disabled>
<i class="fas fa-pause"></i>
</button>
<button class="btn btn-sm btn-outline-primary" id="inference-stop-btn" disabled>
<i class="fas fa-stop"></i>
</button>
</div>
<select class="form-select form-select-sm d-inline-block w-auto ms-2" id="inference-speed-select">
<option value="1">1x</option>
<option value="2">2x</option>
<option value="5">5x</option>
<option value="10">10x</option>
</select>
</div>
</div>
<!-- Inference Chart -->
<div class="row mb-3">
<div class="col-12">
<div id="inference-chart" style="height: 400px;"></div>
</div>
</div>
<!-- Performance Metrics -->
<div class="row">
<div class="col-md-3">
<div class="card bg-dark">
<div class="card-body text-center py-2">
<div class="small text-muted">Accuracy</div>
<div class="h4 mb-0" id="metric-accuracy">--</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-dark">
<div class="card-body text-center py-2">
<div class="small text-muted">Precision</div>
<div class="h4 mb-0" id="metric-precision">--</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-dark">
<div class="card-body text-center py-2">
<div class="small text-muted">Recall</div>
<div class="h4 mb-0" id="metric-recall">--</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-dark">
<div class="card-body text-center py-2">
<div class="small text-muted">F1 Score</div>
<div class="h4 mb-0" id="metric-f1">--</div>
</div>
</div>
</div>
</div>
<!-- Prediction Timeline -->
<div class="row mt-3">
<div class="col-12">
<h6>Prediction Timeline</h6>
<div class="table-responsive" style="max-height: 300px; overflow-y: auto;">
<table class="table table-sm table-dark table-striped">
<thead>
<tr>
<th>Time</th>
<th>Prediction</th>
<th>Confidence</th>
<th>Actual</th>
<th>Result</th>
</tr>
</thead>
<tbody id="prediction-timeline-body">
<tr>
<td colspan="5" class="text-center text-muted">
No predictions yet
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Confusion Matrix -->
<div class="row mt-3">
<div class="col-md-6">
<h6>Confusion Matrix</h6>
<table class="table table-sm table-dark table-bordered text-center">
<thead>
<tr>
<th></th>
<th colspan="2">Predicted</th>
</tr>
<tr>
<th>Actual</th>
<th>BUY</th>
<th>SELL</th>
</tr>
</thead>
<tbody>
<tr>
<th>BUY</th>
<td id="cm-tp-buy">0</td>
<td id="cm-fn-buy">0</td>
</tr>
<tr>
<th>SELL</th>
<td id="cm-fp-sell">0</td>
<td id="cm-tn-sell">0</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6">
<h6>Prediction Distribution</h6>
<div id="prediction-distribution-chart" style="height: 200px;"></div>
</div>
</div>
</div>
<script>
let inferenceState = {
isPlaying: false,
currentIndex: 0,
predictions: [],
annotations: [],
speed: 1
};
// Playback controls
document.getElementById('inference-play-btn').addEventListener('click', function() {
inferenceState.isPlaying = true;
this.disabled = true;
document.getElementById('inference-pause-btn').disabled = false;
document.getElementById('inference-stop-btn').disabled = false;
playInference();
});
document.getElementById('inference-pause-btn').addEventListener('click', function() {
inferenceState.isPlaying = false;
this.disabled = true;
document.getElementById('inference-play-btn').disabled = false;
});
document.getElementById('inference-stop-btn').addEventListener('click', function() {
inferenceState.isPlaying = false;
inferenceState.currentIndex = 0;
document.getElementById('inference-play-btn').disabled = false;
document.getElementById('inference-pause-btn').disabled = true;
this.disabled = true;
resetInferenceDisplay();
});
document.getElementById('inference-speed-select').addEventListener('change', function(e) {
inferenceState.speed = parseFloat(e.target.value);
});
function playInference() {
if (!inferenceState.isPlaying || inferenceState.currentIndex >= inferenceState.predictions.length) {
inferenceState.isPlaying = false;
document.getElementById('inference-play-btn').disabled = false;
document.getElementById('inference-pause-btn').disabled = true;
document.getElementById('inference-stop-btn').disabled = true;
return;
}
const prediction = inferenceState.predictions[inferenceState.currentIndex];
displayPrediction(prediction);
inferenceState.currentIndex++;
// Schedule next prediction
const delay = 1000 / inferenceState.speed;
setTimeout(playInference, delay);
}
function displayPrediction(prediction) {
// Add to timeline table
const tbody = document.getElementById('prediction-timeline-body');
if (tbody.children[0].colSpan === 5) {
tbody.innerHTML = ''; // Clear "no predictions" message
}
const row = document.createElement('tr');
const resultClass = prediction.correct ? 'text-success' : 'text-danger';
const resultIcon = prediction.correct ? 'fa-check' : 'fa-times';
row.innerHTML = `
<td>${new Date(prediction.timestamp).toLocaleTimeString()}</td>
<td><span class="badge bg-${prediction.predicted_action === 'BUY' ? 'success' : 'danger'}">${prediction.predicted_action}</span></td>
<td>${(prediction.confidence * 100).toFixed(1)}%</td>
<td><span class="badge bg-${prediction.actual_action === 'BUY' ? 'success' : 'danger'}">${prediction.actual_action}</span></td>
<td class="${resultClass}"><i class="fas ${resultIcon}"></i></td>
`;
tbody.appendChild(row);
// Scroll to bottom
tbody.parentElement.scrollTop = tbody.parentElement.scrollHeight;
// Update chart (if implemented)
updateInferenceChart(prediction);
}
function updateInferenceChart(prediction) {
// TODO: Update Plotly chart with prediction marker
}
function resetInferenceDisplay() {
document.getElementById('prediction-timeline-body').innerHTML = `
<tr>
<td colspan="5" class="text-center text-muted">
No predictions yet
</td>
</tr>
`;
document.getElementById('metric-accuracy').textContent = '--';
document.getElementById('metric-precision').textContent = '--';
document.getElementById('metric-recall').textContent = '--';
document.getElementById('metric-f1').textContent = '--';
}
function updateMetrics(metrics) {
document.getElementById('metric-accuracy').textContent = (metrics.accuracy * 100).toFixed(1) + '%';
document.getElementById('metric-precision').textContent = (metrics.precision * 100).toFixed(1) + '%';
document.getElementById('metric-recall').textContent = (metrics.recall * 100).toFixed(1) + '%';
document.getElementById('metric-f1').textContent = (metrics.f1_score * 100).toFixed(1) + '%';
// Update confusion matrix
document.getElementById('cm-tp-buy').textContent = metrics.confusion_matrix.tp_buy;
document.getElementById('cm-fn-buy').textContent = metrics.confusion_matrix.fn_buy;
document.getElementById('cm-fp-sell').textContent = metrics.confusion_matrix.fp_sell;
document.getElementById('cm-tn-sell').textContent = metrics.confusion_matrix.tn_sell;
}
</script>