Skip to content

Commit ef5879a

Browse files
committed
add live dataset growth + treemap; switch docs to roboto
1 parent 13af238 commit ef5879a

44 files changed

Lines changed: 2473 additions & 234 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package.json

Lines changed: 68 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,70 @@
11
{
2-
"name": "formulacode-www",
3-
"version": "5.15.1",
4-
"scripts": {
5-
"deleteImgs": "node tasks/deleteNonAnimalImgs.js",
6-
"analysis": "node tasks/wine-analysis.js",
7-
"imgDownload": "node tasks/imgDownload.js",
8-
"limitWine": "node tasks/limit-wine.js",
9-
"identifyWine": "node tasks/identify-wine.js",
10-
"assessWineTxt": "node tasks/assess-wine-txt.js",
11-
"combineCSV": "node tasks/combine-gpt-csv.js",
12-
"gdoc": "node tasks/fetch-google.js",
13-
"style": "node tasks/style-dictionary.js",
14-
"dev": "vite dev",
15-
"build": "vite build",
16-
"preview": "vite preview",
17-
"lint": "prettier --check --plugin-search-dir=. .",
18-
"format": "prettier --write --plugin-search-dir=. ."
19-
},
20-
"devDependencies": {
21-
"@rollup/plugin-dsv": "^3.0.4",
22-
"@sveltejs/adapter-static": "^3.0.1",
23-
"@sveltejs/kit": "^2.3.5",
24-
"@sveltejs/vite-plugin-svelte": "3.0.1",
25-
"archieml": "^0.5.0",
26-
"autoprefixer": "^10.4.17",
27-
"baseline-browser-mapping": "^2.9.19",
28-
"d3": "^7.8.5",
29-
"layercake": "^8.0.2",
30-
"lodash.debounce": "^4.0.8",
31-
"lucide-svelte": "^0.294.0",
32-
"postcss": "^8.4.33",
33-
"prettier": "^3.2.4",
34-
"prettier-plugin-svelte": "^3.1.2",
35-
"rollup": "^4.9.5",
36-
"rollup-plugin-svg": "^2.0.0",
37-
"style-dictionary": "^3.9.2",
38-
"svelte": "^4.2.9",
39-
"svelte-copy": "^1.4.1",
40-
"svelte-preprocess": "^5.1.3",
41-
"vite": "^5.0.11",
42-
"vite-plugin-svgstring": "^1.0.0"
43-
},
44-
"type": "module",
45-
"engines": {
46-
"node": ">= 18.12.0"
47-
},
48-
"browserslist": "> 0.5%, last 4 versions, not ie <= 11, not ie_mob <= 11",
49-
"dependencies": {
50-
"@leveluptuts/svelte-fit": "^1.0.3",
51-
"asciinema-player": "^3.12.1",
52-
"axios": "^1.6.7",
53-
"d3-regression": "^1.3.10",
54-
"fs": "^0.0.1-security",
55-
"image-download": "^2.1.0",
56-
"image-downloader": "^4.3.0",
57-
"mathjax-full": "^3.2.2",
58-
"openai": "^4.28.4",
59-
"svelte-carousel": "^1.0.25",
60-
"svelte-headless-table": "^0.18.3",
61-
"svelte-highlight": "^7.9.0",
62-
"svelte-lazy-image": "^0.5.1",
63-
"svelte-multiselect": "^10.0.0",
64-
"svelte-typeahead": "^5.0.0",
65-
"wx-grid-locales": "^2.2.0",
66-
"wx-svelte-grid": "^1.3.3",
67-
"yootils": "^0.3.1"
68-
}
2+
"name": "formulacode-www",
3+
"version": "5.15.1",
4+
"scripts": {
5+
"deleteImgs": "node tasks/deleteNonAnimalImgs.js",
6+
"analysis": "node tasks/wine-analysis.js",
7+
"imgDownload": "node tasks/imgDownload.js",
8+
"limitWine": "node tasks/limit-wine.js",
9+
"identifyWine": "node tasks/identify-wine.js",
10+
"assessWineTxt": "node tasks/assess-wine-txt.js",
11+
"combineCSV": "node tasks/combine-gpt-csv.js",
12+
"gdoc": "node tasks/fetch-google.js",
13+
"style": "node tasks/style-dictionary.js",
14+
"dashboard": "node scripts/build-dashboard.mjs",
15+
"dev": "vite dev",
16+
"build": "vite build",
17+
"preview": "vite preview",
18+
"lint": "prettier --check --plugin-search-dir=. .",
19+
"format": "prettier --write --plugin-search-dir=. ."
20+
},
21+
"devDependencies": {
22+
"@rollup/plugin-dsv": "^3.0.4",
23+
"@sveltejs/adapter-static": "^3.0.1",
24+
"@sveltejs/kit": "^2.3.5",
25+
"@sveltejs/vite-plugin-svelte": "3.0.1",
26+
"archieml": "^0.5.0",
27+
"autoprefixer": "^10.4.17",
28+
"baseline-browser-mapping": "^2.9.19",
29+
"d3": "^7.8.5",
30+
"layercake": "^8.0.2",
31+
"lodash.debounce": "^4.0.8",
32+
"lucide-svelte": "^0.294.0",
33+
"postcss": "^8.4.33",
34+
"prettier": "^3.2.4",
35+
"prettier-plugin-svelte": "^3.1.2",
36+
"rollup": "^4.9.5",
37+
"rollup-plugin-svg": "^2.0.0",
38+
"style-dictionary": "^3.9.2",
39+
"svelte": "^4.2.9",
40+
"svelte-copy": "^1.4.1",
41+
"svelte-preprocess": "^5.1.3",
42+
"vite": "^5.0.11",
43+
"vite-plugin-svgstring": "^1.0.0"
44+
},
45+
"type": "module",
46+
"engines": {
47+
"node": ">= 18.12.0"
48+
},
49+
"browserslist": "> 0.5%, last 4 versions, not ie <= 11, not ie_mob <= 11",
50+
"dependencies": {
51+
"@leveluptuts/svelte-fit": "^1.0.3",
52+
"asciinema-player": "^3.12.1",
53+
"axios": "^1.6.7",
54+
"d3-regression": "^1.3.10",
55+
"fs": "^0.0.1-security",
56+
"image-download": "^2.1.0",
57+
"image-downloader": "^4.3.0",
58+
"mathjax-full": "^3.2.2",
59+
"openai": "^4.28.4",
60+
"svelte-carousel": "^1.0.25",
61+
"svelte-headless-table": "^0.18.3",
62+
"svelte-highlight": "^7.9.0",
63+
"svelte-lazy-image": "^0.5.1",
64+
"svelte-multiselect": "^10.0.0",
65+
"svelte-typeahead": "^5.0.0",
66+
"wx-grid-locales": "^2.2.0",
67+
"wx-svelte-grid": "^1.3.3",
68+
"yootils": "^0.3.1"
69+
}
6970
}

