File size: 3,778 Bytes
f51ff8f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
// get url of current tab
chrome.tabs.query({ active: true, currentWindow: true }, async function (tabs) {
  const tab = tabs[0];
  const url = tab.url;
  const prefix = 'https://huggingface.co/';

  if (!url.startsWith(prefix)) {
    // show error message in .message
    const message = document.querySelector('.container');
    message.innerHTML = '<h2>Not a Hugging Face page.</h2>';
    return;
  }

  // get project type and path
  const [type, path] = getProjectTypeAndPath(url);

  if (type === null) {
    // show error message in .message
    const message = document.querySelector('.container');
    message.innerHTML = '<h2>No project found.</h2>';
    return;
  }

  // get project info
  const res = await fetch(`https://huggingface.co/api/${type}/${path}/likers?expand[]=likeAt`)
  const likers = await res.json()
  let likeHistory = transformLikesData(likers)

  if (likeHistory.length > 40) {
    // sample 20 points
    const sampledLikeHistory = []
    const step = Math.floor(likeHistory.length / 20)
    for (let i = 0; i < likeHistory.length; i += step) {
      sampledLikeHistory.push(likeHistory[i])
    }
    // Add the last point if it's not included
    if (sampledLikeHistory[sampledLikeHistory.length - 1].x !== likeHistory[likeHistory.length - 1].x) {
      sampledLikeHistory.push(likeHistory[likeHistory.length - 1])
    }
    likeHistory = sampledLikeHistory
  }

  // if likeHistory is empty, show error message
  if (likeHistory.length === 0) {
    const message = document.querySelector('.container');
    message.innerHTML = '<h2>No likes found.</h2>'; 
    return
  }

  const svg = document.querySelector('.line-chart');

  new chartXkcd.XY(svg, {
    title: 'Like History',
    xLabel: 'Time',
    yLabel: 'Likes',
    data: {
      datasets: [{
        label: path,
        data: likeHistory,
      }],
    },
    options: {
      // unxkcdify: true,
      showLegend: false,
      xTickCount: 3,
      yTickCount: 4,
      legendPosition: chartXkcd.config.positionType.upLeft,
      showLine: true,
      timeFormat: 'MM/DD/YYYY',
      dotSize: 0.5,
      dataColors: [
        "#FBBF24", // Warm Yellow
        "#60A5FA", // Light Blue
        "#14B8A6", // Teal
        "#A78BFA", // Soft Purple
        "#FF8C00", // Orange
        "#64748B", // Slate Gray
        "#FB7185", // Coral Pink
        "#6EE7B7", // Mint Green
        "#2563EB", // Deep Blue
        "#374151"  // Charcoal
      ]
    },
  });
  

});

function getProjectTypeAndPath(url) {
  // Define the possible project types
  // Create a URL object to parse the given url
  const parsedUrl = new URL(url);

  // Extract the pathname from the URL and split it into parts
  const pathParts = parsedUrl.pathname.split('/').filter(part => part.length > 0);

  if (pathParts.length < 2) {
    return [null, null];
  }


  // The project type should be the first part of the path
  const type = pathParts[0];
  console.log(type);
  
  if (type !== 'spaces' && type !== 'datasets') {
    // If the type is not spaces or datasets, it should be models
    const actualType = 'models';
    const path = pathParts.slice(0, 2).join('/');
    return [actualType, path];
  } else {
    const path = pathParts.slice(1, 3).join('/');
    return [type, path];

  }
}

function transformLikesData(likesData) {
  // Step 1
  likesData.sort((a, b) => new Date(a.likedAt) - new Date(b.likedAt));

  // Step 2
  const cumulativeLikes = {};
  let cumulativeCount = 0;

  // Step 3
  likesData.forEach(like => {
    const date = like.likedAt
    cumulativeCount++;
    cumulativeLikes[date] = cumulativeCount;
  });

  // Step 4
  const transformedData = Object.keys(cumulativeLikes).map(date => ({
    x: date,
    y: cumulativeLikes[date].toString()
  }));

  return transformedData;
}