Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions data/summary.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
{
"lastUpdated": "2026-07-22T20:21:16.853Z",
"lastUpdated": "2026-07-22T22:45:00.700Z",
"total": {
"adoption": 150108,
"adoptionExCrypto": 132929,
"adoption": 163775,
"adoptionExCrypto": 146596,
"downloads": 298844,
"downloadsExCrypto": 278460,
"npm": 112222,
"pypi": 28487,
"cloneUniques": 1021,
"clones": 136090,
"docker": 8378,
"docker": 18544,
"hf": 3501,
"views": 28164,
"stars": 248,
"repos": 45,
Expand All @@ -30,6 +33,7 @@
"pypi": 12784,
"cloneUniques": 1012,
"clones": 132876,
"docker": 8378
"docker": 18544,
"downloads": 278460
}
}
46 changes: 42 additions & 4 deletions scripts/generate-summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,31 @@ try {
ORDER BY ts.date DESC LIMIT 1
`).get();

// Docker totals
// Docker totals: latest pull_count per image, summed across images — matching
// the dashboard (pages/api/overview.js). MAX() across all rows silently took
// only the single biggest image and undercounted the fleet by ~10K.
const dockerTotal = db.prepare(`
SELECT COALESCE(MAX(pull_count), 0) as total FROM docker_pulls
SELECT COALESCE(SUM(p), 0) AS total FROM (
SELECT (SELECT pull_count FROM docker_pulls dp2
WHERE dp2.image_id = dp.image_id ORDER BY date DESC LIMIT 1) AS p
FROM docker_pulls dp GROUP BY dp.image_id
)
`).get();

// HuggingFace model downloads: latest all-time count per model, summed —
// matching the dashboard. Previously omitted here entirely, which was the
// other half of the summary-vs-dashboard reconciliation gap.
const hfTableExists = db.prepare(
"SELECT name FROM sqlite_master WHERE type='table' AND name='huggingface_stats'"
).get();
const hfTotal = hfTableExists ? db.prepare(`
SELECT COALESCE(SUM(d), 0) AS total FROM (
SELECT (SELECT downloads_all_time FROM huggingface_stats h2
WHERE h2.model_id = h.model_id ORDER BY date DESC LIMIT 1) AS d
FROM huggingface_stats h GROUP BY h.model_id
)
`).get() : { total: 0 };

// GitHub views
const viewsTotal = db.prepare(`
SELECT COALESCE(SUM(count), 0) as total FROM traffic_views
Expand Down Expand Up @@ -139,21 +159,37 @@ try {
const npmPkgCount = db.prepare('SELECT COUNT(*) as count FROM npm_packages').get();

// Total adoption (all ecosystems). Clone term = UNIQUE CLONERS, not raw count.
const totalAll = npmTotal.total + pypiTotal.total + cloneUniquesTotal.total + dockerTotal.total;
const totalExCrypto = npmExCrypto.total + pypiExCrypto.total + cloneUniquesExCrypto.total + dockerTotal.total;
// Same formula as the dashboard's combined.totalAdoption (overview.js):
// uniqueCloners + npm + pypi + docker + hf — the two surfaces must agree.
const totalAll = npmTotal.total + pypiTotal.total + cloneUniquesTotal.total + dockerTotal.total + hfTotal.total;
const totalExCrypto = npmExCrypto.total + pypiExCrypto.total + cloneUniquesExCrypto.total + dockerTotal.total + hfTotal.total;

// Gross DOWNLOADS (all ecosystems): npm downloads + PyPI downloads + Docker
// pulls + git clones (raw) + HF model downloads. Every term is literally a
// download event, counted the same way the ecosystems themselves report
// downloads (incl. CI and re-downloads — same semantics as npm's public
// download counts). This is the marketing/headline metric; `adoption` above
// stays the deduplicated floor. Views are NOT downloads, never included.
const downloadsAll = npmTotal.total + pypiTotal.total + clonesTotal.total + dockerTotal.total + hfTotal.total;
const downloadsExCrypto = npmExCrypto.total + pypiExCrypto.total + clonesExCrypto.total + dockerTotal.total + hfTotal.total;

const summary = {
lastUpdated: new Date().toISOString(),
total: {
adoption: totalAll,
adoptionExCrypto: totalExCrypto,
// Gross download events across npm + PyPI + Docker + git clones. The
// website's "downloads" headline sources THIS field, never `adoption`.
downloads: downloadsAll,
downloadsExCrypto,
npm: npmTotal.total,
pypi: pypiTotal.total,
// Distinct cloners — the term summed into `adoption`.
cloneUniques: cloneUniquesTotal.total,
// Raw git-clone count — context/transparency only, NOT in `adoption`.
clones: clonesTotal.total,
docker: dockerTotal.total,
hf: hfTotal.total,
views: viewsTotal.total,
stars: starsTotal.total,
repos: repoCount.count,
Expand All @@ -171,6 +207,7 @@ try {
cloneUniques: cloneUniquesExCrypto.total,
clones: clonesExCrypto.total,
docker: dockerTotal.total,
downloads: downloadsExCrypto,
},
};

Expand All @@ -179,6 +216,7 @@ try {
console.log(`Summary written to ${outPath}`);
console.log(` Total adoption: ${totalAll.toLocaleString()}`);
console.log(` Excl. CryptoServe: ${totalExCrypto.toLocaleString()}`);
console.log(` Gross downloads: ${downloadsAll.toLocaleString()} (excl. CryptoServe: ${downloadsExCrypto.toLocaleString()})`);
} catch (err) {
console.error('Error generating summary:', err);
process.exit(1);
Expand Down
Loading