scripts/build-dashboard.mjs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#!/usr/bin/env node
2+
/*
3+
* Builds src/data/dashboard.json from api.formulacode.org/rest/v1.
4+
*
5+
* Replicates the Grafana "DataSmith Pipeline Overview" panels (Dataset
6+
* Growth + Problems by Repository + Repository Distribution) using only
7+
* the publicly readable Supabase tables — no auth required.
8+
*
9+
* Run manually with `npm run dashboard`. The output is committed so the
10+
* landing page stays self-contained in case the API is down at deploy.
11+
*/
12+
13+
import { writeFile, mkdir } from "node:fs/promises";
14+
import { dirname, resolve } from "node:path";
15+
import { fileURLToPath } from "node:url";
16+
17+
const API = "https://api.formulacode.org/rest/v1";
18+
const OUT = resolve(
19+
dirname(fileURLToPath(import.meta.url)),
20+
"../src/data/dashboard.json"
21+
);
22+
23+
async function getCount(path) {
24+
const url = `${API}${path}${path.includes("?") ? "&" : "?"}select=*&limit=1`;
25+
const r = await fetch(url, {
26+
headers: { Range: "0-0", "Range-Unit": "items", Prefer: "count=exact" }
27+
});
28+
if (!r.ok) throw new Error(`count ${r.status} ${url}`);
29+
const cr = r.headers.get("content-range");
30+
const total = cr?.split("/")[1];
31+
return total === "*" ? null : Number(total);
32+
}
33+
34+
async function fetchAll(path) {
35+
const out = [];
36+
const pageSize = 1000;
37+
let offset = 0;
38+
while (true) {
39+
const sep = path.includes("?") ? "&" : "?";
40+
const url = `${API}${path}${sep}limit=${pageSize}&offset=${offset}`;
41+
const r = await fetch(url);
42+
if (!r.ok) throw new Error(`fetch ${r.status} ${url}`);
43+
const rows = await r.json();
44+
out.push(...rows);
45+
if (rows.length < pageSize) break;
46+
offset += pageSize;
47+
}
48+
return out;
49+
}
50+
51+
function groupBy(rows, keyFn) {
52+
const m = new Map();
53+
for (const r of rows) {
54+
const k = keyFn(r);
55+
if (!m.has(k)) m.set(k, []);
56+
m.get(k).push(r);
57+
}
58+
return m;
59+
}
60+
61+
async function main() {
62+
const t0 = Date.now();
63+
console.log(`fetching from ${API} ...`);
64+
65+
// Counts (cheap — HEAD with count=exact).
66+
const [total_prs, total_problems, total_repos, perf_prs] = await Promise.all([
67+
getCount("/pull_requests"),
68+
getCount("/candidate_containers"),
69+
getCount("/repositories"),
70+
getCount("/pull_requests?is_performance_commit=eq.true")
71+
]);
72+
console.log(
73+
` totals: prs=${total_prs} problems=${total_problems} repos=${total_repos} perf=${perf_prs}`
74+
);
75+
76+
// Full rows for joining.
77+
const [containers, repositories] = await Promise.all([
78+
fetchAll("/candidate_containers?select=owner,repo,issue_number"),
79+
fetchAll("/repositories?select=owner,repo,stars")
80+
]);
81+
console.log(
82+
` fetched: ${containers.length} containers, ${repositories.length} repos`
83+
);
84+
85+
// For the monthly histogram we need merged_at on each candidate's PR.
86+
// candidate_containers has no FK to pull_requests in the schema cache,
87+
// so do the join ourselves: batch issue_number lookups per (owner, repo).
88+
const byRepo = groupBy(containers, (c) => `${c.owner}/${c.repo}`);
89+
const merged = [];
90+
let queries = 0;
91+
for (const [, group] of byRepo) {
92+
const { owner, repo } = group[0];
93+
const issues = group.map((g) => g.issue_number);
94+
for (let i = 0; i < issues.length; i += 200) {
95+
const chunk = issues.slice(i, i + 200);
96+
const url =
97+
`${API}/pull_requests?owner=eq.${encodeURIComponent(owner)}` +
98+
`&repo=eq.${encodeURIComponent(repo)}` +
99+
`&issue_number=in.(${chunk.join(",")})` +
100+
`&select=issue_number,merged_at`;
101+
const r = await fetch(url);
102+
if (!r.ok) throw new Error(`pr lookup ${r.status} ${url}`);
103+
const rows = await r.json();
104+
for (const row of rows) merged.push({ owner, repo, ...row });
105+
queries += 1;
106+
}
107+
}
108+
console.log(` joined ${merged.length} PRs in ${queries} queries`);
109+
110+
// Aggregations.
111+
const monthly = new Map();
112+
for (const m of merged) {
113+
if (!m.merged_at) continue;
114+
const month = m.merged_at.slice(0, 7); // "YYYY-MM"
115+
monthly.set(month, (monthly.get(month) || 0) + 1);
116+
}
117+
118+
const byRepoCount = new Map();
119+
for (const c of containers) {
120+
const k = `${c.owner}/${c.repo}`;
121+
byRepoCount.set(k, (byRepoCount.get(k) || 0) + 1);
122+
}
123+
124+
// Output shape — matches what the Svelte components consume.
125+
const out = {
126+
generated_at: new Date().toISOString(),
127+
source: API,
128+
totals: {
129+
pull_requests: total_prs,
130+
problems: total_problems,
131+
repositories: total_repos,
132+
performance_prs: perf_prs,
133+
pr_to_problem_rate: total_prs ? total_problems / total_prs : 0
134+
},
135+
monthly: [...monthly.entries()]
136+
.sort(([a], [b]) => a.localeCompare(b))
137+
.map(([month, count]) => ({ month, count })),
138+
by_repository: [...byRepoCount.entries()]
139+
.sort((a, b) => b[1] - a[1])
140+
.map(([repository, count]) => ({ repository, count })),
141+
repository_stars: repositories
142+
.filter((r) => r.stars != null)
143+
.sort((a, b) => b.stars - a.stars)
144+
.map((r) => ({ repository: `${r.owner}/${r.repo}`, stars: r.stars }))
145+
};
146+
147+
await mkdir(dirname(OUT), { recursive: true });
148+
await writeFile(OUT, JSON.stringify(out, null, 2) + "\n");
149+
const dt = ((Date.now() - t0) / 1000).toFixed(1);
150+
console.log(`wrote ${OUT} in ${dt}s`);
151+
}
152+
153+
main().catch((err) => {
154+
console.error(err);
155+
process.exit(1);
156+
});

