├── .gitignore ├── README.md ├── assets ├── banner.png ├── screenshot.png ├── settings-page.png └── settings.png └── plugin ├── background.js ├── content.css ├── content.js ├── icons ├── icon128.png ├── icon16.png ├── icon32.png └── icon48.png ├── manifest.json ├── settings.html └── settings.js /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hugging Face tl;dr 2 | 3 |

4 | Screenshot of the descriptions shown by the Chrome Plugin 5 |

6 | 7 |

8 | Experimental tl;dr summaries for datasets on the Hugging Face Hub! 9 |

10 | 11 | The Hugging Face tl;dr Chrome extension enhances your browsing experience on the Hugging Face Hub by providing concise tl;dr summaries for datasets. With this extension, you can quickly grasp the key points of a dataset when navigating through the Hugging Face Hub, making it easier to identify relevant datasets for your machine learning projects. 12 | 13 |

14 | Screenshot of the descriptions shown by the Chrome Plugin 15 |

16 | 17 | **Disclaimer**: *This extension is an experimental project aimed at gauging the usefulness of tl;dr summaries for datasets on the Hugging Face Hub. The summaries are generated using the [mistralai/Mixtral-8x7B-Instruct-v0.1](https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1) model, and the quality of the summaries may vary. If you encounter any issues or have suggestions for improvements, please open an issue before submitting a pull request.* 18 | 19 | ## ✨ Features 20 | 21 | - 🤖 Automatically fetches and displays tl;dr summaries for datasets on the Hugging Face Hub 22 | - 📜 Summaries are added as a compact section below each dataset card, making them easily noticeable 23 | - 👍 Provide feedback on the usefulness of the summaries through a simple rating system 24 | 25 | 26 | 27 | https://github.com/davanstrien/huggingface-tldr/assets/8995957/9f30886e-0917-4c42-b7c7-b940172eae4e 28 | 29 | 30 | 31 | ## 🚀 Getting Started 32 | 33 |
34 | Installation 35 | 36 | 1. Clone this repository or download the source code as a ZIP file using this [link](https://github.com/davanstrien/huggingface-tldr/archive/refs/heads/main.zip). 37 | 2. If you downloaded the source code as a ZIP file, extract the contents to a directory on your computer. 38 | 3. Open Google Chrome and navigate to `chrome://extensions`. 39 | 4. Enable "Developer mode" using the toggle switch in the top right corner. 40 | 5. Click on "Load unpacked" and select the `plugin` directory from the source code you downloaded. 41 | 6. The Hugging Face tl;dr extension should now be installed and active in your Chrome browser. 42 | 43 |
44 | 45 |
46 | 47 | Usage 48 | 49 | 1. Navigate to the Hugging Face Hub and browse through the datasets. 50 | 2. The extension will automatically fetch and display the tl;dr summaries below each dataset card. 51 | 3. If you find a summary helpful, give it an upvote. If not, you can downvote it to provide feedback. 52 | 4. To enable voting functionality and contribute to the improvement of the summaries, you need to provide a valid token in the extension settings. You can obtain a token from your Hugging Face account settings. 53 | 54 |
55 | 56 | ## 🔧 Extension Settings 57 | 58 | To enable voting functionality and provide feedback on the tl;dr summaries, you need to provide a valid Hugging Face token in the extension settings. Follow the steps below to configure the extension settings: 59 | 60 | 1. Right-click on the extension icon in the Chrome toolbar. 61 | 2. Select "Options" from the context menu. 62 | 3. In the settings page, enter your Hugging Face token in the provided input field. 63 | 4. Click on the "Save" button to store the token. 64 | 65 | 66 | ![](assets/settings.png) 67 | 68 | Add a read-only token from your Hugging Face account settings to enable voting functionality. 69 | ![](assets/settings-page.png) 70 | 71 | Note: The token is securely stored in the extension's local storage and is only used for authenticating requests to the Hugging Face API when submitting votes. You only need to provide a read-only token, as the extension does not require write access to your Hugging Face account. 72 | 73 | ## Disclaimer 74 | 75 | This extension is an experimental project. The tl;dr summaries are currently generated using [mistralai/Mixtral-8x7B-Instruct-v0.1](https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1) 76 | 77 | ## Contributing 78 | 79 | Contributions to the Hugging Face tl;dr extension are welcome! If you encounter any issues or have suggestions for improvements, please open an issue before submitting a pull request. 80 | -------------------------------------------------------------------------------- /assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davanstrien/huggingface-tldr/de9ca42f5b0649a1587e69966f77264247ceb181/assets/banner.png -------------------------------------------------------------------------------- /assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davanstrien/huggingface-tldr/de9ca42f5b0649a1587e69966f77264247ceb181/assets/screenshot.png -------------------------------------------------------------------------------- /assets/settings-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davanstrien/huggingface-tldr/de9ca42f5b0649a1587e69966f77264247ceb181/assets/settings-page.png -------------------------------------------------------------------------------- /assets/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davanstrien/huggingface-tldr/de9ca42f5b0649a1587e69966f77264247ceb181/assets/settings.png -------------------------------------------------------------------------------- /plugin/background.js: -------------------------------------------------------------------------------- 1 | chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { 2 | if (request.action === "getToken") { 3 | chrome.storage.local.get("token", (data) => { 4 | sendResponse({ token: data.token }); 5 | }); 6 | return true; // Required to use sendResponse asynchronously 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /plugin/content.css: -------------------------------------------------------------------------------- 1 | .dataset-tooltip { 2 | display: none; 3 | position: absolute; 4 | background-color: #000; 5 | color: #fff; 6 | padding: 5px; 7 | border-radius: 4px; 8 | font-size: 12px; 9 | z-index: 1000; 10 | max-width: 200px; 11 | word-wrap: break-word; 12 | top: 100%; 13 | left: 0; 14 | } 15 | 16 | .overview-card-wrapper header { 17 | position: relative; 18 | } 19 | 20 | .hover-icon { 21 | position: absolute; 22 | top: 0; 23 | right: 0; 24 | font-size: 16px; 25 | color: #888; 26 | cursor: pointer; 27 | padding: 5px; 28 | } 29 | 30 | .hover-icon:hover { 31 | color: #000; 32 | } 33 | 34 | .vote-button { 35 | background-color: transparent; 36 | border: none; 37 | cursor: pointer; 38 | font-size: 16px; 39 | margin-right: 5px; 40 | } 41 | 42 | .vote-button:hover { 43 | opacity: 0.8; 44 | } 45 | 46 | .vote-button.voted { 47 | opacity: 1; 48 | } 49 | 50 | .vote-button:not(.voted) { 51 | opacity: 0.5; 52 | } -------------------------------------------------------------------------------- /plugin/content.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates a unique user ID and stores it in the localStorage. 3 | * If a user ID already exists, retrieves and returns it. 4 | * @returns {string} The generated or existing user ID. 5 | */ 6 | function generateUserId() { 7 | const existingUserId = localStorage.getItem("userId"); 8 | if (existingUserId) { 9 | return existingUserId; 10 | } else { 11 | const newUserId = Math.random().toString(36).substring(2, 15); 12 | localStorage.setItem("userId", newUserId); 13 | return newUserId; 14 | } 15 | } 16 | 17 | function isTokenAvailable(callback) { 18 | try { 19 | chrome.runtime.sendMessage({ action: "getToken" }, (response) => { 20 | if (chrome.runtime.lastError) { 21 | console.error("Error in sendMessage:", chrome.runtime.lastError); 22 | callback(false); 23 | } else { 24 | callback(!!response.token); 25 | } 26 | }); 27 | } catch (error) { 28 | console.error("Error in isTokenAvailable:", error); 29 | callback(false); 30 | } 31 | } 32 | 33 | function addDatasetDescription(descriptions, box) { 34 | const datasetName = box.querySelector("h4").textContent.trim(); 35 | const description = descriptions[datasetName]; 36 | 37 | if (!box.querySelector(".tl-dr-description")) { 38 | let displayText = "No tl;dr description currently available"; 39 | if (description) { 40 | displayText = "tl;dr " + description; 41 | } 42 | 43 | const descriptionElement = document.createElement("div"); 44 | descriptionElement.innerHTML = displayText; 45 | descriptionElement.style.marginTop = "5px"; 46 | descriptionElement.style.marginLeft = "5px"; 47 | descriptionElement.style.fontSize = "12px"; 48 | descriptionElement.style.color = "#888"; 49 | descriptionElement.classList.add("tl-dr-description"); 50 | 51 | const voteText = document.createElement("div"); 52 | voteText.textContent = "Is this tl;dr summary useful?"; 53 | voteText.style.marginTop = "5px"; 54 | voteText.style.marginLeft = "5px"; 55 | voteText.style.fontSize = "12px"; 56 | voteText.style.color = "#888"; 57 | voteText.style.fontWeight = "bold"; 58 | 59 | const voteButtons = document.createElement("div"); 60 | voteButtons.style.marginTop = "5px"; 61 | voteButtons.style.marginLeft = "5px"; 62 | 63 | const upvoteButton = document.createElement("button"); 64 | upvoteButton.textContent = "👍"; 65 | upvoteButton.classList.add("vote-button"); 66 | upvoteButton.dataset.vote = "1"; 67 | upvoteButton.dataset.dataset = datasetName; 68 | 69 | const downvoteButton = document.createElement("button"); 70 | downvoteButton.textContent = "👎"; 71 | downvoteButton.classList.add("vote-button"); 72 | downvoteButton.dataset.vote = "0"; 73 | downvoteButton.dataset.dataset = datasetName; 74 | 75 | voteButtons.appendChild(upvoteButton); 76 | voteButtons.appendChild(downvoteButton); 77 | 78 | box.appendChild(descriptionElement); 79 | box.appendChild(voteText); 80 | box.appendChild(voteButtons); 81 | } 82 | } 83 | 84 | function isMainDatasetsPage() { 85 | const url = window.location.href; 86 | const mainPagePattern = /^https:\/\/huggingface\.co\/datasets(?:\?.*)?$/; 87 | return mainPagePattern.test(url); 88 | } 89 | 90 | function fetchAndAddDescriptions() { 91 | if (isMainDatasetsPage()) { 92 | fetch( 93 | "https://huggingface.co/datasets/davanstrien/descriptions/resolve/main/data.json?download=true" 94 | ) 95 | .then((response) => response.json()) 96 | .then((data) => { 97 | const datasetBoxes = document.querySelectorAll( 98 | ".overview-card-wrapper" 99 | ); 100 | datasetBoxes.forEach((box) => { 101 | addDatasetDescription(data, box); 102 | }); 103 | }) 104 | .catch((error) => { 105 | console.error("Error fetching dataset descriptions:", error); 106 | }); 107 | } 108 | } 109 | let previousVotes = {}; 110 | 111 | document.addEventListener("click", (event) => { 112 | if (event.target.classList.contains("vote-button") && isMainDatasetsPage()) { 113 | const { vote } = event.target.dataset; 114 | const datasetName = event.target.dataset.dataset; 115 | 116 | // Check if the user has already voted for the same option 117 | if (previousVotes[datasetName] === parseInt(vote)) { 118 | // Display an "already voted" message 119 | const alreadyVotedMessage = document.createElement("div"); 120 | alreadyVotedMessage.textContent = "Already voted!"; 121 | alreadyVotedMessage.style.marginTop = "5px"; 122 | alreadyVotedMessage.style.color = "#ff0000"; 123 | alreadyVotedMessage.style.fontSize = "12px"; 124 | event.target.parentNode.appendChild(alreadyVotedMessage); 125 | 126 | // Remove the "already voted" message after 2 seconds 127 | setTimeout(() => { 128 | alreadyVotedMessage.remove(); 129 | }, 2000); 130 | 131 | return; // Exit the event listener 132 | } 133 | 134 | const overviewCardWrapper = event.target.closest(".overview-card-wrapper"); 135 | if (overviewCardWrapper) { 136 | const descriptionElement = 137 | overviewCardWrapper.querySelector(".tl-dr-description"); 138 | const description = descriptionElement 139 | ? descriptionElement.textContent.trim() 140 | : "No tl;dr description available"; 141 | 142 | const userID = generateUserId(); // Generate or retrieve the user ID 143 | 144 | const payload = { 145 | dataset: datasetName, 146 | description: description, 147 | vote: parseInt(vote), 148 | userID: userID, // Include the user ID in the payload 149 | }; 150 | 151 | // Check if the token is available 152 | isTokenAvailable((tokenAvailable) => { 153 | if (tokenAvailable) { 154 | // Retrieve the token from the background script 155 | chrome.runtime.sendMessage({ action: "getToken" }, (response) => { 156 | const { token } = response; 157 | // Token is available, proceed with vote submission 158 | fetch("https://davanstrien-dataset-tldr.hf.space/vote", { 159 | method: "POST", 160 | headers: { 161 | "Content-Type": "application/json", 162 | Authorization: `${token}`, 163 | }, 164 | body: JSON.stringify(payload), 165 | }) 166 | .then((response) => response.json()) 167 | .then((data) => { 168 | console.log("Vote submitted successfully:", data); 169 | 170 | // Update the previous vote for the dataset 171 | previousVotes[datasetName] = parseInt(vote); 172 | 173 | // Set the opacity of all vote buttons to 0.5 174 | const voteButtons = 175 | overviewCardWrapper.querySelectorAll(".vote-button"); 176 | voteButtons.forEach((button) => { 177 | button.style.opacity = "0.5"; 178 | button.classList.remove("voted"); 179 | }); 180 | 181 | // Set the opacity of the current voted button to 1 and add the "voted" class 182 | event.target.style.opacity = "1"; 183 | event.target.classList.add("voted"); 184 | 185 | // Display a success message 186 | const successMessage = document.createElement("div"); 187 | successMessage.textContent = "Vote registered!"; 188 | successMessage.style.marginTop = "5px"; 189 | successMessage.style.color = "#4caf50"; 190 | successMessage.style.fontSize = "12px"; 191 | overviewCardWrapper.appendChild(successMessage); 192 | 193 | // Remove the success message after 2 seconds 194 | setTimeout(() => { 195 | successMessage.remove(); 196 | }, 2000); 197 | }) 198 | .catch((error) => { 199 | console.error("Error submitting vote:", error); 200 | }); 201 | }); 202 | } else { 203 | // Token is missing, display an alert or message to the user 204 | alert( 205 | "Please provide the token in the extension settings to submit your vote." 206 | ); 207 | } 208 | }); 209 | } 210 | } 211 | }); 212 | 213 | const observer = new MutationObserver((mutations) => { 214 | if (isMainDatasetsPage()) { 215 | mutations.forEach((mutation) => { 216 | if (mutation.type === "childList") { 217 | const { addedNodes } = mutation; 218 | addedNodes.forEach((node) => { 219 | if ( 220 | node.nodeType === Node.ELEMENT_NODE && 221 | node.classList.contains("overview-card-wrapper") 222 | ) { 223 | fetchAndAddDescriptions(); 224 | } 225 | }); 226 | } 227 | }); 228 | } 229 | }); 230 | 231 | const observerOptions = { 232 | childList: true, 233 | subtree: true, 234 | }; 235 | 236 | const targetNode = document.body; 237 | observer.observe(targetNode, observerOptions); 238 | 239 | // Add descriptions to the initial set of dataset boxes 240 | fetchAndAddDescriptions(); 241 | -------------------------------------------------------------------------------- /plugin/icons/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davanstrien/huggingface-tldr/de9ca42f5b0649a1587e69966f77264247ceb181/plugin/icons/icon128.png -------------------------------------------------------------------------------- /plugin/icons/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davanstrien/huggingface-tldr/de9ca42f5b0649a1587e69966f77264247ceb181/plugin/icons/icon16.png -------------------------------------------------------------------------------- /plugin/icons/icon32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davanstrien/huggingface-tldr/de9ca42f5b0649a1587e69966f77264247ceb181/plugin/icons/icon32.png -------------------------------------------------------------------------------- /plugin/icons/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davanstrien/huggingface-tldr/de9ca42f5b0649a1587e69966f77264247ceb181/plugin/icons/icon48.png -------------------------------------------------------------------------------- /plugin/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "Hugging Face tl;dr", 4 | "version": "1.0", 5 | "description": "Adds tl;dr descriptions to datasets on the Hugging Face Hub.", 6 | "permissions": [ 7 | "activeTab", 8 | "storage" 9 | ], 10 | "options_page": "settings.html", 11 | "host_permissions": [ 12 | "https://huggingface.co/datasets/davanstrien/*" 13 | ], 14 | "content_scripts": [ 15 | { 16 | "matches": [ 17 | "https://huggingface.co/datasets*" 18 | ], 19 | "js": [ 20 | "content.js" 21 | ], 22 | "css": [ 23 | "content.css" 24 | ] 25 | } 26 | ], 27 | "icons": { 28 | "16": "icons/icon16.png", 29 | "32": "icons/icon32.png", 30 | "48": "icons/icon48.png", 31 | "128": "icons/icon128.png" 32 | }, 33 | "background": { 34 | "service_worker": "background.js" 35 | } 36 | } -------------------------------------------------------------------------------- /plugin/settings.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hugging Face tl;dr Extension Settings 5 | 6 | 7 |

Extension Settings

8 |

9 | In order to submit feedback on the ratings you need to provide a read only 10 | Hugging Face Hub token.
You can get a read only token from 11 | this page. 12 |

13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /plugin/settings.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", () => { 2 | const tokenInput = document.getElementById("token"); 3 | const saveButton = document.getElementById("save"); 4 | 5 | // Load the saved token from storage 6 | chrome.storage.local.get("token", (data) => { 7 | if (data.token) { 8 | tokenInput.value = data.token; 9 | } 10 | }); 11 | 12 | // Save the token when the Save button is clicked 13 | saveButton.addEventListener("click", () => { 14 | const token = tokenInput.value; 15 | chrome.storage.local.set({ token: token }, () => { 16 | console.log("Token saved"); 17 | alert("Token saved successfully!"); 18 | }); 19 | }); 20 | }); 21 | --------------------------------------------------------------------------------