如何构建支持 AI 的自然语言合成 Chrome 扩展程序

2025-06-04

如何构建支持 AI 的自然语言合成 Chrome 扩展程序

Transilator 是一款 Chrome 扩展程序,它可以将屏幕上的文本翻译并合成为自然语音。在本教程中,我将向您展示它的开发过程。

要查看代码,请单击此处

以下是该扩展的演示:


这是3 部分系列文章的第 1 部分,介绍如何使用AWS Amplify Predictions为您的应用程序添加机器学习和 AI 功能。

第 1 部分 - 构建翻译器:文本的语言检测、文本翻译和自然语音合成。

第 2 部分 - 图像实体识别 - 构建探索自然的实地指南。

第 3 部分 - 从图像中识别文本 - 将会议徽章转换为联系人。


关于此扩展

Translitor 允许您突出显示屏幕上的文本并以您选择的语言读出它。

特征

  • 语音逼真,悦耳动听
  • 支持的语言输出:阿拉伯语、英语、中文、荷兰语、西班牙语、葡萄牙语、丹麦语、印地语、意大利语、日语、韩语、挪威语、波兰语、俄语、瑞典语、土耳其语
  • 支持的语言输入:荷兰语、葡萄牙语、英语、意大利语、法语、西班牙语

用例

  • 学习一门新语言/单词应该如何发音
  • 聆听新闻文章、文档或博客文章
  • 有视力问题/可访问性相关用例的用户
  • 收听电子邮件
  • 聆听从其他语言翻译成您的语言的内容
  • 在发布博客文章/推文之前进行审核
  • 一般的多任务处理(一边处理一些事情,一边听取其他事情)

入门

本教程主要分为两个部分:

  1. 创建 Amplify 项目并创建 ML 和 AI 服务
  2. 构建 Chrome 扩展程序并连接到步骤 1 中创建的 ML 和 AI 服务

第 1 部分 - 使用 Amplify 创建 ML 和 AI 服务

AWS Amplify是一个用于构建云应用程序的框架,其中包括 CLI(用于创建和管理服务)、客户端库(用于连接到 CLI 创建的 API)、UI 库(用于简化身份验证等操作)以及具有 CI 和 CD 的托管平台。

在本教程中,我们将使用 CLI 创建服务并使用 Amplify 客户端库与这些 API 进行交互。

创建项目。

我们希望使用模块化和现代 JavaScript 来构建我们的扩展程序,因此我们需要使用 Webpack(或类似的工具)。一个完美的入门项目已经存在,它是一个使用 Webpack 的 Chrome 扩展程序样板(点击此处查看)。

克隆此样板然后更改到新目录:

git clone git@github.com:samuelsimoes/chrome-extension-webpack-boilerplate.git

cd chrome-extension-webpack-boilerplate
Enter fullscreen mode Exit fullscreen mode

如果您尚未安装和配置 Amplify CLI,请单击此处观看有关如何执行此操作的视频演示。

接下来,初始化一个新的 Amplify 项目:

$ amplify init
Enter fullscreen mode Exit fullscreen mode

接下来,我们将使用预测类别添加我们需要的服务

文本解释

我们将首先添加文本解释:

$ amplify add predictions

? Please select from of the below mentioned categories:
❯ Interpret

? What would you like to interpret?
❯ Interpret Text

? Provide a friendly name for your resource: (interpretText<XXXX>)

? What kind of interpretation would you like?
❯ All

? Who should have access?
❯ Auth and Guest users
Enter fullscreen mode Exit fullscreen mode

文本翻译

接下来,我们将添加文本翻译:

$ amplify add predictions

? Please select from of the below mentioned categories:
❯ Convert

? What would you like to convert?
❯ Translate text into a different language

? Provide a friendly name for your resource: (translateText<XXXX>)

? What is the source language?
❯ Choose any language, we will change this dynamically later in our app

? What is the target language?
❯ Choose any language, we will change this dynamically later in our app

? Who should have access?
❯ Auth and Guest users
Enter fullscreen mode Exit fullscreen mode

语音合成

接下来,我们要添加一种方法来获取文本翻译并合成语音。

$ amplify add predictions

? Please select from of the below mentioned categories:
❯ Convert

? What would you like to convert?
❯ Generate speech audio from text

? Provide a friendly name for your resource (speechGenerator<XXXX>)

? What is the source language?
❯ Choose any language, we will change this dynamically later in our app

? Select a speaker
❯ Choose any speaker, we will change this dynamically later in our app

? Who should have access?
❯ Auth and Guest users
Enter fullscreen mode Exit fullscreen mode

现在,我们已经创建了所有 API 配置,并且可以通过运行 Amplifypush命令来创建服务:

amplify push
Enter fullscreen mode Exit fullscreen mode