src/components/pages/DocsPage.svelte

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<script>
22
const repos = [
33
{
4-
path: "formula-code/fc-eval",
54
name: "fc-eval",
65
description:
76
"Run frontier LLM agents against the FormulaCode benchmark. Spins up reproducible Docker environments, replays the unit-test suite, and computes per-workload speedup, advantage, and stratified scores. Bring your own Terminus or OpenHands agent — `fceval run -d formulacode -a <your-agent>` is all it takes.",
@@ -11,7 +10,6 @@
1110
imageAlt: "fc-eval repository preview"
1211
},
1312
{
14-
path: "formula-code/datasmith",
1513
name: "datasmith",
1614
description:
1715
"The four-stage pipeline that mines FormulaCode's tasks from real GitHub repositories: scraping high-quality performance PRs, attribute-filtering them with LLM judges, synthesising reproducible build environments, and running the statistical-significance tests that admit a candidate into the benchmark.",
@@ -71,9 +69,6 @@
7169
href={r.docsUrl}
7270
aria-label="Open {r.name} documentation"
7371
>
74-
<div class="card-header">
75-
<span class="repo-path">{r.path}</span>
76-
</div>
7772
<div class="card-image">
7873
<img src={r.image} alt={r.imageAlt} loading="lazy" />
7974
</div>
@@ -229,21 +224,6 @@
229224
color: inherit;
230225
}
231226
232-
.card-header {
233-
display: flex;
234-
justify-content: space-between;
235-
align-items: baseline;
236-
gap: var(--space-sm);
237-
padding: var(--space-md) var(--space-lg) 0;
238-
flex-wrap: wrap;
239-
}
240-
241-
.repo-path {
242-
font-family: var(--mono);
243-
font-size: 0.78rem;
244-
color: var(--text-muted);
245-
}
246-
247227
.card-image {
248228
padding: var(--space-md) var(--space-lg);
249229
}

src/components/pages/OverviewPage.svelte

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import { getContext } from "svelte";
33
import OverviewHeader from "$components/layout/OverviewHeader.svelte";
44
import CompactLeaderboard from "$components/sections/CompactLeaderboard.svelte";
5+
import DatasetGrowth from "$components/sections/DatasetGrowth.svelte";
6+
import ProblemsByRepository from "$components/sections/ProblemsByRepository.svelte";
57
import ResultsHighlights from "$components/sections/ResultsHighlights.svelte";
68
import SubmitCta from "$components/sections/SubmitCta.svelte";
79
@@ -83,6 +85,9 @@
8385
</section>
8486
</main>
8587
88+
<DatasetGrowth />
89+
<ProblemsByRepository />
90+
8691
<ResultsHighlights stratified={leaderboardData.stratified} />
8792
8893
<CompactLeaderboard

0 commit comments

Comments
 (0)