Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Ready, Xet, Go!</title> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<div class="hero-band"> | |
<div class="hero-content"> | |
<img src="huggie.png" alt="Huggie" class="hero-logo hero-logo-left"> | |
<div class="hero-text"> | |
<h1 class="hero-title">Ready, Xet, Go!</h1> | |
<p class="hero-subtitle">At the speed of chunks</p> | |
</div> | |
<img src="rockxet.png" alt="RockXet" class="hero-logo hero-logo-right"> | |
</div> | |
</div> | |
<div class="container"> | |
<div class="stats-card"> | |
<div class="card"> | |
<h2>Xet Migration Progress</h2> | |
<div class="progress-container"> | |
<div class="progress-bar" id="progressBar">0%</div> | |
</div> | |
</div> | |
</div> | |
<div class="charts-container"> | |
<div class="chart-card"> | |
<div class="card"> | |
<h2>Repos Migrated to Xet</h2> | |
<div class="chart-container"> | |
<canvas id="progressChart"></canvas> | |
</div> | |
</div> | |
</div> | |
<div class="chart-card"> | |
<div class="card"> | |
<h2>LFS vs. Xet Files</h2> | |
<div class="chart-container"> | |
<canvas id="largeFilesChart"></canvas> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
const REPO_CSV_URL = 'https://huggingface.co/datasets/jsulz/ready-xet-go/resolve/main/repo-progress.csv'; | |
const FILE_CSV_URL = 'https://huggingface.co/datasets/jsulz/ready-xet-go/resolve/main/file-progress.csv'; | |
(async () => { | |
/* | |
* Data fetching and parsing | |
*/ | |
const repo_rows = []; | |
const file_rows = []; | |
const repo_csv = await new Promise((resolve, reject) => { | |
Papa.parse(REPO_CSV_URL, { | |
download: true, | |
header : true, | |
complete: resolve, | |
error : reject | |
}); | |
}); | |
repo_csv.data.forEach(row => { | |
if (row.date && row.xet_repos && row.hub_repos) { | |
repo_rows.push({ | |
date: new Date(row.date), | |
xet_repos: parseInt(row.xet_repos, 10), | |
hub_repos: parseInt(row.hub_repos, 10) | |
}); | |
} | |
}); | |
const file_csv = await new Promise((resolve, reject) => { | |
Papa.parse(FILE_CSV_URL, { | |
download: true, | |
header : true, | |
complete: resolve, | |
error : reject | |
}); | |
}); | |
file_csv.data.forEach(row => { | |
if (row.date && row.lfs_files && row.xet_files) { | |
file_rows.push({ | |
date: new Date(row.date), | |
lfs_files: parseInt(row.lfs_files, 10), | |
xet_files: parseInt(row.xet_files, 10) | |
}); | |
} | |
}); | |
/* | |
* Progress Bar | |
*/ | |
// Progress Bar Constants | |
const max_value = 100; | |
const current_status = Math.round((repo_rows[repo_rows.length - 1].xet_repos / repo_rows[repo_rows.length - 1].hub_repos) * max_value); | |
// Animate Progress Bar - increments smoothly every 50ms | |
const progressBar = document.getElementById('progressBar'); | |
let currentProgress = 0; | |
function animateProgressBar() { | |
if (currentProgress < current_status) { | |
currentProgress++; | |
progressBar.style.width = `${currentProgress}%`; | |
progressBar.textContent = `${currentProgress}%`; | |
setTimeout(animateProgressBar, 75); | |
} | |
} | |
animateProgressBar(); | |
/* | |
* Charts | |
*/ | |
// | |
// Line chart for repo migration progress | |
// | |
// Set up chart data | |
const maxCount = Math.max( | |
...repo_rows.map(row => row.xet_repos), | |
); | |
const dataPoints = repo_rows.map(row => ({ | |
date: row.date, | |
value: row.xet_repos | |
})); | |
// Format date for display (MMM D YYYY) | |
function formatDate(dateStr) { | |
return new Date(dateStr).toLocaleDateString('en-US', { | |
year: 'numeric', month: 'short', day: 'numeric' | |
}); | |
} | |
// Initialize line chart | |
const lineChartCtx = document.getElementById('progressChart').getContext('2d'); | |
let lineChart = new Chart(lineChartCtx, { | |
type: 'line', | |
data: { | |
labels: dataPoints.map(point => formatDate(point.date)), | |
datasets: [{ | |
label: 'Repos Migrated', | |
data: dataPoints.map(point => point.value), | |
borderColor: '#7875FF', | |
backgroundColor: 'rgba(255, 127, 65, 1)', | |
tension: 0.4 | |
}] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
animation: { duration: 2000 }, | |
scales: { | |
y: { | |
min: 0, | |
ticks: { stepSize: 100000 } | |
}, | |
x: { | |
ticks: { | |
maxTicksLimit: 20 | |
} | |
}, | |
}, | |
plugins: { | |
tooltip: { | |
callbacks: { | |
label: function(context) { | |
return `Repos Migrated: ${context.parsed.y.toLocaleString()}`; | |
} | |
} | |
} | |
} | |
} | |
}); | |
// | |
// Donut chart for large files | |
// | |
// Set up donut chart data | |
lfs_file_count = file_rows[file_rows.length - 1].lfs_files; | |
xet_file_count = file_rows[file_rows.length - 1].xet_files; | |
// Initialize donut chart | |
const donutChartCtx = document.getElementById('largeFilesChart').getContext('2d'); | |
let donutChart = new Chart(donutChartCtx, { | |
type: 'doughnut', | |
data: { | |
labels: [ | |
'LFS Files', | |
'Xet Files', | |
], | |
datasets: [{ | |
label: 'My First Dataset', | |
data: [lfs_file_count, xet_file_count], | |
backgroundColor: [ | |
'oklch(0.577 0.245 27.325 / 75.56%)', | |
'oklch(0.6361 0.1994 280.07 / 71.37%)', | |
], | |
hoverOffset: 4 | |
}] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
animation: { duration: 2000 }, | |
plugins: { | |
legend: { | |
position: 'top', | |
}, | |
} | |
} | |
}); | |
})(); | |
</script> | |
</body> | |
</html> |