{"id":4763,"date":"2024-08-24T13:45:04","date_gmt":"2024-08-24T08:15:04","guid":{"rendered":"https:\/\/itechgenie.com\/myblog\/?p=4763"},"modified":"2024-08-24T13:45:04","modified_gmt":"2024-08-24T08:15:04","slug":"email-or-website-summarization-browser-extension","status":"publish","type":"post","link":"https:\/\/itechgenie.com\/myblog\/2024\/08\/email-or-website-summarization-browser-extension\/","title":{"rendered":"Email or Website Summarization Browser Extension"},"content":{"rendered":"\n<p>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.<\/p>\n\n\n\n<p>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 <a href=\"https:\/\/cloud.google.com\/vertex-ai\/generative-ai\/docs\/reference\/nodejs\/latest\">VertexAI<\/a>. <\/p>\n\n\n\n<p>Now getting into extension development, basic development content is already available in the blog post <a href=\"https:\/\/itechgenie.com\/myblog\/2024\/06\/browser-extension-sample-chrome-edge\/\" data-type=\"link\" data-id=\"https:\/\/itechgenie.com\/myblog\/2024\/06\/browser-extension-sample-chrome-edge\/\">here<\/a> and the important part if the popup.js and content.js <\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>popup.js<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">document.getElementById(\"summarizeEmail\").addEventListener(\"click\", () => {<br>  chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {<br>    chrome.tabs.sendMessage(tabs[0].id, { action: \"getEmailContent\" }, (response) => {<br>      if (response.emailContent) {<br>        chrome.runtime.sendMessage({ action: \"summarizeEmail\", emailContent: response.emailContent }, (response) => {<br>          document.getElementById(\"summary\").innerText = response.summary;<br>        });<br>      }<br>    });<br>  });<br>});<br><br>document.getElementById(\"summarizeText\").addEventListener(\"click\", () => {<br>  chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {<br>    chrome.scripting.executeScript(<br>      {<br>        target: { tabId: tabs[0].id },<br>        function: getSelectedText,<br>      },<br>      (results) => {<br>        if (results &amp;&amp; results[0] &amp;&amp; results[0].result) {<br>          chrome.runtime.sendMessage({ action: \"summarizeText\", textContent: results[0].result }, (response) => {<br>            document.getElementById(\"summary\").innerText = response.summary;<br>          });<br>        }<br>      }<br>    );<br>  });<br>});<br><br>function getSelectedText() {<br>  return window.getSelection().toString();<br>}<\/pre>\n\n\n\n<p class=\"has-medium-font-size\"><strong>content.js<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/\/ Function to inject the \"AI Summary\" button into Gmail<br>const injectAISummaryButton = () => {<br>  const existingButton = document.getElementById(\"ai-summary-button\");<br>  if (existingButton) {<br>    return; \/\/ Button already exists, do not add it again<br>  }<br><br>  const targetElement = document.querySelector(\".AO\");<br>  if (targetElement) {<br>    const aiSummaryButton = document.createElement(\"button\");<br>    aiSummaryButton.id = \"ai-summary-button\";<br>    aiSummaryButton.innerText = \"AI Summary\";<br>    aiSummaryButton.style.position = \"absolute\";<br>    aiSummaryButton.style.top = \"10px\";<br>    aiSummaryButton.style.right = \"10px\";<br>    aiSummaryButton.style.zIndex = 10000;<br>    aiSummaryButton.style.backgroundColor = \"#007bff\";<br>    aiSummaryButton.style.color = \"#ffffff\";<br>    aiSummaryButton.style.border = \"none\";<br>    aiSummaryButton.style.padding = \"10px\";<br>    aiSummaryButton.style.cursor = \"pointer\";<br><br>    aiSummaryButton.addEventListener(\"click\", () => {<br>      const emailContent = getEmailContent();<br>      if (emailContent) {<br>        chrome.runtime.sendMessage({ action: \"summarizeEmail\", emailContent: emailContent }, (response) => {<br>          showAISummaryOverlay(response.summary);<br>        });<br>      }<br>    });<br><br>    targetElement.prepend(aiSummaryButton);<br>  }<br>};<br><br>\/\/ Function to extract email content from Gmail's DOM<br>const getEmailContent = () => {<br>  const emailContentElement = document.querySelector(\".AO\"); \/\/ Selector for the email body content<br>  return emailContentElement ? emailContentElement.innerText : \"\";<br>};<br><br>\/\/ Function to create and show the AI Summary overlay<br>const showAISummaryOverlay = (summary) => {<br>  \/\/ Remove existing overlay if present<br>  const existingOverlay = document.getElementById(\"ai-summary-overlay\");<br>  if (existingOverlay) {<br>    existingOverlay.remove();<br>  }<br><br>  \/\/ Create overlay elements<br>  const overlay = document.createElement(\"div\");<br>  overlay.id = \"ai-summary-overlay\";<br>  overlay.style.position = \"fixed\";<br>  overlay.style.top = \"0\";<br>  overlay.style.left = \"0\";<br>  overlay.style.width = \"100%\";<br>  overlay.style.height = \"100%\";<br>  overlay.style.backgroundColor = \"rgba(0, 0, 0, 0.7)\";<br>  overlay.style.zIndex = 10000;<br>  overlay.style.display = \"flex\";<br>  overlay.style.alignItems = \"center\";<br>  overlay.style.justifyContent = \"center\";<br><br>  const content = document.createElement(\"div\");<br>  content.style.backgroundColor = \"white\";<br>  content.style.padding = \"20px\";<br>  content.style.borderRadius = \"10px\";<br>  content.style.maxWidth = \"500px\";<br>  content.style.boxShadow = \"0 0 10px rgba(0, 0, 0, 0.5)\";<br><br>  const title = document.createElement(\"h2\");<br>  title.innerText = \"AI Summary\";<br>  title.style.marginTop = \"0\";<br><br>  const summaryText = document.createElement(\"p\");<br>  summaryText.innerText = summary;<br><br>  const closeButton = document.createElement(\"button\");<br>  closeButton.innerText = \"Close\";<br>  closeButton.style.marginTop = \"20px\";<br>  closeButton.style.padding = \"10px\";<br>  closeButton.style.backgroundColor = \"#007bff\";<br>  closeButton.style.color = \"white\";<br>  closeButton.style.border = \"none\";<br>  closeButton.style.borderRadius = \"5px\";<br>  closeButton.style.cursor = \"pointer\";<br><br>  closeButton.addEventListener(\"click\", () => {<br>    overlay.remove();<br>  });<br><br>  \/\/ Append elements<br>  content.appendChild(title);<br>  content.appendChild(summaryText);<br>  content.appendChild(closeButton);<br>  overlay.appendChild(content);<br>  document.body.appendChild(overlay);<br>};<br><br>\/\/ Inject the \"AI Summary\" button when the content script is loaded<br>injectAISummaryButton();<br><br>\/\/ Observe changes in the Gmail DOM to inject the button when necessary<br>const observer = new MutationObserver((mutations) => {<br>  for (const mutation of mutations) {<br>    if (mutation.type === \"childList\") {<br>      injectAISummaryButton();<br>    }<br>  }<br>});<br><br>observer.observe(document.body, { childList: true, subtree: true });<br><br>\/\/ Listen for messages from the popup or background script<br>chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {<br>  if (request.action === \"getEmailContent\") {<br>    const emailContent = getEmailContent();<br>    sendResponse({ emailContent: emailContent });<br>  }<br>});<\/pre>\n\n\n\n<p class=\"has-medium-font-size\"><strong>background.js<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">const API_ENDPOINT = \"http:\/\/localhost:3001\/secure\/ai\";<br><br>const getSummary = (content, callback) => {<br>  const encodedContent = encodeURIComponent(content);<br><br>  fetch(API_ENDPOINT + \"\/summary\", {<br>    method: \"POST\",<br>    headers: {<br>      \"Content-Type\": \"application\/json\",<br>    },<br>    body: JSON.stringify({ prompt: \"Please summarize the below uri encoded content. \\n\\n\" + content }),<br>  })<br>    .then((response) => {<br>      if (!response.ok) {<br>        throw new Error(\"Network response was not ok \" + response.statusText);<br>      }<br>      return response.json();<br>    })<br>    .then((data) => {<br>      if (callback &amp;&amp; typeof callback === \"function\") {<br>        callback(data);<br>      }<br>    })<br>    .catch((error) => {<br>      console.error(\"Error: \" + error);<br>      if (callback &amp;&amp; typeof callback === \"function\") {<br>        callback({ summary: \"Error fetching summary.\" });<br>      }<br>    });<br>};<br><br>chrome.runtime.onInstalled.addListener(() => {<br>  chrome.contextMenus.create({<br>    id: \"summarizeText\",<br>    title: \"AI Summary\",<br>    contexts: [\"selection\"],<br>  });<br>});<br><br>chrome.contextMenus.onClicked.addListener((info, tab) => {<br>  if (info.menuItemId === \"summarizeText\") {<br>    const selectedText = info.selectionText;<br><br>    console.log(\"Selected Text: \" + selectedText);<br><br>    getSummary(selectedText, (data) => {<br>      chrome.scripting.executeScript({<br>        target: { tabId: tab.id },<br>        func: (summary) => {<br>          const summaryElement = document.createElement(\"div\");<br>          summaryElement.style.position = \"fixed\";<br>          summaryElement.style.bottom = \"10px\";<br>          summaryElement.style.right = \"10px\";<br>          summaryElement.style.backgroundColor = \"white\";<br>          summaryElement.style.border = \"1px solid black\";<br>          summaryElement.style.padding = \"10px\";<br>          summaryElement.style.zIndex = 10000;<br>          summaryElement.innerText = summary;<br>          document.body.appendChild(summaryElement);<br>        },<br>        args: [data.message],<br>      });<br>    });<br>  }<br>});<br><br>chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {<br>  if (request.action === \"summarizeEmail\") {<br>    const selectedText = request.emailContent;<br><br>    console.log(\"Selected Email Content: \" + selectedText);<br><br>    getSummary(selectedText, (data) => {<br>      sendResponse({ summary: data.message });<br>    });<br><br>    return true; \/\/ Will respond asynchronously.<br>  }<br>});<\/pre>\n\n\n\n<p>Explanation on whats happening,<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Listen to the gmail page for the page loads, Once the page is loaded invoke the  injectAISummaryButton in the <strong>content.js<\/strong><\/li>\n\n\n\n<li>&#8220;AI Summary button will be injected at the top right corner of the page&#8221; <img loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"370\" class=\"wp-image-4764\" style=\"width: 400px;\" src=\"http:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-132133.png\" alt=\"\" srcset=\"https:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-132133.png 956w, https:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-132133-300x277.png 300w, https:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-132133-768x710.png 768w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/li>\n\n\n\n<li>A context menu is also added when a text is selected. The click event i registered in the popup.js.                                                                             <img loading=\"lazy\" decoding=\"async\" width=\"450\" height=\"132\" class=\"wp-image-4766\" style=\"width: 450px;\" src=\"http:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-133007.png\" alt=\"\" srcset=\"https:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-133007.png 849w, https:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-133007-300x88.png 300w, https:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-133007-768x225.png 768w\" sizes=\"auto, (max-width: 450px) 100vw, 450px\" \/><\/li>\n\n\n\n<li>Upon selecting the text in any web page and clicking on the context menu. or clicking on the &#8220;AI Summary&#8221; on gmail page will send the data of the email over the api and show the summarized response to the user.<\/li>\n\n\n\n<li>  <img loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"274\" class=\"wp-image-4765\" style=\"width: 400px;\" src=\"http:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-132528.png\" alt=\"\" srcset=\"https:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-132528.png 1094w, https:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-132528-300x206.png 300w, https:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-132528-1024x702.png 1024w, https:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/08\/Screenshot-2024-08-24-132528-768x527.png 768w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/li>\n<\/ol>\n\n\n\n<p>Refer the full chrome extension plugin at <a href=\"https:\/\/github.com\/prakashm88\/email-summarizer\/\">GitHub<\/a><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/itechgenie.com\/myblog\/2024\/08\/email-or-website-summarization-browser-extension\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Email or Website Summarization Browser Extension&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":4506,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[3,16,9,14],"tags":[110,113,107,105,111,33,53],"class_list":["post-4763","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-features","category-javascript-2","category-snippets","category-web-sites","tag-addons","tag-browser-extension","tag-browser-extensions","tag-chrome","tag-chrome-extension","tag-guide","tag-tips-tricks"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/itechgenie.com\/myblog\/wp-content\/uploads\/sites\/2\/2024\/06\/Browser-extensions.jpg","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2HHtz-1eP","jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/itechgenie.com\/myblog\/wp-json\/wp\/v2\/posts\/4763","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itechgenie.com\/myblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itechgenie.com\/myblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itechgenie.com\/myblog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/itechgenie.com\/myblog\/wp-json\/wp\/v2\/comments?post=4763"}],"version-history":[{"count":1,"href":"https:\/\/itechgenie.com\/myblog\/wp-json\/wp\/v2\/posts\/4763\/revisions"}],"predecessor-version":[{"id":4767,"href":"https:\/\/itechgenie.com\/myblog\/wp-json\/wp\/v2\/posts\/4763\/revisions\/4767"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/itechgenie.com\/myblog\/wp-json\/wp\/v2\/media\/4506"}],"wp:attachment":[{"href":"https:\/\/itechgenie.com\/myblog\/wp-json\/wp\/v2\/media?parent=4763"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itechgenie.com\/myblog\/wp-json\/wp\/v2\/categories?post=4763"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itechgenie.com\/myblog\/wp-json\/wp\/v2\/tags?post=4763"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}