File size: 7,520 Bytes
ab1abdd
20faa99
fdb7c58
 
 
 
ab1abdd
fdb7c58
 
d088c21
ab1abdd
929d75e
 
031ee4b
6c9b36e
d088c21
 
c4c2a3e
d088c21
 
 
 
122513a
d088c21
 
122513a
 
 
 
 
2b529d5
d088c21
c07926b
7fc47b1
 
d088c21
7fc47b1
 
d088c21
 
7fc47b1
d088c21
7fc47b1
 
 
 
d088c21
7fc47b1
122513a
7fc47b1
 
 
 
 
 
d088c21
7fc47b1
122513a
7fc47b1
c608763
7fc47b1
 
057b514
ab1abdd
929d75e
 
 
ab1abdd
057b514
929d75e
 
 
 
122513a
929d75e
122513a
929d75e
 
 
 
 
 
 
 
 
 
 
 
 
031ee4b
 
 
 
 
ab1abdd
 
 
 
fdb7c58
 
 
 
7fc47b1
c608763
 
7fc47b1
 
 
 
c608763
122513a
929d75e
 
 
 
 
 
 
122513a
 
ab1abdd
c608763
13006e3
929d75e
122513a
 
 
929d75e
c4c2a3e
122513a
929d75e
 
 
13006e3
929d75e
13006e3
929d75e
 
 
 
 
 
 
 
 
ab1abdd
 
929d75e
122513a
031ee4b
 
 
 
122513a
929d75e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122513a
929d75e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
03b5e31
c07926b
fdb7c58
7fc47b1
929d75e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
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";
import ProviderSummary from "../components/ProviderSummary";
import OrganizationCard from "../components/OrganizationCard";
import ProviderHeatmapSkeleton from "../components/ProviderHeatmapSkeleton";

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: "#0088cc", authors: ["apple"] },
  { color: "#FEB800", authors: ["microsoft"] },
  { color: "#76B900", authors: ["nvidia"] },
  { color: "#0088cc", authors: ["deepseek-ai"] },
  { color: "#0088cc", authors: ["Qwen"] },
  { color: "#4C6EE6", authors: ["CohereLabs"] },
  { color: "#4C6EE6", authors: ["ibm-granite"] },
  { color: "#A020F0", authors: ["stabilityai"] },
  { color: "#FEC912", authors: ["huggingface","HuggingFaceTB","HuggingFaceH4", "HuggingFaceM4", "HuggingFaceFW", "HuggingFaceFV","open-r1","parler-tts","nanotron","lerobot","distilbert"] },
];

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, // regenerate every hour
    };
  } catch (error) {
    console.error("Error fetching data:", error);
    return {
      props: {
        calendarData: {},
        providers: PROVIDERS,
      },
      revalidate: 60, // retry after 1 minute if there was an error
    };
  }
}

const ProviderHeatmap = React.memo(({ provider, calendarData }: { provider: ProviderInfo, calendarData: CalendarData }) => {
  const providerName = provider.fullName || provider.authors[0];
  const calendarKey = provider.authors[0]; // Use the same key as calendar generation
  const totalCount = calendarData[calendarKey]?.reduce((sum, day) => sum + day.count, 0) || 0;
  
  return (
    <div id={`provider-${calendarKey}`} className="relative bg-gradient-to-br from-card to-card/95 rounded-2xl border border-border shadow-lg hover:shadow-xl transition-all duration-300 p-6 group">
      {/* Organization Header */}
      <OrganizationCard
        provider={provider}
        calendarKey={calendarKey}
        providerName={providerName}
        totalCount={totalCount}
      />
      
      {/* Heatmap Section */}
      <div className="flex flex-col items-center bg-muted/30 rounded-xl p-3 group-hover:bg-muted/40 transition-colors duration-300">
        <Heatmap
          data={calendarData[calendarKey]}
          color={provider.color}
          providerName={providerName}
          fullName={provider.fullName ?? providerName}
          avatarUrl={provider.avatarUrl ?? ''}
          authorId={calendarKey}
          showHeader={false}
        />
      </div>

      {/* Releases Past Year placed under the heatmap */}
      <div className="mt-3 text-xs text-muted-foreground italic text-center">
        <span className="font-bold text-foreground">{totalCount}</span> new repos in the last year
      </div>
    </div>
  );
});

const OpenSourceHeatmap: React.FC<OpenSourceHeatmapProps> = ({
  calendarData,
  providers,
}) => {
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    if (calendarData && Object.keys(calendarData).length > 0) {
      setIsLoading(false);
    }
  }, [calendarData]);

  const sortedProviders = useMemo(() => 
    providers.sort((a, b) => {
      const aData = calendarData[a.authors[0]] || [];
      const bData = calendarData[b.authors[0]] || [];
      const aCount = aData.reduce((sum, day) => sum + day.count, 0);
      const bCount = bData.reduce((sum, day) => sum + day.count, 0);
      return bCount - aCount;
    }),
    [providers, calendarData]
  );

  return (
    <div className="w-full p-4 py-16 relative">
      <h1 className="text-3xl lg:text-5xl mt-16 font-bold text-center mb-2 text-foreground">
        Hugging Face Heatmap 🤗
      </h1>
      <div className="text-center text-sm my-8 space-y-4">
        <p className="text-muted-foreground">
          Open models, datasets, and apps from the top AI labs in the last year.
        </p>
      </div>

      {/* Provider Summary List */}
      <div className="mb-16 mx-auto">
        <div className="overflow-x-auto scrollbar-hide">
          <div className="flex gap-6 px-4 py-2 min-w-max justify-center">
            {sortedProviders.map((provider, index) => (
              <ProviderSummary
                key={provider.fullName || provider.authors[0]}
                provider={provider}
                calendarData={calendarData}
                rank={index + 1}
              />
            ))}
          </div>
        </div>
      </div>
           
      {isLoading ? (
        <div className="flex flex-col gap-8 max-w-4xl mx-auto mb-16">
          {Array.from({ length: 3 }).map((_, idx) => (
            <ProviderHeatmapSkeleton key={idx} />
          ))}
        </div>
      ) : (
        <>
          <div className="mb-16">
            <div className="flex flex-col gap-8 max-w-4xl mx-auto">
              {sortedProviders.slice(0, 3).map((provider, index) => (
                <ProviderHeatmap 
                  key={provider.fullName || provider.authors[0]}
                  provider={provider} 
                  calendarData={calendarData}
                />
              ))}
            </div>
          </div>

          {/* Rest of the providers */}
          {sortedProviders.length > 3 && (
              <div className="flex flex-col gap-8 max-w-4xl mx-auto">
                {sortedProviders.slice(3).map((provider, index) => (
                  <ProviderHeatmap 
                    key={provider.fullName || provider.authors[0]}
                    provider={provider} 
                    calendarData={calendarData}
                  />
                ))}
              </div>
          )}
        </>
      )}
      
      {/* CTA Section */}
      <div className="mt-24 mb-16 flex justify-center">
        <div className="bg-gradient-to-br from-card to-card/95 rounded-2xl border border-border shadow-lg hover:shadow-xl transition-all duration-300 p-8 max-w-2xl w-full text-center space-y-6">
          <div className="space-y-4">
            <h2 className="text-2xl lg:text-3xl font-bold text-foreground">
              Want Your Own Heatmap?
            </h2>
            <p className="text-muted-foreground text-lg">
              Search for any Hugging Face organization or user to see their model release activity.
            </p>
          </div>
          <div className="flex justify-center">
            <UserSearchDialog />
          </div>
        </div>
      </div>
    </div>
  );
};

export default OpenSourceHeatmap;