现在服务已经部署完毕,我们可以继续创建 Chrome 扩展程序!

第 2 部分 - 构建扩展。

Chrome 扩展程序概述

Chrome 扩展程序由几个主要文件组成:

点击此处,了解更多关于 Chrome 扩展程序的基础知识。以下文件定义均复制自此文章。

manifest.json - 此文件用于引导您的扩展程序并提供版本控制等元数据。没有它,您的扩展程序就无法运行。

后台脚本(background.js) - 扩展程序的核心和灵魂。您可以在此处创建一个监听器,以便在用户点击图标时触发弹窗。所有“硬”业务逻辑和原生浏览器交互都应尽可能放在此处。

内容脚本(content.js) - 内容脚本可以注入到浏览器的标签页中,并在浏览器会话上下文中访问 DOM。您可以在这里添加新的 DOM 元素、添加额外的监听器等。内容脚本是可选的。

弹出式 UI(popup.js 和 popup.html)- 点击/激活扩展程序时显示的小应用。可以使用任何框架(例如 React、Vue 或原生 JS)构建。我们使用的是原生 JS。

在这个扩展中,我使用弹出式 UI 和内容脚本来控制大部分行为。

在 中popup.js,有一个逻辑允许用户选择他们想要将文本翻译成的语言。在 中content.js,有一个监听器用于监听 中发生的事件,popup.js以便我们可以在两者之间来回发送消息。当用户选择一种语言时,我们会在 中调用以下方法popup.js

// popup.js
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, {language}, function(response) {
    console.log('response: ', response)
  });
});
Enter fullscreen mode Exit fullscreen mode

然后,在中content.js,我们可以接收该消息并通过附加当前页面的监听器来更新本地状态:

// content.js
chrome.runtime.onMessage.addListener(
  function(request, sender) {
    if (!sender) return
    state.setLanguage(request.language)
    return true
})
Enter fullscreen mode Exit fullscreen mode

这两个函数控制着 chrome 扩展 UI 和用户浏览器上运行的实际代码之间的数据流。

替代文本

构建它

接下来我们需要做的是安装 Amplify 库:

npm install aws-amplify
Enter fullscreen mode Exit fullscreen mode

接下来,我们需要添加内容脚本。此样板默认没有这个脚本,所以我们需要手动添加。

touch src/js/content.js
Enter fullscreen mode Exit fullscreen mode

现在,更新manifest.json并添加以下内容以启用新的内容脚本并允许内容脚本在当前活动选项卡上工作:

"permissions": ["activeTab"],
"content_scripts": [{
    "matches": ["*://*/*"],
    "js": ["content.bundle.js"],
    "run_at": "document_end"
  }],
Enter fullscreen mode Exit fullscreen mode

接下来,我们需要更新 webpack 配置来处理content.js脚本:

entry: {
  popup: path.join(__dirname, "src", "js", "popup.js"),
  options: path.join(__dirname, "src", "js", "options.js"),
  background: path.join(__dirname, "src", "js", "background.js"),
  content: path.join(__dirname, "src", "js", "content.js")
},
chromeExtensionBoilerplate: {
  notHotReload: ["content"]
},
Enter fullscreen mode Exit fullscreen mode

在这里,我们将内容脚本排除在热重加载之外,并将新的入口点添加到入口配置中。

popup.js

在popup.js中,我们为弹出窗口中的点击事件设置了监听器。当用户点击某种语言时,我们会向内容脚本发送一条消息,其中包含一个包含所选语言的对象。我们还添加了一个函数,用于为按钮添加一个新类,使背景变暗,并告知用户按钮已被选中。

import "../css/popup.css";

