Creating a Chrome extension powered by AI technologies can greatly enhance user experience by integrating advanced features directly into the browser.
In this tutorial, we’ll walk you through the entire process of building a Chrome extension from scratch using an AI/ML API. Starting with setting up the development environment—including installing essential tools and configuring the project - we’ll guide you through each component of the extension. These components include:
Throughout the tutorial, we’ll highlight best practices for building Chrome extensions and managing user interactions effectively. By the end, you’ll have a strong foundation for creating Chrome extensions and the skills to develop your own AI-powered solutions.
Let’s take a brief look at the key technologies we’ll be using.
The AI/ML API is a revolutionary platform for developers and SaaS entrepreneurs, enabling seamless integration of advanced AI capabilities into their products. It provides access to over 200 cutting-edge AI models, covering a wide range of applications, from natural language processing (NLP) to computer vision.
By the end of this tutorial, you’ll not only have built a fully functional AI-powered Chrome extension but also gained valuable insights into leveraging advanced AI/ML technologies in real-world applications.
A Chrome extension is a lightweight software program designed to modify or enhance the functionality of the Google Chrome web browser. Built using familiar web technologies like HTML, CSS, and JavaScript, these extensions are purpose-driven, focusing on specific tasks or features. Their simplicity makes them easy to develop, understand, and use, providing users with tailored solutions to improve their browsing experience.
Building a Chrome extension requires understanding its structure, permissions, and interaction with web pages. In this section, we’ll set up our development environment and create the foundational files necessary to start building an extension.
Before diving into coding, ensure you have the following prerequisites:
A minimal Chrome extension requires at least three key files:
As we progress through this tutorial, we will also create:
Once your project structure is in place, you’ll be ready to begin writing the code for your extension.
The manifest.json file is the core of your Chrome extension. It provides the browser with essential information about your extension, including its purpose, functionality, and the permissions it requires. Let’s explore how to configure this file effectively.
The following configuration demonstrates the essential and additional fields in the manifest.json file for the "Summarize" Chrome extension.
You can create an icon for your Chrome extension using tools like ChatGPT or AI/ML platforms. Here’s the prompt I used to generate an icon:
Generate a black-and-white icon for my 'Summarize' Chrome extension.
This extension enables users to highlight specific text on a website
or summarize the entire page. It’s an AI-powered tool.
The icon should feature a solid white background.
Download the icon and rename it appropriately. You can use a single icon for different sizes.
The scripts.js file contains the logic that defines your extension's behavior. In this section, we’ll outline the key functionalities your script needs to implement.
Begin by setting up the essential variables:
const getSummary = async text => {
try {
const headers = {
Authorization: `Bearer ${AIML_API_KEY}`,
'Content-Type': 'application/json',
};
const jsonData = {
model: MODEL,
messages: [
{
role: 'assistant',
content:
`You are an AI assistant who
provides summaries for long texts.
You are using HTML tags to format
your response.`,
},
{
role: 'user',
content:
`Please summarize the following
text: ${text}`,
},
],
};
const response = await fetch(
'https://api.aimlapi.com/v1/chat/completions',
{
method: 'POST',
headers: headers,
body: JSON.stringify(jsonData),
}
);
if (!response.ok) {
throw new Error('API request failed');
}
const data = await response.json();
return data.choices[0].message.content;
} catch (error) {
console.log(`Error: ${error}`);
}
};
In the message, we specified that the model should send HTML in the response. This is crucial for preserving the original markup and formatting, ensuring that the content is displayed correctly on the web page.
Let’s create a function to generate the overlay. This function will add the overlay and a button to the DOM. Additionally, we’ll attach a click event listener to the button, which will trigger the getSummary function and display the response to the user.
const createSummaryOverlay = text => {
overlay = document.createElement('div');
overlay.id = 'summary-overlay';
overlay.style.display = 'none';
const summaryButton = document.createElement('button');
summaryButton.id = 'summary-button';
summaryButton.textContent = 'Summarize';
overlay.appendChild(summaryButton);
document.body.appendChild(overlay);
summaryButton.addEventListener('click', async () => {
summaryButton.textContent = 'Summarizing...';
summaryButton.disabled = true;
try {
const summary = await getSummary(text);
summaryButton.textContent = 'Summary';
const summaryContainer = document.createElement('div');
summaryContainer.innerHTML = summary;
overlay.appendChild(summaryContainer);
} catch (error) {
console.log(`Error: ${error}`);
}
});
};
const showOverlay = () => {
const selection = window.getSelection();
const range = selection.getRangeAt(0);
const rect = range.getBoundingClientRect();
overlay.style.display = 'flex';
overlay.style.top = `${window.scrollY + rect.top - 50}px`;
overlay.style.left = `${rect.left}px`;
};
document.addEventListener('mouseup', event => {
if (event.target.closest('#summary-overlay')) return;
const selectedText = window.getSelection().toString().trim();
if (selectedText.length > 200 && selectedText.length < 7000) {
if (!overlay) createSummaryOverlay();
showOverlay();
} else if (overlay) {
document.body.removeChild(overlay);
overlay = null;
}
});
const AIML_API_KEY = 'Your API KEY'; // Replace with your AIML_API_KEY
const MODEL = 'Your model';
let overlay = null;
const getSummary = async text => {
try {
const headers = {
Authorization: `Bearer ${AIML_API_KEY}`,
'Content-Type': 'application/json',
};
const jsonData = {
model: MODEL,
messages: [
{
role: 'assistant',
content:
`You are an AI assistant who
provides summaries for long texts.
You are using HTML tags to format
your response.`,
},
{
role: 'user',
content:
`Please summarize the following
text: ${text}`,
},
],
};
const response = await fetch(
'https://api.aimlapi.com/v1/chat/completions',
{
method: 'POST',
headers: headers,
body: JSON.stringify(jsonData),
}
);
if (!response.ok) {
throw new Error('API request failed');
}
const data = await response.json();
return data.choices[0].message.content;
} catch (error) {
console.log(`Error: ${error}`);
}
};
const createSummaryOverlay = text => {
overlay = document.createElement('div');
overlay.id = 'summary-overlay';
overlay.style.display = 'none';
const summaryButton = document.createElement('button');
summaryButton.id = 'summary-button';
summaryButton.textContent = 'Summarize';
overlay.appendChild(summaryButton);
document.body.appendChild(overlay);
summaryButton.addEventListener('click', async () => {
summaryButton.textContent = 'Summarizing...';
summaryButton.disabled = true;
try {
const summary = await getSummary(text);
summaryButton.textContent = 'Summary';
const summaryContainer = document.createElement('div');
summaryContainer.innerHTML = summary;
overlay.appendChild(summaryContainer);
} catch (error) {
console.log(`Error: ${error}`);
}
});
};
const showOverlay = () => {
const selection = window.getSelection();
const range = selection.getRangeAt(0);
const rect = range.getBoundingClientRect();
overlay.style.display = 'flex';
overlay.style.top = `${window.scrollY + rect.top - 50}px`;
overlay.style.left = `${rect.left}px`;
};
document.addEventListener('mouseup', event => {
if (event.target.closest('#summary-overlay')) return;
const selectedText = window.getSelection().toString().trim();
if (selectedText.length > 200 && selectedText.length < 7000) {
if (!overlay) createSummaryOverlay();
showOverlay();
} else if (overlay) {
document.body.removeChild(overlay);
overlay = null;
}
});
To ensure a smooth and intuitive user experience, your extension should feature a clean and user-friendly interface.
Define styles for the following elements:
Overlay Positioning: use absolute positioning to place the overlay near the selected text.
#summary-overlay {
max-width: 500px;
max-height: 500px;
overflow-y: scroll;
cursor: pointer;
position: absolute;
border-radius: 4px;
background-color: #333;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 10px;
box-sizing: border-box;
z-index: 10000;
color: #fff;
}
#summary-button {
background: transparent;
border: none;
font-size: 14px;
cursor: pointer;
z-index: 10001;
}
#summary-button:hover {
color: #000;
padding: 2px;
border-radius: 4px;
}
#summary-button:disabled {
color: #aaa;
cursor: default;
}
We’ve completed the first part - now you can select text and receive a summary of it. The next step is to configure the interface to summarize the entire website.
To enable summarization of the entire website, we need to make the following additions:
This file will define the user interface for the popup, allowing users to initiate a site-wide summary.
This script will handle the logic for the popup, including interacting with the main script and triggering the summarization process.
Add the following lines to configure the extension’s popup:
"action": {
"default_title": "Summarize site",
"default_popup": "popup.html"
}
With these updates, users will be able to interact with the extension via a popup to generate a summary for the entire website.
{
"manifest_version": 3,
"name": "Summarize",
"version": "1.0",
"description": "Write a summary of a website or text",
"host_permissions": ["*://*.aimlapi.com/*"],
"permissions": ["activeTab", "scripting"],
"action": {
"default_title": "Summarize site",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["scripts.js"],
"css": ["styles.css"]
}
],
"icons": {
"16": "icons/icon.png",
"48": "icons/icon.png",
"128": "icons/icon.png"
}
}
Open the popup.html file and insert the following code. This code defines the structure of the popup window, includes inline styles for simplicity, and connects the popup.js script.
<!DOCTYPE >
<html>
<head>
<title>Summarizer</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 10px;
width: 400px;
background-color: #333;
color: white;
}
button {
padding: 8px 12px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<h3>Summarize site</h3>
<button id="summarize-btn">Summarize site</button>
</body>
<script src="popup.js"></script>
</html>
The final step is to implement the functionality for the popup.js file. The following code adds an event listener to a button in the popup, enabling it to trigger the summarization process on the active browser tab:
document
.getElementById('summarize-btn')
.addEventListener('click', async function clickSummary() {
const bntSummary = document.getElementById('summarize-btn');
// Update button text to indicate the process has started
bntSummary.innerText = 'Summarizing...';
// Prevent multiple clicks during execution
bntSummary.removeEventListener('click', clickSummary);
// Change button style for feedback
bntSummary.style.backgroundColor = '#0053ac';
// Identify the active tab in the current browser window
const [tab] = await chrome.tabs.query({
active: true,
currentWindow: true,
});
// Execute the summarizeText function
//in the context of the active tab
chrome.scripting.executeScript({
target: { tabId: tab.id },
// Function to run in the tab's environment
func: summarizeText,
});
});
The next step is to handle communication between the content_script (executing in the context of the webpage) and the popup script (popup.js). This ensures that the summarization results are displayed in the popup after being processed.
The following code snippet demonstrates how to listen for messages from the content_script and dynamically update the popup UI to show the summarization result:
chrome.runtime.onMessage.addListener(
(request, sender, sendResponse) => {
// Remove the summarize button once
// the summary is available
document.getElementById("summarize-btn").remove();
// Create a new container to display the summary
const summaryContainer = document.createElement("div");
// Set the received summary as the container's content
summaryContainer.innerHTML = request.text;
// Add the container to the popup's body
document.body.appendChild(summaryContainer);
}
);
To complete the summarization process, the summarizeText function needs to be added. This function extracts the text content of the webpage and communicates with other parts of the extension to send the summarized result. Here’s the code for the function:
const summarizeText = async () => {
// Extracts all visible text from the webpage
const bodyText = document.body.innerText;
// Calls an external or predefined function to generate a summary
const summary = await getSummary(bodyText);
// Sends the summary to other parts of the extension
chrome.runtime.sendMessage({ text: summary });
};
Never hardcode your API key directly into your scripts, especially if you plan to distribute your extension. This practice exposes your key to potential misuse. Instead, consider using environment variables or prompting users to input their API key securely.
.env
file to your project and store your API key securely:AIML_API_KEY=your_api_key;
Chrome extensions do not natively support .env
files. Additional configurations are required to use environment variables within an extension. These details will be covered in an upcoming tutorial.
scripts.js
file. However, remember to replace this approach with a more secure implementation before distribution:// Set your AIML_API_KEY
const AIML_API_KEY = '';
With all components in place, it's time to load your extension into Chrome and see it in action.
chrome://extensions/
to access the extensions management page.summary-extension
or your project's specific folder).content_scripts
are properly configured in the manifest.json
file.With a solid foundation in place, you can enhance your extension further:
These enhancements will help make your extension more feature-rich, efficient, and user-friendly, providing greater value to your users.
Congratulations on building a Chrome extension that integrates advanced AI capabilities! This project demonstrates how combining web technologies with powerful APIs can create engaging and accessible user experiences. You now have the skills and knowledge to enhance this extension further or create entirely new ones that leverage AI/ML APIs.
You can explore the full implementation on GitHub: Summary-extention
Happy coding and good luck with your future projects!