Spaces:
				
			
			
	
			
			
					
		Running
		
	
	
	
			
			
	
	
	
	
		
		
					
		Running
		
	Commit 
							
							·
						
						eda28cd
	
1
								Parent(s):
							
							22aa376
								
remove requirement for name, get user full name and avatar url
Browse files- src/components/Heatmap.tsx +34 -16
 - src/pages/[author]/index.tsx +24 -25
 - src/pages/index.tsx +47 -53
 - src/types/heatmap.ts +4 -2
 - src/utils/authors.ts +68 -0
 - src/utils/calendar.ts +10 -10
 
    	
        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 | 
         
            -
                  < 
     | 
| 34 | 
         
            -
             
     | 
| 35 | 
         
            -
             
     | 
| 36 | 
         
            -
                       
     | 
| 37 | 
         
            -
             
     | 
| 38 | 
         
            -
             
     | 
| 39 | 
         
            -
             
     | 
| 40 | 
         
            -
             
     | 
| 41 | 
         
            -
                       
     | 
| 42 | 
         
            -
             
     | 
| 43 | 
         
            -
             
     | 
| 44 | 
         
            -
             
     | 
| 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  
     | 
| 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  
     | 
| 76 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 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  
     | 
| 11 | 
         
            -
               
     | 
| 12 | 
         
            -
               
     | 
| 13 | 
         
            -
               
     | 
| 14 | 
         
            -
               
     | 
| 15 | 
         
            -
               
     | 
| 16 | 
         
            -
               
     | 
| 17 | 
         
            -
               
     | 
| 18 | 
         
            -
               
     | 
| 19 | 
         
            -
               
     | 
| 20 | 
         
            -
               
     | 
| 21 | 
         
            -
               
     | 
| 22 | 
         
            -
               
     | 
| 23 | 
         
            -
               
     | 
| 24 | 
         
            -
               
     | 
| 25 | 
         
            -
             
     | 
| 26 | 
         | 
| 27 | 
         
             
            export async function getStaticProps() {
         
     | 
| 28 | 
         
             
              try {
         
     | 
| 29 | 
         
            -
                const allAuthors =  
     | 
| 30 | 
         
            -
                  ({ authors }) => authors,
         
     | 
| 31 | 
         
            -
                );
         
     | 
| 32 | 
         
             
                const uniqueAuthors = Array.from(new Set(allAuthors));
         
     | 
| 33 | 
         | 
| 34 | 
         
            -
                const  
     | 
| 35 | 
         
            -
                const  
     | 
| 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  
     | 
| 52 | 
         
            -
                const calendarData = generateCalendarData(flatData, PROVIDERS_MAP);
         
     | 
| 53 | 
         | 
| 54 | 
         
             
                return {
         
     | 
| 55 | 
         
             
                  props: {
         
     | 
| 56 | 
         
             
                    calendarData,
         
     | 
| 57 | 
         
            -
                    providers:  
     | 
| 58 | 
         
             
                  },
         
     | 
| 59 | 
         
             
                  revalidate: 3600, // regenerate every hour
         
     | 
| 60 | 
         
             
                };
         
     | 
| 
         @@ -63,7 +47,7 @@ export async function getStaticProps() { 
     | 
|
| 63 | 
         
             
                return {
         
     | 
| 64 | 
         
             
                  props: {
         
     | 
| 65 | 
         
             
                    calendarData: {},
         
     | 
| 66 | 
         
            -
                    providers:  
     | 
| 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 | 
         
            -
                      { 
     | 
| 108 | 
         
            -
                        .sort(
         
     | 
| 109 | 
         
            -
                           
     | 
| 110 | 
         
            -
                             
     | 
| 111 | 
         
            -
                             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 112 | 
         
             
                        )
         
     | 
| 113 | 
         
            -
                        .map(( 
     | 
| 114 | 
         
            -
                           
     | 
| 115 | 
         
            -
             
     | 
| 116 | 
         
            -
             
     | 
| 117 | 
         
            -
                               
     | 
| 118 | 
         
            -
             
     | 
| 119 | 
         
            -
             
     | 
| 120 | 
         
            -
             
     | 
| 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:  
     | 
| 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:  
     | 
| 11 | 
         
             
            ): CalendarData => {
         
     | 
| 12 | 
         
             
              const data: Record<string, Activity[]> = Object.fromEntries(
         
     | 
| 13 | 
         
            -
                 
     | 
| 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 | 
         
            -
                 
     | 
| 27 | 
         
             
                  if (authors.some((author) => item.id.startsWith(author))) {
         
     | 
| 28 | 
         
            -
                    countMap[ 
     | 
| 29 | 
         
            -
                    countMap[ 
     | 
| 30 | 
         
            -
                      (countMap[ 
     | 
| 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 | 
         
            -
                 
     | 
| 40 | 
         
            -
                  const count = countMap[ 
     | 
| 41 | 
         
            -
                  data[ 
     | 
| 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 | 
         
            +
            };
         
     |