cfahlgren1 HF staff commited on
Commit
eda28cd
1 Parent(s): 22aa376

remove requirement for name, get user full name and avatar url

Browse files
src/components/Heatmap.tsx CHANGED
@@ -1,17 +1,36 @@
1
  import React from "react";
2
  import ActivityCalendar from "react-activity-calendar";
3
- import { Tooltip } from "@mui/material";
4
  import Link from "next/link";
5
 
6
  type HeatmapProps = {
7
  data: Array<{ date: string; count: number; level: number }>;
8
  color: string;
9
  providerName: string;
 
 
10
  };
11
 
12
- const Heatmap: React.FC<HeatmapProps> = ({ data, color, providerName }) => {
13
  return (
14
- <div className="flex flex-col items-center">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  <div className="w-full overflow-x-auto flex justify-center">
16
  <ActivityCalendar
17
  data={data}
@@ -30,19 +49,18 @@ const Heatmap: React.FC<HeatmapProps> = ({ data, color, providerName }) => {
30
  )}
31
  />
32
  </div>
33
- <div>
34
- <p className="text-sm italic light:text-slate-500">
35
- Models, Datasets, and Spaces created by{" "}
36
- <Link
37
- href={`https://huggingface.co/${providerName}`}
38
- target="_blank"
39
- rel="noopener noreferrer"
40
- className="hover:underline text-blue-500"
41
- >
42
- {providerName}.
43
- </Link>
44
- </p>
45
- </div>
46
  </div>
47
  );
48
  };
 
1
  import React from "react";
2
  import ActivityCalendar from "react-activity-calendar";
3
+ import { Tooltip, Avatar } from "@mui/material";
4
  import Link from "next/link";
5
 
6
  type HeatmapProps = {
7
  data: Array<{ date: string; count: number; level: number }>;
8
  color: string;
9
  providerName: string;
10
+ fullName: string;
11
+ avatarUrl: string;
12
  };
13
 
14
+ const Heatmap: React.FC<HeatmapProps> = ({ data, color, providerName, fullName, avatarUrl }) => {
15
  return (
16
+ <div className="flex flex-col items-center w-full mx-auto">
17
+ <div className="flex flex-col sm:flex-row items-center mb-4 w-full justify-center">
18
+ {avatarUrl && (
19
+ <Avatar src={avatarUrl} alt={fullName} className="mb-2 sm:mb-0 sm:mr-4" sx={{ width: 48, height: 48 }} />
20
+ )}
21
+ <div className="text-center sm:text-left">
22
+ <h2 className="text-lg font-semibold">
23
+ <Link
24
+ href={`https://huggingface.co/${providerName}`}
25
+ target="_blank"
26
+ rel="noopener noreferrer"
27
+ className="hover:text-blue-500 hover:underline"
28
+ >
29
+ {fullName}
30
+ </Link>
31
+ </h2>
32
+ </div>
33
+ </div>
34
  <div className="w-full overflow-x-auto flex justify-center">
35
  <ActivityCalendar
36
  data={data}
 
49
  )}
50
  />
51
  </div>
52
+ <p className="text-xs italic text-slate-500 mt-2 text-center">
53
+ Models, Datasets, and Spaces created on {" "}
54
+ <Link
55
+ href="https://huggingface.co"
56
+ target="_blank"
57
+ rel="noopener noreferrer"
58
+ className="hover:underline"
59
+ >
60
+ Hugging Face
61
+ </Link>
62
+ .
63
+ </p>
 
64
  </div>
65
  );
66
  };
src/pages/[author]/index.tsx CHANGED
@@ -3,6 +3,7 @@ import { GetServerSidePropsContext } from "next";
3
  import { OpenSourceHeatmapProps } from "../../types/heatmap";
4
  import { generateCalendarData } from "../../utils/calendar";
5
  import Heatmap from "../../components/Heatmap";
 
6
 
7
  const DEFAULT_COLOR = "#FF9D00";
8
 
