cfahlgren1 HF staff commited on
Commit
633e5e5
1 Parent(s): 5e26aa6
Files changed (4) hide show
  1. bun.lockb +0 -0
  2. package.json +7 -2
  3. src/pages/api/hello.ts +0 -13
  4. src/pages/index.tsx +179 -108
bun.lockb CHANGED
Binary files a/bun.lockb and b/bun.lockb differ
 
package.json CHANGED
@@ -9,9 +9,14 @@
9
  "lint": "next lint"
10
  },
11
  "dependencies": {
 
 
 
 
 
12
  "react": "^18",
13
- "react-dom": "^18",
14
- "next": "14.2.5"
15
  },
16
  "devDependencies": {
17
  "typescript": "^5",
 
9
  "lint": "next lint"
10
  },
11
  "dependencies": {
12
+ "@duckdb/duckdb-wasm": "^1.28.1-dev106.0",
13
+ "@emotion/react": "^11.13.0",
14
+ "@emotion/styled": "^11.13.0",
15
+ "@mui/material": "^5.16.6",
16
+ "next": "14.2.5",
17
  "react": "^18",
18
+ "react-activity-calendar": "^2.2.11",
19
+ "react-dom": "^18"
20
  },
21
  "devDependencies": {
22
  "typescript": "^5",
src/pages/api/hello.ts DELETED
@@ -1,13 +0,0 @@
1
- // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2
- import type { NextApiRequest, NextApiResponse } from "next";
3
-
4
- type Data = {
5
- name: string;
6
- };
7
-
8
- export default function handler(
9
- req: NextApiRequest,
10
- res: NextApiResponse<Data>,
11
- ) {
12
- res.status(200).json({ name: "John Doe" });
13
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/pages/index.tsx CHANGED
@@ -1,118 +1,189 @@
1
- import Image from "next/image";
 
2
  import { Inter } from "next/font/google";
 
 
 
 
3
 
4
  const inter = Inter({ subsets: ["latin"] });
5
 
 
 
 
 
 
 
 
 
 
6
  export default function Home() {
7
- return (
8
- <main
9
- className={`flex min-h-screen flex-col items-center justify-between p-24 ${inter.className}`}
10
- >
11
- <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
12
- <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
13
- Get started by editing&nbsp;
14
- <code className="font-mono font-bold">src/pages/index.tsx</code>
15
- </p>
16
- <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
17
- <a
18
- className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
19
- href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
20
- target="_blank"
21
- rel="noopener noreferrer"
22
- >
23
- By{" "}
24
- <Image
25
- src="/vercel.svg"
26
- alt="Vercel Logo"
27
- className="dark:invert"
28
- width={100}
29
- height={24}
30
- priority
31
- />
32
- </a>
33
- </div>
34
- </div>
35
 
36
- <div className="relative flex place-items-center before:absolute before:h-[300px] before:w-full sm:before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-full sm:after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700/10 after:dark:from-sky-900 after:dark:via-[#0141ff]/40 before:lg:h-[360px]">
37
- <Image
38
- className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
39
- src="/next.svg"
40
- alt="Next.js Logo"
41
- width={180}
42
- height={37}
43
- priority
44
- />
45
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
- <div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
48
- <a
49
- href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
50
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
51
- target="_blank"
52
- rel="noopener noreferrer"
53
- >
54
- <h2 className={`mb-3 text-2xl font-semibold`}>
55
- Docs{" "}
56
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
57
- -&gt;
58
- </span>
59
- </h2>
60
- <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
61
- Find in-depth information about Next.js features and API.
62
- </p>
63
- </a>
64
-
65
- <a
66
- href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
67
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
68
- target="_blank"
69
- rel="noopener noreferrer"
70
- >
71
- <h2 className={`mb-3 text-2xl font-semibold`}>
72
- Learn{" "}
73
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
74
- -&gt;
75
- </span>
76
- </h2>
77
- <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
78
- Learn about Next.js in an interactive course with&nbsp;quizzes!
79
- </p>
80
- </a>
81
-
82
- <a
83
- href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
84
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
85
- target="_blank"
86
- rel="noopener noreferrer"
87
- >
88
- <h2 className={`mb-3 text-2xl font-semibold`}>
89
- Templates{" "}
90
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
91
- -&gt;
92
- </span>
93
- </h2>
94
- <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
95
- Discover and deploy boilerplate example Next.js&nbsp;projects.
96
- </p>
97
- </a>
98
-
99
- <a
100
- href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template-tw&utm_campaign=create-next-app"
101
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
102
- target="_blank"
103
- rel="noopener noreferrer"
104
- >
105
- <h2 className={`mb-3 text-2xl font-semibold`}>
106
- Deploy{" "}
107
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
108
- -&gt;
109
- </span>
110
- </h2>
111
- <p className={`m-0 max-w-[30ch] text-sm opacity-50 text-balance`}>
112
- Instantly deploy your Next.js site to a shareable URL with Vercel.
113
- </p>
114
- </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  </div>
116
  </main>
117
  );
118
- }
 
1
+ "use client";
2
+
3
  import { Inter } from "next/font/google";
4
+ import ActivityCalendar from "react-activity-calendar";
5
+ import * as duckdb from "@duckdb/duckdb-wasm"
6
+ import { useState, useEffect } from "react";
7
+ import { Tooltip as MuiTooltip } from '@mui/material';
8
 
9
  const inter = Inter({ subsets: ["latin"] });
10
 
11
+ interface CustomActivity {
12
+ date: string;
13
+ count: number;
14
+ level: number;
15
+ details: Array<{ provider: string; count: number }>;
16
+ }
17
+
18
+ type ProviderKey = "mistralai" | "meta-llama" | "openai" | "anthropic" | "google";
19
+
20
  export default function Home() {
21
+ const [calendarData, setCalendarData] = useState<Record<ProviderKey, CustomActivity[]>>({} as Record<ProviderKey, CustomActivity[]>);
22
+ const [isLoading, setIsLoading] = useState(true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ const PROVIDERS_MAP: Record<ProviderKey, { name: string; color: string }> = {
25
+ "mistralai": {"name": "Mistral AI", "color": "#ff7000"},
26
+ "meta-llama": {"name": "Meta", "color": "#0668E1"},
27
+ "openai": {"name": "OpenAI", "color": "#10A37F"},
28
+ "anthropic": {"name": "Anthropic", "color": "#cc785c"},
29
+ "google": {"name": "Google", "color": "#4285F4"},
30
+ }
31
+
32
+ const getModelData = async (conn: duckdb.AsyncDuckDBConnection) => {
33
+ const result = await conn.query(`
34
+ SELECT
35
+ STRFTIME(DATE_TRUNC('day', CAST(createdAt AS DATE)), '%Y-%m-%d') AS date,
36
+ CASE
37
+ WHEN SPLIT_PART(id, '/', 1) IN ('meta-llama', 'facebook') THEN 'meta-llama'
38
+ ELSE SPLIT_PART(id, '/', 1)
39
+ END AS provider,
40
+ COUNT(*) AS count
41
+ FROM models
42
+ WHERE CAST(createdAt AS DATE) >= DATE_TRUNC('year', CURRENT_DATE)
43
+ AND (
44
+ SPLIT_PART(id, '/', 1) IN (${Object.keys(PROVIDERS_MAP).map(provider => `'${provider}'`).join(', ')})
45
+ OR SPLIT_PART(id, '/', 1) = 'facebook'
46
+ )
47
+ GROUP BY DATE_TRUNC('day', CAST(createdAt AS DATE)),
48
+ CASE
49
+ WHEN SPLIT_PART(id, '/', 1) IN ('meta-llama', 'facebook') THEN 'meta-llama'
50
+ ELSE SPLIT_PART(id, '/', 1)
51
+ END
52
+ ORDER BY date
53
+ `);
54
+ return result.toArray().map((row: any) => ({
55
+ date: row.date,
56
+ provider: row.provider,
57
+ count: Number(row.count)
58
+ }));
59
+ }
60
+
61
+ const generateCalendarData = (modelData: any[]) => {
62
+ const data: Record<ProviderKey, CustomActivity[]> = Object.keys(PROVIDERS_MAP).reduce((acc, provider) => {
63
+ acc[provider as ProviderKey] = [];
64
+ return acc;
65
+ }, {} as Record<ProviderKey, CustomActivity[]>);
66
+
67
+ const today = new Date();
68
+ const startOfYear = new Date(today.getFullYear(), 0, 1);
69
+
70
+ for (let d = new Date(startOfYear); d <= today; d.setDate(d.getDate() + 1)) {
71
+ const dateString = d.toISOString().split('T')[0];
72
+
73
+ Object.keys(PROVIDERS_MAP).forEach((provider) => {
74
+ const dayData = modelData.filter(item => item.date === dateString && item.provider === provider);
75
+ const count = dayData.reduce((sum, item) => sum + item.count, 0);
76
+
77
+ data[provider as ProviderKey].push({
78
+ date: dateString,
79
+ count,
80
+ level: 0,
81
+ details: dayData,
82
+ });
83
+ });
84
+ }
85
+
86
+ const avgCounts: Record<ProviderKey, number> = Object.fromEntries(
87
+ Object.keys(PROVIDERS_MAP).map(provider => [
88
+ provider,
89
+ data[provider as ProviderKey].reduce((sum, day) => sum + day.count, 0) / data[provider as ProviderKey].length || 0
90
+ ])
91
+ ) as Record<ProviderKey, number>;
92
+
93
+ Object.entries(data).forEach(([provider, days]) => {
94
+ const avgCount = avgCounts[provider as ProviderKey];
95
+ days.forEach(day => {
96
+ day.level = day.count === 0 ? 0 :
97
+ day.count <= avgCount * 0.5 ? 1 :
98
+ day.count <= avgCount ? 2 :
99
+ day.count <= avgCount * 1.5 ? 3 : 4;
100
+ });
101
+ });
102
 
103
+ return data;
104
+ }
105
+
106
+ const initDB = async () => {
107
+ const CDN_BASE = `https://cdn.jsdelivr.net/npm/@duckdb/duckdb-wasm@next`
108
+
109
+ const JSDELIVR_BUNDLES = {
110
+ mvp: {
111
+ mainModule: `${CDN_BASE}/dist/duckdb-mvp.wasm`,
112
+ mainWorker: `${CDN_BASE}/dist/duckdb-browser-mvp.worker.js`,
113
+ },
114
+ eh: {
115
+ mainModule: `${CDN_BASE}/dist/duckdb-eh.wasm`,
116
+ mainWorker: `${CDN_BASE}/dist/duckdb-browser-eh.worker.js`,
117
+ },
118
+ }
119
+
120
+ const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES)
121
+ const worker_url = URL.createObjectURL(
122
+ new Blob([`importScripts("${bundle.mainWorker}");`], {
123
+ type: "text/javascript",
124
+ })
125
+ )
126
+
127
+ const worker = new Worker(worker_url)
128
+ const logger = new duckdb.ConsoleLogger()
129
+ const db = new duckdb.AsyncDuckDB(logger, worker)
130
+ await db.instantiate(bundle.mainModule)
131
+
132
+ const connection = await db.connect()
133
+
134
+ await connection.query(`
135
+ CREATE VIEW models AS SELECT * FROM read_parquet('https://huggingface.co/datasets/cfahlgren1/hub-stats/resolve/refs%2Fconvert%2Fparquet/models/train/0000.parquet?download=true');
136
+ `);
137
+
138
+ const modelData = await getModelData(connection);
139
+ const calendarData = generateCalendarData(modelData);
140
+ setCalendarData(calendarData);
141
+ setIsLoading(false);
142
+
143
+ await connection.close();
144
+ }
145
+
146
+ useEffect(() => {
147
+ initDB();
148
+ }, []);
149
+
150
+ return (
151
+ <main className={`flex flex-col items-center justify-center min-h-screen mx-auto p-24 ${inter.className}`}>
152
+ <h1 className="text-5xl font-bold text-center">Open Source Calendar</h1>
153
+ <p className="text-center mt-2 text-sm">A calendar for open source model releases.</p>
154
+ <div className="mt-16">
155
+ {isLoading ? (
156
+ <p>Loading...</p>
157
+ ) : (
158
+ <>
159
+ {Object.entries(PROVIDERS_MAP)
160
+ .sort(([keyA], [keyB]) =>
161
+ calendarData[keyB as ProviderKey].reduce((sum, day) => sum + day.count, 0) -
162
+ calendarData[keyA as ProviderKey].reduce((sum, day) => sum + day.count, 0)
163
+ )
164
+ .map(([key, value]) => (
165
+ <div key={key} className="mb-8">
166
+ <h2 className="text-2xl font-bold mb-2">{value.name}</h2>
167
+ <ActivityCalendar
168
+ data={calendarData[key as ProviderKey]}
169
+ theme={{
170
+ dark: ['#161b22', value.color],
171
+ }}
172
+ colorScheme="dark"
173
+ renderBlock={(block, activity) => (
174
+ <MuiTooltip
175
+ title={`${activity.count} activities on ${activity.date}`}
176
+ >
177
+ {block}
178
+ </MuiTooltip>
179
+ )}
180
+ />
181
+ </div>
182
+ ))
183
+ }
184
+ </>
185
+ )}
186
  </div>
187
  </main>
188
  );
189
+ }