timqian's picture
Add extension
f51ff8f
raw
history blame
3.78 kB
// 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;
}