cn-heatmap / src /pages /index.tsx
xianbao's picture
xianbao HF staff
Upload folder using huggingface_hub
7d8a788 verified
"use client";
import { Inter } from "next/font/google";
import ActivityCalendar from "react-activity-calendar";
import * as duckdb from "@duckdb/duckdb-wasm"
import { useState, useEffect } from "react";
import { Tooltip as MuiTooltip } from '@mui/material';
const inter = Inter({ subsets: ["latin"] });
interface CustomActivity {
date: string;
count: number;
level: number;
details: Array<{ provider: string; count: number }>;
}
type ProviderKey = "BAAI" | "deepseek-ai" | "internlm" | "Qwen" | "THUDM" | "TencentARC" | "01-ai" | "openbmb";
export default function Home() {
const [calendarData, setCalendarData] = useState<Record<ProviderKey, CustomActivity[]>>({} as Record<ProviderKey, CustomActivity[]>);
const [isLoading, setIsLoading] = useState(true);
const PROVIDERS_MAP: Record<ProviderKey, { name: string; color: string }> = {
"BAAI": { "name": "BAAI", "color": "#FF6F61" }, // Coral Red
"deepseek-ai": { "name": "Deepseek", "color": "#4B8BBE" }, // Soft Blue
"internlm": { "name": "Internlm", "color": "#34A853" }, // Emerald Green
"Qwen": { "name": "Qwen", "color": "#FFA500" }, // Bright Orange
"THUDM": { "name": "GLM", "color": "#00A6D6" }, // Cerulean Blue
"TencentARC": { "name": "Tencent", "color": "#1DA1F2" }, // Twitter Blue
"01-ai": { "name": "Yi/01", "color": "#FF6347" }, // Tomato Red
"openbmb": { "name": "OpenBMB", "color": "#8A2BE2" }, // Blue Violet
}
const getModelData = async (conn: duckdb.AsyncDuckDBConnection) => {
const result = await conn.query(`
SELECT
STRFTIME(DATE_TRUNC('day', CAST(createdAt AS DATE)), '%Y-%m-%d') AS date,
CASE
WHEN provider IN ('TencentARC', 'Tencent-Hunyuan') THEN 'TencentARC'
ELSE provider
END AS provider,
COUNT(*) AS count
FROM (
SELECT *, SPLIT_PART(id, '/', 1) AS provider
FROM models
WHERE CAST(createdAt AS DATE) >= DATE_TRUNC('year', CURRENT_DATE)
) subquery
WHERE provider IN (${Object.keys(PROVIDERS_MAP).map(p => `'${p}'`).join(', ')}, 'Tencent-Hunyuan')
GROUP BY 1, 2
ORDER BY date
`);
return result.toArray().map((row: any) => ({
date: row.date,
provider: row.provider,
count: Number(row.count)
}));
}
const generateCalendarData = (modelData: any[]) => {
const data: Record<ProviderKey, CustomActivity[]> = Object.keys(PROVIDERS_MAP).reduce((acc, provider) => {
acc[provider as ProviderKey] = [];
return acc;
}, {} as Record<ProviderKey, CustomActivity[]>);
const today = new Date();
const startOfYear = new Date(today.getFullYear(), 0, 1);
for (let d = new Date(startOfYear); d <= today; d.setDate(d.getDate() + 1)) {
const dateString = d.toISOString().split('T')[0];
Object.keys(PROVIDERS_MAP).forEach((provider) => {
const dayData = modelData.filter(item => item.date === dateString && item.provider === provider);
const count = dayData.reduce((sum, item) => sum + item.count, 0);
data[provider as ProviderKey].push({
date: dateString,
count,
level: 0,
details: dayData,
});
});
}
const avgCounts: Record<ProviderKey, number> = Object.fromEntries(
Object.keys(PROVIDERS_MAP).map(provider => [
provider,
data[provider as ProviderKey].reduce((sum, day) => sum + day.count, 0) / data[provider as ProviderKey].length || 0
])
) as Record<ProviderKey, number>;
Object.entries(data).forEach(([provider, days]) => {
const avgCount = avgCounts[provider as ProviderKey];
days.forEach(day => {
day.level = day.count === 0 ? 0 :
day.count <= avgCount * 0.5 ? 1 :
day.count <= avgCount ? 2 :
day.count <= avgCount * 1.5 ? 3 : 4;
});
});
return data;
}
const initDB = async () => {
const CDN_BASE = `https://cdn.jsdelivr.net/npm/@duckdb/duckdb-wasm@next`
const JSDELIVR_BUNDLES = {
mvp: {
mainModule: `${CDN_BASE}/dist/duckdb-mvp.wasm`,
mainWorker: `${CDN_BASE}/dist/duckdb-browser-mvp.worker.js`,
},
eh: {
mainModule: `${CDN_BASE}/dist/duckdb-eh.wasm`,
mainWorker: `${CDN_BASE}/dist/duckdb-browser-eh.worker.js`,
},
}
const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES)
const worker_url = URL.createObjectURL(
new Blob([`importScripts("${bundle.mainWorker}");`], {
type: "text/javascript",
})
)
const worker = new Worker(worker_url)
const logger = new duckdb.ConsoleLogger()
const db = new duckdb.AsyncDuckDB(logger, worker)
await db.instantiate(bundle.mainModule)
const connection = await db.connect()
await connection.query(`
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');
`);
const modelData = await getModelData(connection);
const calendarData = generateCalendarData(modelData);
setCalendarData(calendarData);
setIsLoading(false);
await connection.close();
}
useEffect(() => {
initDB();
}, []);
return (<main className={`grid grid-cols-1 md:grid-cols-2 gap-8 min-h-screen mx-auto p-6 ${inter.className}`}>
<div className="col-span-2 text-center">
<h1 className="text-5xl font-bold">Chinese AI Community: Open Source Heatmap</h1>
<p className="mt-2 text-sm">A heatmap for open source model releases.</p>
</div>
{isLoading ? (
<div className="col-span-2 text-center">
<p>Loading...</p>
</div>
) : (
Object.entries(PROVIDERS_MAP)
.sort(([keyA], [keyB]) =>
calendarData[keyB as ProviderKey].reduce((sum, day) => sum + day.count, 0) -
calendarData[keyA as ProviderKey].reduce((sum, day) => sum + day.count, 0)
)
.map(([key, value]) => (
<div key={key} className="mt-16 md:col-span-1">
<h2 className="text-2xl font-bold mb-2">{value.name}</h2>
<ActivityCalendar
data={calendarData[key as ProviderKey]}
theme={{
dark: ['#161b22', value.color],
}}
colorScheme="dark"
renderBlock={(block, activity) => (
<MuiTooltip title={`${activity.count} activities on ${activity.date}`}>
{block}
</MuiTooltip>
)}
/>
</div>
))
)}
</main>
);
}