| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>ML Inference Dashboard</title> |
| <link rel="stylesheet" href="/static/styles.css?v=2.0"> |
| <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> |
| </head> |
| <body> |
| <div class="container"> |
| <header> |
| <h1>ML Inference Service with Drift Detection</h1> |
| <p class="subtitle">Default of Credit Card Clients</p> |
| </header> |
|
|
| <section class="card"> |
| <h2>Drift Metrics</h2> |
| <div id="drift-chart"> |
| <p>Loading...</p> |
| </div> |
| </section> |
|
|
| <section class="card"> |
| <h2>Recent Predictions</h2> |
| <div id="predictions"> |
| <p>Loading...</p> |
| </div> |
| </section> |
|
|
| <footer> |
| <p>Made with FastAPI, Plotly, Evidently, Python 3.9 and Hugging Face Spaces friendly</p> |
| </footer> |
| </div> |
|
|
| <script> |
| async function fetchDashboardData() { |
| try { |
| const resp = await fetch("/dashboard/data"); |
| const json = await resp.json(); |
| |
| const predDiv = document.getElementById("predictions"); |
| const driftDiv = document.getElementById("drift-chart"); |
| |
| if(json.status === "ok") { |
| const data = json.data; |
| |
| |
| const driftData = data.drift || []; |
| const columns = driftData.map(d => d.column); |
| const scores = driftData.map(d => Number(d.score)); |
| |
| const trace = { x: columns, y: scores, type: 'bar', marker: {color: '#FF7F50'} }; |
| const layout = { |
| title: 'Drift Scores by Column', |
| yaxis: {title: 'Score'}, |
| xaxis: {title: 'Column'}, |
| margin: {t: 40, l: 50, r: 30, b: 80}, |
| font: {size: 12} |
| }; |
| |
| Plotly.newPlot(driftDiv, [trace], layout, {responsive: true}); |
| |
| |
| if(Array.isArray(data.results) && data.results.length > 0){ |
| let table = "<table><thead><tr><th>#</th><th>Prediction</th><th>Probability</th><th>Risk Level</th></tr></thead><tbody>"; |
| data.results.forEach((r, i) => { |
| table += `<tr> |
| <td>${i+1}</td> |
| <td>${r.prediction}</td> |
| <td>${(r.probability*100).toFixed(2)}%</td> |
| <td>${r.risk_level}</td> |
| </tr>`; |
| }); |
| table += "</tbody></table>"; |
| predDiv.innerHTML = table; |
| } else { |
| predDiv.innerHTML = "<p>No recent predictions.</p>"; |
| } |
| |
| } else { |
| predDiv.innerHTML = "<p>Dashboard data not available.</p>"; |
| driftDiv.innerHTML = "<p>Dashboard data not available.</p>"; |
| } |
| |
| } catch(err) { |
| console.error("Failed to fetch dashboard data:", err); |
| } |
| } |
| |
| |
| fetchDashboardData(); |
| setInterval(fetchDashboardData, 10000); |
| </script> |
| </body> |
| </html> |
|
|