import React, { useState, useEffect, useMemo } from "react";
import { generateCalendarData } from "../utils/calendar";
import {
OpenSourceHeatmapProps,
ProviderInfo,
ModelData,
CalendarData,
} from "../types/heatmap";
import Heatmap from "../components/Heatmap";
import { fetchAllProvidersData, fetchAllAuthorsData } from "../utils/authors";
import UserSearchDialog from "../components/UserSearchDialog";
const PROVIDERS: ProviderInfo[] = [
{ color: "#ff7000", authors: ["mistralai"] },
{ color: "#1877F2", authors: ["meta-llama", "facebook"] },
{ color: "#10A37F", authors: ["openai"] },
{ color: "#cc785c", authors: ["Anthropic"] },
{ color: "#DB4437", authors: ["google"] },
{ color: "#5E35B1", authors: ["allenai"] },
{ color: "#0066CC", authors: ["apple"] },
{ color: "#FEB800", authors: ["microsoft"] },
{ color: "#76B900", authors: ["nvidia"] },
{ color: "#00A8E0", authors: ["deepseek-ai"] },
{ color: "#6366F1", authors: ["Qwen"] },
{ color: "#FF6B6B", authors: ["CohereLabs"] },
{ color: "#4ECDC4", authors: ["ibm-granite"] },
{ color: "#A855F7", authors: ["stabilityai"] },
];
export async function getStaticProps() {
try {
const allAuthors = PROVIDERS.flatMap(({ authors }) => authors);
const uniqueAuthors = Array.from(new Set(allAuthors));
const flatData: ModelData[] = await fetchAllAuthorsData(uniqueAuthors);
const updatedProviders = await fetchAllProvidersData(PROVIDERS);
const calendarData = generateCalendarData(flatData, updatedProviders);
return {
props: {
calendarData,
providers: updatedProviders,
},
revalidate: 3600,
};
} catch (error) {
console.error("Error fetching data:", error);
return {
props: {
calendarData: {},
providers: PROVIDERS,
},
revalidate: 60,
};
}
}
const ProviderCard = React.memo(({
provider,
calendarData,
isExpanded,
onToggle
}: {
provider: ProviderInfo,
calendarData: CalendarData,
isExpanded: boolean,
onToggle: () => void
}) => {
const providerName = provider.fullName || provider.authors[0];
const totalActivity = calendarData[providerName]?.reduce((sum, day) => sum + day.count, 0) || 0;
const recentActivity = calendarData[providerName]?.slice(-30).reduce((sum, day) => sum + day.count, 0) || 0;
return (
{isExpanded && (
)}
);
});
const OpenSourceHeatmap: React.FC = ({
calendarData,
providers,
}) => {
const [isLoading, setIsLoading] = useState(true);
const [expandedProviders, setExpandedProviders] = useState>(new Set());
const [filterQuery, setFilterQuery] = useState("");
const [sortBy, setSortBy] = useState<"total" | "recent">("total");
useEffect(() => {
if (calendarData && Object.keys(calendarData).length > 0) {
setIsLoading(false);
}
}, [calendarData]);
const sortedAndFilteredProviders = useMemo(() => {
let filtered = providers;
if (filterQuery) {
filtered = providers.filter(p =>
(p.fullName || p.authors[0]).toLowerCase().includes(filterQuery.toLowerCase())
);
}
return filtered.sort((a, b) => {
const aName = a.fullName || a.authors[0];
const bName = b.fullName || b.authors[0];
if (sortBy === "total") {
return calendarData[bName]?.reduce((sum, day) => sum + day.count, 0) || 0 -
calendarData[aName]?.reduce((sum, day) => sum + day.count, 0) || 0;
} else {
return calendarData[bName]?.slice(-30).reduce((sum, day) => sum + day.count, 0) || 0 -
calendarData[aName]?.slice(-30).reduce((sum, day) => sum + day.count, 0) || 0;
}
});
}, [providers, calendarData, filterQuery, sortBy]);
const toggleProvider = (providerName: string) => {
setExpandedProviders(prev => {
const newSet = new Set(prev);
if (newSet.has(providerName)) {
newSet.delete(providerName);
} else {
newSet.add(providerName);
}
return newSet;
});
};
const toggleAll = () => {
if (expandedProviders.size === sortedAndFilteredProviders.length) {
setExpandedProviders(new Set());
} else {
setExpandedProviders(new Set(sortedAndFilteredProviders.map(p => p.fullName || p.authors[0])));
}
};
return (
{/* Header */}
AI Labs Activity Dashboard
Track models, datasets, and spaces from leading AI organizations on Hugging Face
{/* Controls */}
{/* Stats Summary */}
{!isLoading && (
{providers.length}
Organizations
{Object.values(calendarData).reduce((total, days) =>
total + days.reduce((sum, day) => sum + day.count, 0), 0
).toLocaleString()}
Total Activities
{Object.values(calendarData).reduce((total, days) =>
total + days.slice(-30).reduce((sum, day) => sum + day.count, 0), 0
).toLocaleString()}
Last 30 Days
)}
{/* Provider List */}
{isLoading ? (
) : (
{sortedAndFilteredProviders.length === 0 ? (
No organizations found matching "{filterQuery}"
) : (
sortedAndFilteredProviders.map((provider) => {
const providerName = provider.fullName || provider.authors[0];
return (
toggleProvider(providerName)}
/>
);
})
)}
)}
);
};
export default React.memo(OpenSourceHeatmap);