@@ -30,12 +31,14 @@ const OpenSourceHeatmap: React.FC<OpenSourceHeatmapProps> = ({
30
  calendarData[keyB].reduce((sum, day) => sum + day.count, 0) -
31
  calendarData[keyA].reduce((sum, day) => sum + day.count, 0)
32
  )
33
- .map(([providerName, { color }]) => (
34
  <Heatmap
35
  key={providerName}
36
  data={calendarData[providerName]}
37
  color={color}
38
  providerName={providerName}
 
 
39
  />
40
  ))}
41
  </div>
@@ -49,31 +52,20 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
49
 
50
  const authorColor = color || DEFAULT_COLOR;
51
 
52
- const providers = {
53
- [author as string]: {
54
- color: authorColor as string,
55
- authors: [author as string],
56
- },
57
- };
58
-
59
  try {
60
- const entityTypes = ["models", "datasets", "spaces"];
61
- const allData = await Promise.all(
62
- entityTypes.map(async (type) => {
63
- const response = await fetch(
64
- `https://huggingface.co/api/${type}?author=${author}&sort=createdAt&direction=-1`,
65
- );
66
- const data = await response.json();
67
- return data.map((item: any) => ({
68
- createdAt: item.createdAt,
69
- id: item.id,
70
- type: type,
71
- }));
72
- }),
73
- );
74
 
75
- const flatData = allData.flat();
76
- const calendarData = generateCalendarData(flatData, providers);
 
 
 
 
 
 
 
 
 
77
 
78
  return {
79
  props: {
@@ -88,7 +80,14 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
88
  props: {
89
  calendarData: {},
90
  color: authorColor,
91
- providers,
 
 
 
 
 
 
 
92
  },
93
  };
94
  }
 
3
  import { OpenSourceHeatmapProps } from "../../types/heatmap";
4
  import { generateCalendarData } from "../../utils/calendar";
5
  import Heatmap from "../../components/Heatmap";
6
+ import { fetchUserData, fetchAuthorData } from "../../utils/authors";
7
 
8
  const DEFAULT_COLOR = "#FF9D00";
9
 
 
31
  calendarData[keyB].reduce((sum, day) => sum + day.count, 0) -
32
  calendarData[keyA].reduce((sum, day) => sum + day.count, 0)
33
  )
34
+ .map(([providerName, { color, fullName, avatarUrl }]) => (
35
  <Heatmap
36
  key={providerName}
37
  data={calendarData[providerName]}
38
  color={color}
39
  providerName={providerName}
40
+ fullName={fullName ?? providerName}
41
+ avatarUrl={avatarUrl ?? ''}
42
  />
43
  ))}
44
  </div>
 
52
 
53
  const authorColor = color || DEFAULT_COLOR;