window.addEventListener('DOMContentLoaded', () => {
  var buttons = document.getElementsByClassName("lang-button");
  Array.from(buttons).forEach(function(button) {
    button.addEventListener('click', function(item) {
      Array.from(buttons).forEach(item => item.classList.remove("button-selected"))
      item.target.classList.add("button-selected")
      const language = item.target.dataset.id
      chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
        chrome.tabs.sendMessage(tabs[0].id, {language}, function(response) {
          console.log('response: ', response)
        });
      });
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

内容.js

Content.js 是我们大部分代码所在的文件。这里有一个事件监听器,用于监听 mouseup 事件,以及三个主要函数,当任何文本被选中时,它们会运行:

interpretFromPredictions- 此功能解释所选文本的语言:

function interpretFromPredictions(textToInterpret) {
  Predictions.interpret({
    text: {
      source: {
        text: textToInterpret,
      },
      type: "ALL"
    }
  }).then(result => {
    const language = result.textInterpretation.language
    const translationLangugage = state.getLanguage()
    translate(textToInterpret, language, translationLangugage)
  })
  .catch(err => {
    console.log('error: ', err)
  })
}
Enter fullscreen mode Exit fullscreen mode

translate- 此功能将突出显示的文本翻译成用户选择的语言。

function translate(textToTranslate, language, targetLanguage) {
  Predictions.convert({
    translateText: {
      source: {
        text: textToTranslate,
        language
      },
      targetLanguage
    }
  }).then(result => {
    generateTextToSpeech(targetLanguage, result.text)
  })
    .catch(err => {
      console.log('error translating: ', err)
    })
}
Enter fullscreen mode Exit fullscreen mode

generateTextToSpeech- 翻译完成后,最后一步是将其合成为自然语音。

function generateTextToSpeech(language, textToGenerateSpeech) {
  const voice = voices[language]
  Predictions.convert({
    textToSpeech: {
      source: {
        text: textToGenerateSpeech,
      },
      voiceId: voice
    }
  }).then(result => {
    console.log('result: ', result)
    let AudioContext = window.AudioContext || window.webkitAudioContext;
    console.log({ AudioContext });
    const audioCtx = new AudioContext();
    if (source) {
      source.disconnect()
    }
    source = audioCtx.createBufferSource();
    audioCtx.decodeAudioData(result.audioStream, (buffer) => {
      source.buffer = buffer;
      source.playbackRate.value = 1
      source.connect(audioCtx.destination);
      source.start(0);
    }, (err) => console.log({err}));

    // setResponse(`Generation completed, press play`);
  })
    .catch(err => {
      console.log('error synthesizing speech: ', err)
    })
}
Enter fullscreen mode Exit fullscreen mode

用于语音合成的服务是 Amazon Polly。Amazon Polly 针对不同的翻译语言提供不同的语音(请参阅此处的列表)。

generatedTestToSpeech函数中我们使用语言来确定语音:

// Voice data
const voices = {
  ar: "Zeina",
  zh: "Zhiyu",
  da: "Naja",
  nl: "Lotte",
  en: "Salli",
  ...
}

// Get proper voice in the function:
const voice = voices[language]
Enter fullscreen mode Exit fullscreen mode

为了设置和更新用户选择的语言,我们有一个基本的状态机:

const state = {
  language: 'en',
  getLanguage: function() {
    return this.language
  },
  setLanguage: function(language) {
    this.language = language
  }
}
Enter fullscreen mode Exit fullscreen mode

要查看所有代码content.js,请单击此处

最后,在popup.html中我们呈现按钮来选择不同的语言。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <p class="heading">Choose Language</p>
  <div class="list">
    <h4 class='lang-button' data-id="en">English</h4>
    <h4 class='lang-button' data-id="es">Spanish</h4>
    <h4 class='lang-button' data-id="pt">Portugese</h4>
    <h4 class='lang-button' data-id="zh">Chinese</h4>
    <h4 class='lang-button' data-id="ar">Arabic</h4>
    <h4 class='lang-button' data-id="da">Danish</h4>
    <h4 class='lang-button' data-id="nl">Dutch</h4>
    <h4 class='lang-button' data-id="hi">Hindi</h4>
    <h4 class='lang-button' data-id="it">Italian</h4>
    <h4 class='lang-button' data-id="ja">Japanese</h4>
    <h4 class='lang-button' data-id="ko">Korean</h4>
    <h4 class='lang-button' data-id="no">Norwegian</h4>
    <h4 class='lang-button' data-id="pl">Polish</h4>
    <h4 class='lang-button' data-id="ru">Russian</h4>
    <h4 class='lang-button' data-id="sv">Swedish</h4>
    <h4 class='lang-button' data-id="tr">Turkish</h4>
  </div>
</body>
</html>

Enter fullscreen mode Exit fullscreen mode

接下来,使用popup.css中的 css或在popup.css中为弹出菜单创建自己的样式

构建和部署扩展

现在扩展已经完成,我们可以尝试一下。

要运行 webpack 并构建扩展,请运行以下命令:

npm run build
Enter fullscreen mode Exit fullscreen mode

现在您将看到build文件夹已填充由 webpack 捆绑的扩展代码。

要上传并使用扩展程序:

  1. 访问 chrome://extensions(菜单 -> 设置 -> 扩展)。
  2. 勾选右上角的复选框以启用开发者模式。
  3. 点击“加载解压的扩展...”按钮。
  4. 选择包含解压的扩展的目录。

要查看完整的代码库,请单击此处


我叫Nader Dabit。我是 Amazon Web Services 的开发倡导者,负责AWS AppSyncAWS Amplify等项目。我专注于跨平台和云端应用程序开发。

文章来源:https://dev.to/dabit3/how-to-build-an-ai-enabled-natural-language-synthesization-chrome-extension-1bhl
PREV
推出“盒装会议应用程序”
NEXT
⚡️ 5 分钟教程:使用 AWS Amplify Hosting 部署 NextJS 应用程序