Email or Website Summarization Browser Extension

Browser Extensions

Continuing on the journey of browser extension, lets see how a browser extension can help with Email or Website summarization using a Generative AI API integration.

I used NodeJS as my backend to create a API based on VertexAI for summarization. Here is the a documentation to create an API using VertexAI.

Now getting into extension development, basic development content is already available in the blog post here and the important part if the popup.js and content.js

popup.js

document.getElementById("summarizeEmail").addEventListener("click", () => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, { action: "getEmailContent" }, (response) => {
if (response.emailContent) {
chrome.runtime.sendMessage({ action: "summarizeEmail", emailContent: response.emailContent }, (response) => {
document.getElementById("summary").innerText = response.summary;
});
}
});
});
});

document.getElementById("summarizeText").addEventListener("click", () => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.scripting.executeScript(
{
target: { tabId: tabs[0].id },
function: getSelectedText,
},
(results) => {
if (results && results[0] && results[0].result) {
chrome.runtime.sendMessage({ action: "summarizeText", textContent: results[0].result }, (response) => {
document.getElementById("summary").innerText = response.summary;
});
}
}
);
});
});

function getSelectedText() {
return window.getSelection().toString();
}

content.js

// Function to inject the "AI Summary" button into Gmail
const injectAISummaryButton = () => {
const existingButton = document.getElementById("ai-summary-button");
if (existingButton) {
return; // Button already exists, do not add it again
}

const targetElement = document.querySelector(".AO");
if (targetElement) {
const aiSummaryButton = document.createElement("button");
aiSummaryButton.id = "ai-summary-button";
aiSummaryButton.innerText = "AI Summary";
aiSummaryButton.style.position = "absolute";
aiSummaryButton.style.top = "10px";
aiSummaryButton.style.right = "10px";
aiSummaryButton.style.zIndex = 10000;
aiSummaryButton.style.backgroundColor = "#007bff";
aiSummaryButton.style.color = "#ffffff";
aiSummaryButton.style.border = "none";
aiSummaryButton.style.padding = "10px";
aiSummaryButton.style.cursor = "pointer";

aiSummaryButton.addEventListener("click", () => {
const emailContent = getEmailContent();
if (emailContent) {
chrome.runtime.sendMessage({ action: "summarizeEmail", emailContent: emailContent }, (response) => {
showAISummaryOverlay(response.summary);
});
}
});

targetElement.prepend(aiSummaryButton);
}
};

// Function to extract email content from Gmail's DOM
const getEmailContent = () => {
const emailContentElement = document.querySelector(".AO"); // Selector for the email body content
return emailContentElement ? emailContentElement.innerText : "";
};

// Function to create and show the AI Summary overlay
const showAISummaryOverlay = (summary) => {
// Remove existing overlay if present
const existingOverlay = document.getElementById("ai-summary-overlay");
if (existingOverlay) {
existingOverlay.remove();
}

// Create overlay elements
const overlay = document.createElement("div");
overlay.id = "ai-summary-overlay";
overlay.style.position = "fixed";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.height = "100%";
overlay.style.backgroundColor = "rgba(0, 0, 0, 0.7)";
overlay.style.zIndex = 10000;
overlay.style.display = "flex";
overlay.style.alignItems = "center";
overlay.style.justifyContent = "center";

const content = document.createElement("div");
content.style.backgroundColor = "white";
content.style.padding = "20px";
content.style.borderRadius = "10px";
content.style.maxWidth = "500px";
content.style.boxShadow = "0 0 10px rgba(0, 0, 0, 0.5)";

const title = document.createElement("h2");
title.innerText = "AI Summary";
title.style.marginTop = "0";

const summaryText = document.createElement("p");
summaryText.innerText = summary;

const closeButton = document.createElement("button");
closeButton.innerText = "Close";
closeButton.style.marginTop = "20px";
closeButton.style.padding = "10px";
closeButton.style.backgroundColor = "#007bff";
closeButton.style.color = "white";
closeButton.style.border = "none";
closeButton.style.borderRadius = "5px";
closeButton.style.cursor = "pointer";

closeButton.addEventListener("click", () => {
overlay.remove();
});

// Append elements
content.appendChild(title);
content.appendChild(summaryText);
content.appendChild(closeButton);
overlay.appendChild(content);
document.body.appendChild(overlay);
};

// Inject the "AI Summary" button when the content script is loaded
injectAISummaryButton();

// Observe changes in the Gmail DOM to inject the button when necessary
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === "childList") {
injectAISummaryButton();
}
}
});

observer.observe(document.body, { childList: true, subtree: true });

// Listen for messages from the popup or background script
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "getEmailContent") {
const emailContent = getEmailContent();
sendResponse({ emailContent: emailContent });
}
});

background.js

const API_ENDPOINT = "http://localhost:3001/secure/ai";

const getSummary = (content, callback) => {
const encodedContent = encodeURIComponent(content);

fetch(API_ENDPOINT + "/summary", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ prompt: "Please summarize the below uri encoded content. \n\n" + content }),
})
.then((response) => {
if (!response.ok) {
throw new Error("Network response was not ok " + response.statusText);
}
return response.json();
})
.then((data) => {
if (callback && typeof callback === "function") {
callback(data);
}
})
.catch((error) => {
console.error("Error: " + error);
if (callback && typeof callback === "function") {
callback({ summary: "Error fetching summary." });
}
});
};

chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: "summarizeText",
title: "AI Summary",
contexts: ["selection"],
});
});

chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === "summarizeText") {
const selectedText = info.selectionText;

console.log("Selected Text: " + selectedText);

getSummary(selectedText, (data) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
func: (summary) => {
const summaryElement = document.createElement("div");
summaryElement.style.position = "fixed";
summaryElement.style.bottom = "10px";
summaryElement.style.right = "10px";
summaryElement.style.backgroundColor = "white";
summaryElement.style.border = "1px solid black";
summaryElement.style.padding = "10px";
summaryElement.style.zIndex = 10000;
summaryElement.innerText = summary;
document.body.appendChild(summaryElement);
},
args: [data.message],
});
});
}
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "summarizeEmail") {
const selectedText = request.emailContent;

console.log("Selected Email Content: " + selectedText);

getSummary(selectedText, (data) => {
sendResponse({ summary: data.message });
});

return true; // Will respond asynchronously.
}
});

Explanation on whats happening,

  1. Listen to the gmail page for the page loads, Once the page is loaded invoke the injectAISummaryButton in the content.js
  2. “AI Summary button will be injected at the top right corner of the page”
  3. A context menu is also added when a text is selected. The click event i registered in the popup.js.
  4. Upon selecting the text in any web page and clicking on the context menu. or clicking on the “AI Summary” on gmail page will send the data of the email over the api and show the summarized response to the user.

Refer the full chrome extension plugin at GitHub

The Evolution of Browser Extensions: From Web Customization to Advanced Development Tools

Browser Extensions

It’s been a while that I published a post. A week before, I created a new Chrome extension and shared with my team and noticed the new developers didn’t have knowledge on how powerful the browser extensions can be. It pushed me to write a short post about the history and power of browser extensions.

A Brief History

Browser extensions have dramatically transformed how users interact with the internet, offering a plethora of customization options and functionalities that enhance productivity, security, streamline workflows and user experience. These small software modules, integrated into web browsers like Chrome, Edge, Firefox etc., enable users and developers to tailor their browsing experience, automate tasks, and access additional features not available in standard browser installations. The evolution of browser extensions has marked a significant milestone in web development, fostering a community of developers who continuously innovate and simplify complex tasks.

The Early Days

Browser extensions trace their origins back to the early days of web browsers. The first notable implementation was by Internet Explorer in the late 1990s, which allowed for basic plugins to extend browser capabilities. Early days of these extensions allowed developers to add custom menu bars(also known as Browser Bands and Communication Bands), context menu options for seamless integration with extensions. CricInfo cricket score ticker was a popular toolbar that I have used in the early days. Internet download manager extension is one another toolbar which allowed the download of audios and videos, changed the life of lot of Dial-up connection users.

The Rise of Firefox

However, it was Mozilla Firefox that popularized the concept of extensions by providing a dedicated platform for the developers to create and submit the add-ons. Themes and skins are a fun part of extensions world. Greasemonkey,one of the early add-ons, allowed users to write custom code on top of extensions was a boon for customization. I used my first AdBlocker script from UserScripts.org installed using Greasemonkey. This Add-on allowed me to create customize my own scripts without taking the hassle of publishing. Firefox’s various components like Add-ons, Extensions, and Plugins (Flash, Java, SilverLight, etc.) eventually evolved into standardized extensions.

The Chrome Era

Then came the days of Chrome. Google Chrome, introduced in 2008, revolutionized the extension landscape by offering streamlined APIs and a dedicated web store for its extensions. This facilitated easier development and distribution of extensions, leading to a surge in their popularity. The Chrome Web Store, launched in 2010, became a central hub for users to discover and install extensions, further solidifying their importance in the web ecosystem.

Extensions like Web Developer and React Developer Tools provide essential utilities for debugging, testing, and optimizing web applications. By leveraging browser APIs, developers can create tools that integrate seamlessly into their development environment, automating repetitive tasks and offering real-time insights into application performance.

Essential Extensions for Users

Some of the most used extensions include:
AdBlock / AdBlock Plus / uBlock Origin: Blocks ads on websites, improving load times and reducing clutter.
Microsoft Editor / Grammarly: Enhances writing by checking grammar, spelling, and style.
Honey: Automatically finds and applies coupon codes at checkout.
Bitwarden / LastPass: A password manager that stores and auto-fills passwords securely.
Momentum: Replaces the new tab page with a personal dashboard featuring a to-do list, weather, and inspirational quotes.
Dark Reader: Applies a dark theme to websites, reducing eye strain.

Must-Have Extensions for Developers

From a developer’s perspective, extensions are a boon. Some popular developer-friendly extensions are:
TamperMonkey – Modify website layouts, add/remove features, or automate actions – Alternative to Greasemonkey supporting userscripts.
React Developer Tools / Vue.js / – Provides debugging and inspection tools for React and Vue.js applications.
Redux DevTools – Allows developers to inspect every state and action payload for Redux applications.
Postman – A powerful tool for testing APIs by making HTTP requests.
JSON Viewer – Formats JSON data to make it more readable.
XPath Helper – Helps to find XPath expressions for elements on a webpage.
ColorZilla – Advanced color picker and gradient generator.
WhatFont – Identifies fonts used on a webpage.

We will see how to create a simple browser extension in the next post –Browser extension sample – Chrome/Edge – HttpRequestViewer