54
 
 
 
 
 
 
 
 
55
  try {
56
+ const { fullName, avatarUrl } = await fetchUserData([author as string]);
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
+ const providers = {
59
+ [author as string]: {
60
+ color: authorColor as string,
61
+ authors: [author as string],
62
+ fullName,
63
+ avatarUrl,
64
+ },
65
+ };
66
+
67
+ const flatData = await fetchAuthorData(author as string);
68
+ const calendarData = generateCalendarData(flatData, [providers[author as string]]);
69
 
70
  return {
71
  props: {
 
80
  props: {
81
  calendarData: {},
82
  color: authorColor,
83
+ providers: {
84
+ [author as string]: {
85
+ color: authorColor as string,
86
+ authors: [author as string],
87
+ fullName: author,
88
+ avatarUrl: null,
89
+ },
90
+ },
91
  },
92
  };
93
  }
src/pages/index.tsx CHANGED
@@ -6,55 +6,39 @@ import {
6
  ModelData,
7
  } from "../types/heatmap";
8
  import Heatmap from "../components/Heatmap";
 
9
 
10
- const PROVIDERS_MAP: Record<string, ProviderInfo> = {
11
- "Mistral AI": { color: "#ff7000", authors: ["mistralai"] },
12
- Meta: { color: "#1877F2", authors: ["facebook", "meta-llama"] },
13
- OpenAI: { color: "#10A37F", authors: ["openai"] },
14
- Anthropic: { color: "#cc785c", authors: ["Anthropic"] },
15
- Google: { color: "#DB4437", authors: ["google"] },
16
- "Allen Institute for AI": { color: "#5E35B1", authors: ["allenai"] },
17
- Apple: { color: "#0088cc", authors: ["apple"] },
18
- Microsoft: { color: "#FEB800", authors: ["microsoft"] },
19
- NVIDIA: { color: "#76B900", authors: ["nvidia"] },
20
- DeepSeek: { color: "#0088cc", authors: ["deepseek-ai"] },
21
- Qwen: { color: "#0088cc", authors: ["Qwen"] },
22
- "Cohere For AI": { color: "#4C6EE6", authors: ["CohereForAI"] },
23
- IBM: { color: "#4C6EE6", authors: ["ibm-granite"] },
24
- "Stability AI": { color: "#A020F0", authors: ["stabilityai"] },
25
- };
26
 
27
  export async function getStaticProps() {
28
  try {
29
- const allAuthors = Object.values(PROVIDERS_MAP).flatMap(
30
- ({ authors }) => authors,
31
- );
32
  const uniqueAuthors = Array.from(new Set(allAuthors));
33
 
34
- const entityTypes = ["models", "datasets", "spaces"];
35
- const allData = await Promise.all(
36
- uniqueAuthors.flatMap((author) =>
37
- entityTypes.map(async (type) => {
38
- const response = await fetch(
39
- `https://huggingface.co/api/${type}?author=${author}&sort=createdAt&direction=-1`,
40
- );
41
- const data = await response.json();
42
- return data.map((item: any) => ({
43
- createdAt: item.createdAt,
44
- id: item.id,
45
- type: type,
46
- }));
47
- }),
48
- ),
49
- );
50
 
51
- const flatData: ModelData[] = allData.flat();
52
- const calendarData = generateCalendarData(flatData, PROVIDERS_MAP);
53
 
54
  return {
55
  props: {
56
  calendarData,
57
- providers: PROVIDERS_MAP,
58
  },
59
  revalidate: 3600, // regenerate every hour
60
  };
@@ -63,7 +47,7 @@ export async function getStaticProps() {
63
  return {
64
  props: {
65
  calendarData: {},
66
- providers: PROVIDERS_MAP,
67
  },
68
  revalidate: 60, // retry after 1 minute if there was an error
69
  };
@@ -104,21 +88,31 @@ const OpenSourceHeatmap: React.FC<OpenSourceHeatmapProps> = ({
104
  <p className="text-center">Loading...</p>
105
  ) : (
106
  <div className="space-y-16">
107
- {Object.entries(providers)
108
- .sort(
109
- ([keyA], [keyB]) =>
110
- calendarData[keyB].reduce((sum, day) => sum + day.count, 0) -
111
- calendarData[keyA].reduce((sum, day) => sum + day.count, 0),
 
 
 
 
 
112
  )
113
- .map(([providerName, { color }]) => (
114
- <div key={providerName} className="flex flex-col items-center">
115
- <Heatmap
116
- data={calendarData[providerName]}
117
- color={color}
118
- providerName={providerName}
119
- />
120
- </div>
121
- ))}
 
 
 
 
 
122
  </div>
123
  )}
124
  </div>
 
6
  ModelData,
7
  } from "../types/heatmap";
8
  import Heatmap from "../components/Heatmap";
9
+ import { fetchAllProvidersData, fetchAllAuthorsData } from "../utils/authors";
10
 
11
+ const PROVIDERS: ProviderInfo[] = [
12
+ { color: "#ff7000", authors: ["mistralai"] },
13
+ { color: "#1877F2", authors: ["meta-llama", "facebook", ] },
14
+ { color: "#10A37F", authors: ["openai"] },
15
+ { color: "#cc785c", authors: ["Anthropic"] },
16
+ { color: "#DB4437", authors: ["google"] },
17
+ { color: "#5E35B1", authors: ["allenai"] },
18
+ { color: "#0088cc", authors: ["apple"] },
19
+ { color: "#FEB800", authors: ["microsoft"] },
20
+ { color: "#76B900", authors: ["nvidia"] },
21
+ { color: "#0088cc", authors: ["deepseek-ai"] },
22
+ { color: "#0088cc", authors: ["Qwen"] },
23
+ { color: "#4C6EE6", authors: ["CohereForAI"] },
24
+ { color: "#4C6EE6", authors: ["ibm-granite"] },
25
+ { color: "#A020F0", authors: ["stabilityai"] },
26
+ ];
27
 
28
  export async function getStaticProps() {
29
  try {
30
+ const allAuthors = PROVIDERS.flatMap(({ authors }) => authors);
 
 
31
  const uniqueAuthors = Array.from(new Set(allAuthors));
32
 
33
+ const flatData: ModelData[] = await fetchAllAuthorsData(uniqueAuthors);
34
+ const updatedProviders = await fetchAllProvidersData(PROVIDERS);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ const calendarData = generateCalendarData(flatData, updatedProviders);
 
37
 
38
  return {
39
  props: {
40
  calendarData,
41
+ providers: updatedProviders,
42
  },
43
  revalidate: 3600, // regenerate every hour
44
  };
 
47
  return {
48
  props: {
49
  calendarData: {},
50
+ providers: PROVIDERS,
51
  },
52
  revalidate: 60, // retry after 1 minute if there was an error
53
  };
 
88
  <p className="text-center">Loading...</p>
89
  ) : (
90
  <div className="space-y-16">
91
+ {providers
92
+ .sort((a, b) =>
93
+ calendarData[b.fullName || b.authors[0]].reduce(
94
+ (sum, day) => sum + day.count,
95
+ 0
96
+ ) -
97
+ calendarData[a.fullName || a.authors[0]].reduce(
98
+ (sum, day) => sum + day.count,
99
+ 0
100
+ )
101
  )
102
+ .map((provider) => {
103
+ const providerName = provider.fullName || provider.authors[0];
104
+ return (
105
+ <div key={providerName} className="flex flex-col items-center">
106
+ <Heatmap
107
+ data={calendarData[providerName]}
108
+ color={provider.color}
109
+ providerName={providerName}
110
+ fullName={provider.fullName ?? providerName}
111
+ avatarUrl={provider.avatarUrl ?? ''}
112
+ />
113
+ </div>
114
+ );
115
+ })}
116
  </div>
117
  )}
118
  </div>
src/types/heatmap.ts CHANGED
@@ -1,6 +1,8 @@
1
  export interface ProviderInfo {
2
  color: string;
3
  authors: string[];
 
 
4
  }
5
 
6
  export interface ModelData {
@@ -22,5 +24,5 @@ export interface OpenSourceHeatmapProps {
22
  calendarData: CalendarData;
23
  author: string;
24
  color: string;
25
- providers: Record<string, ProviderInfo>;
26
- }
 
1
  export interface ProviderInfo {
2
  color: string;
3
  authors: string[];
4
+ fullName?: string;
5
+ avatarUrl?: string | null;
6
  }
7
 
8
  export interface ModelData {
 
24
  calendarData: CalendarData;
25
  author: string;
26
  color: string;
27
+ providers: ProviderInfo[];
28
+ }
src/utils/authors.ts ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ProviderInfo, ModelData } from "../types/heatmap";
2
+
3
+ export async function fetchUserData(authors: string[]) {
4
+ const primaryAuthor = authors[0];
5
+ try {
6
+ const response = await fetch(`https://huggingface.co/api/users/${primaryAuthor}/overview`);
7
+ const data = await response.json();
8
+ return {
9
+ fullName: data.fullname || primaryAuthor,
10
+ avatarUrl: data.avatarUrl || null,
11
+ };
12
+ } catch (error) {
13
+ console.error(`Error fetching user data for ${primaryAuthor}:`, error);
14
+ return {
15
+ fullName: primaryAuthor,
16
+ avatarUrl: null,
17
+ };
18
+ }
19
+ }
20
+
21
+ export async function fetchAllProvidersData(providers: ProviderInfo[]): Promise<ProviderInfo[]> {
22
+ return Promise.all(providers.map(async (providerInfo) => {
23
+ const { fullName, avatarUrl } = await fetchUserData(providerInfo.authors);
24
+ return {
25
+ ...providerInfo,
26
+ fullName,
27
+ avatarUrl: avatarUrl || null
28
+ };
29
+ }));
30
+ }
31
+
32
+ export async function fetchAuthorData(author: string): Promise<ModelData[]> {
33
+ const entityTypes = ["models", "datasets", "spaces"] as const;
34
+ try {
35
+ const allData = await Promise.all(
36
+ entityTypes.map(async (type) => {
37
+ const response = await fetch(
38
+ `https://huggingface.co/api/${type}?author=${author}&sort=createdAt&direction=-1`
39
+ );
40
+ if (!response.ok) {
41
+ throw new Error(`HTTP error! status: ${response.status}`);
42
+ }
43
+ const data = await response.json();
44
+ return data.map((item: any): ModelData => ({
45
+ createdAt: item.createdAt,
46
+ id: item.id,
47
+ }));
48
+ })
49
+ );
50
+
51
+ return allData.flat();
52
+ } catch (error) {
53
+ console.error(`Error fetching data for author ${author}:`, error);
54
+ return [];
55
+ }
56
+ }
57
+
58
+ export async function fetchAllAuthorsData(authors: string[]): Promise<ModelData[]> {
59
+ try {
60
+ const allData = await Promise.all(
61
+ authors.map(async (author) => await fetchAuthorData(author))
62
+ );
63
+ return allData.flat();
64
+ } catch (error) {
65
+ console.error("Error fetching data for all authors:", error);
66
+ return [];
67
+ }
68
+ }
src/utils/calendar.ts CHANGED
@@ -7,10 +7,10 @@ import {
7
 
8
  export const generateCalendarData = (
9
  modelData: ModelData[],
10
- providers: Record<string, ProviderInfo>,
11
  ): CalendarData => {
12
  const data: Record<string, Activity[]> = Object.fromEntries(
13
- Object.keys(providers).map((provider) => [provider, []]),
14
  );
15
 
16
  const today = new Date();
@@ -23,11 +23,11 @@ export const generateCalendarData = (
23
 
24
  modelData.forEach((item) => {
25
  const dateString = item.createdAt.split("T")[0];
26
- Object.entries(providers).forEach(([provider, { authors }]) => {
27
  if (authors.some((author) => item.id.startsWith(author))) {
28
- countMap[provider] = countMap[provider] || {};
29
- countMap[provider][dateString] =
30
- (countMap[provider][dateString] || 0) + 1;
31
  }
32
  });
33
  });
@@ -36,9 +36,9 @@ export const generateCalendarData = (
36
  for (let d = new Date(startDate); d <= today; d.setDate(d.getDate() + 1)) {
37
  const dateString = d.toISOString().split("T")[0];
38
 
39
- Object.entries(providers).forEach(([provider]) => {
40
- const count = countMap[provider]?.[dateString] || 0;
41
- data[provider].push({ date: dateString, count, level: 0 });
42
  });
43
  }
44
 
@@ -68,4 +68,4 @@ export const generateCalendarData = (
68
  });
69
 
70
  return data;
71
- };
 
7
 
8
  export const generateCalendarData = (
9
  modelData: ModelData[],
10
+ providers: ProviderInfo[]
11
  ): CalendarData => {
12
  const data: Record<string, Activity[]> = Object.fromEntries(
13
+ providers.map((provider) => [provider.authors[0], []]),
14
  );
15
 
16
  const today = new Date();
 
23
 
24
  modelData.forEach((item) => {
25
  const dateString = item.createdAt.split("T")[0];
26
+ providers.forEach(({ authors }) => {
27
  if (authors.some((author) => item.id.startsWith(author))) {
28
+ countMap[authors[0]] = countMap[authors[0]] || {};
29
+ countMap[authors[0]][dateString] =
30
+ (countMap[authors[0]][dateString] || 0) + 1;
31
  }
32
  });
33
  });
 
36
  for (let d = new Date(startDate); d <= today; d.setDate(d.getDate() + 1)) {
37
  const dateString = d.toISOString().split("T")[0];
38
 
39
+ providers.forEach(({ authors }) => {
40
+ const count = countMap[authors[0]]?.[dateString] || 0;
41
+ data[authors[0]].push({ date: dateString, count, level: 0 });
42
  });
43
  }
44
 
 
68
  });
69
 
70
  return data;
71
+ };