在这篇文章中,我们演示了如何使用 亚马逊波莉— 一种将文本转换为逼真语音的领先云服务 — 用于阅读网页内容并在阅读内容时突出显示内容。 向网页添加音频播放可改善页面的可访问性和访问者体验。 音频增强的内容更具影响力和令人难忘,为页面吸引更多流量,并利用访问者的消费能力。 它还提高了发布页面的公司或组织的品牌。 文字转语音技术使这些商业利益成为可能。 我们通过演示如何使用 Amazon Polly 实现这一目标来加速这一过程。
此功能提高了残障访问者的可访问性,并且可以作为您组织的可访问性策略的一部分采用。 同样重要的是,它增强了无障碍访问者的页面体验。 这两个群体都有显着的消费能力,并且在使用音频增强来吸引他们注意力的页面上花费更多。
解决方案概述
PollyReadsThePage
(PRTP)——正如我们所说的解决方案——允许网页发布者将音频控件放到他们的网页上。 当访客选择 播放 在控件上,控件读取页面并突出显示内容。 PRTP 使用 Amazon Polly 的一般功能从文本合成语音。 它调用 Amazon Polly 为每个页面生成两个工件:
- 浏览器可播放格式的音频内容:MP3
- 一个语音标记文件,指示每个文本句子:
- 朗读句子的播放时间
- 句子出现在页面上的位置
当访客选择 播放, 浏览器播放 MP3 文件。 阅读音频时,浏览器检查时间,在标记文件中找到当时要阅读的句子,在页面上定位并突出显示。
PRTP 允许访问者以不同的声音和语言阅读。 每个声音都需要自己的一对文件。 PRTP 使用神经声音。 有关支持的神经语音和语言的列表,请参阅 神经之声. 有关 Amazon Polly 中标准语音和神经语音的完整列表,请参阅 Amazon Polly中的声音.
我们考虑两种类型的网页:静态页面和动态页面。 在一个 静止 页面,内容包含在页面中,并且仅在发布新版本的页面时更改。 作为其 Web 构建过程的一部分,该公司可能会每天或每周更新页面。 对于这种类型的页面,可以在构建时预先生成音频文件并将它们放在 Web 服务器上进行播放。 如下图所示,脚本 PRTP Pre-Gen
调用 Amazon Polly 来生成音频。 它将 HTML 页面本身和一个可选的配置文件作为输入,该文件指定要从页面中提取哪些文本(Text Extract Config
)。 如果提取配置被省略,预生成脚本会明智地选择要从页面正文中提取的文本。 Amazon Polly 以 亚马逊简单存储服务 (Amazon S3) 存储桶; 该脚本将它们复制到您的 Web 服务器。 当访问者播放音频时,浏览器会直接从 Web 服务器下载 MP3。 对于亮点,一个嵌入式图书馆, PRTP.js
, 使用标记文件突出显示正在阅读的文本。
的内容 动态 页面响应访问者交互而变化,因此无法预先生成音频,但必须动态合成。 如下图所示,当访问者播放音频时,页面使用 PRTP.js
在 Amazon Polly 中生成音频,并使用与静态页面相同的方法突出显示合成的音频。 要从浏览器访问 AWS 服务,访问者需要 AWS 身份。 我们展示了如何使用 亚马逊Cognito 身份池,以允许访问者对 Amazon Polly 和 S3 存储桶进行足够的访问以呈现音频。
生成 Mp3 音频和语音标记需要 Polly 服务将相同的输入合成两次。 请参阅 Amazon Polly 定价页面 了解成本影响。 预生成可以节省成本,因为合成是在构建时执行的,而不是在每个访问者交互时按需执行。
这篇文章随附的代码可作为开源存储库在 GitHub上.
为了探索解决方案,我们遵循以下步骤:
- 设置资源,包括预生成构建服务器、S3 存储桶、Web 服务器和 Amazon Cognito 身份。
- 运行静态预生成构建并测试静态页面。
- 测试动态页面。
先决条件
要运行此示例,您需要一个 AWS账户 有权使用 Amazon Polly、Amazon S3、Amazon Cognito 和(用于演示目的) AWS 云9.
预配资源
我们分享一个 AWS CloudFormation 模板在您的帐户中创建一个独立的演示环境,以帮助您跟进帖子。 如果您喜欢在自己的环境中设置 PRTP,请参阅中的说明 README.md.
要使用 CloudFormation 配置演示环境,请首先下载 CloudFormation模板. 然后完成以下步骤:
- 在AWS CloudFormation控制台上,选择 创建堆栈。
- 使用新资源(标准).
- 选择 上传模板文件。
- 选择文件 上传您下载的模板的本地副本。 文件名是
prtp.yml
. - 下一页.
- 输入您选择的堆栈名称。 稍后您再次输入此作为替换 .
- 您可以在 参数 部分。
- 下一页.
- 继续阅读其余部分。
- 阅读并选中 公司能力 部分。
- 创建堆栈.
- 堆栈完成后,找到
BucketName
在堆栈输出中。
我们鼓励您在将堆栈用于生产环境之前与您的安全团队一起审查堆栈。
在 AWS Cloud9 IDE 中设置 Web 服务器和预生成服务器
接下来,在 AWS Cloud9 控制台上,找到环境 PRTPDemoCloud9
由 CloudFormation 堆栈创建。 选择 打开 IDE 打开 AWS Cloud9 环境。 打开终端窗口并运行以下命令,克隆 PRTP 代码,设置预生成依赖项,并启动 Web 服务器进行测试:
针对 ,使用您为 CloudFormation 堆栈指定的名称。 为了 , 指定允许访问 Web 服务器的 IP 地址范围。 要限制对本地计算机上的浏览器的访问,请使用以下命令查找您的 IP 地址 https://whatismyipaddress.com/ 并附加 /32
指定范围。 例如,如果您的 IP 是 10.2.3.4, use 10.2.3.4/32
. 服务器侦听端口 8080。输出中给出了服务器侦听的公共 IP 地址。 例如:
测试静态页面
在浏览器中,导航到 PRTPStaticDefault.html
. (如果您使用的是演示,则 URL 为 http://<cloud9host>:8080/web/PRTPStaticDefault.html
,其中 是您在设置 IDE 时发现的公共 IP 地址。)选择 播放 在顶部的音频控制上。 收听音频并观看精彩片段。 通过改变速度、改变声音、暂停、快进和倒带来探索控制。 以下屏幕截图显示了该页面; 文本“跳过隐藏的段落”被突出显示,因为它当前正在被阅读。
尝试相同的 PRTPStaticConfig.html
和 PRTPStaticCustom.html
. 结果是相似的。 例如,所有三个人都阅读了猫照片的替代文本(“猫的随机图片”)。 这三个人都将 NE、NW、SE 和 SW 读取为完整的单词(“northeast”、“northwest”、“southeast”、“southwest”),利用了 Amazon Polly 词典。
注意音频的主要区别:
PRTPStaticDefault.html
阅读页面正文中的所有文本,包括底部的总结部分,其中包括“您的想法一言以蔽之”、“提交查询”、“最后更新于 1 年 2020 月 XNUMX 日”和“开发团队的问题”。PRTPStaticConfig.html
和PRTPStaticCustom.html
不要阅读这些,因为它们明确排除了语音合成的总结。PRTPStaticCustom.html
读 QB 畅销书 表与其他表不同。 它只读取前三行,并读取每一行的行号。 它为每一行重复列。PRTPStaticCustom.html
使用自定义转换来定制表格的读数。 其他页面使用默认表格呈现。PRTPStaticCustom.html
以比文本其余部分更大的音量朗读“汤姆·布雷迪”。 它使用语音合成标记语言 (SSML)prosody
标签来定制汤姆布拉迪的阅读。 其他页面不会以这种方式定制。PRTPStaticCustom.html
,由于自定义转换,读取 NW、SW、NE、SE 顺序的主要图块; 也就是说,它显示“今日文章”、“今日报价”、“今日照片”、“今日笑话”。 其他页面按照图块以自然 NW、NE、SW、SE 出现的顺序阅读它们在 HTML 中出现的顺序:“今日文章”、“今日照片”、“今日报价”、“今日笑话”天。”
让我们更深入地了解音频是如何生成的,以及页面如何突出显示文本。
静态前置发生器
我们的 GitHub 存储库包括为 PRPTStatic
页面,但如果您想自己生成它们,请从 AWS Cloud9 IDE 中的 bash shell 运行以下命令:
现在让我们看看这些脚本是如何工作的。
默认情况
我们从 gen_default.sh
:
该脚本首先运行 Python 程序 FixHTML.py
制作源 HTML 文件 PRTPStaticDefault.html
格式良好。 它将文件格式正确的版本写入 example/tmp_wff.html
. 这一步至关重要,原因有两个:
- 大多数源 HTML 格式不正确。 此步骤将源 HTML 修复为格式正确。 例如,许多 HTML 页面不会关闭
P
元素。 此步骤将关闭它们。 - 我们跟踪在 HTML 页面中找到文本的位置。 我们需要使用与浏览器相同的文档对象模型 (DOM) 结构来跟踪位置。 例如,浏览器会自动添加一个
TBODY
到TABLE
. Python 程序遵循与浏览器相同的格式良好的修复。
gen_ssml.sh
将格式正确的 HTML 作为输入,对其应用 XML 样式表转换 (XSLT) 转换,然后输出 SSML 文件。 (SSML 是 Amazon Polly 中用于控制如何从文本呈现音频的语言。)在当前示例中,输入是 example/tmp_wff.html
. 输出是 example/tmp.ssml
. 转换的工作是决定从 HTML 中提取哪些文本并将其馈送到 Amazon Polly。 generic.xslt
对于大多数网页来说,这是一个合理的默认 XSLT 转换。 在以下示例代码片段中,它不包括音频控件、HTML 标头以及 HTML 元素,例如 script
和 form
. 它还排除了具有隐藏属性的元素。 它包括通常包含文本的元素,例如 P
, H1
及 SPAN
. 对于这些,它会呈现一个标记,包括元素的完整 XPath 表达式和元素的值。
以下是呈现的 SSML 片段。 这将作为输入提供给 Amazon Polly。 请注意,例如,要在音频中读取文本“跳过隐藏的段落”,我们将其与一个标记相关联,这告诉我们该文本出现在 XPath 表达式给定的页面位置 /html/body[1]/div[2]/ul[1]/li[1]
.
要在 Amazon Polly 中生成音频,我们调用脚本 run_polly.sh
。 它运行 AWS命令行界面 (AWS CLI) 命令 aws polly start-speech-synthesis-task
两次:一次生成 MP3 音频,一次生成标记文件。 因为生成是异步的,所以脚本会进行轮询,直到在指定的 S3 存储桶中找到输出。 当它找到输出时,它会下载到构建服务器并将文件复制到 web/polly
文件夹。 以下是 Web 文件夹的列表:
- PRTPStaticDefault.html
- PRTPStaticConfig.html
- PRTPStaticCustom.html
- PRTP.js
- polly/PRTPStaticDefault/Joanna.mp3、Joanna.marks、Matthew.mp3、Matthew.marks
- polly/PRTPStaticConfig/Joanna.mp3、Joanna.marks、Matthew.mp3、Matthew.marks
- polly/PRTPStaticCustom/Joanna.mp3、Joanna.marks、Matthew.mp3、Matthew.marks
每个页面都有自己的一组特定于语音的 MP3 和标记文件。 这些文件是预先生成的文件。 该页面不需要在运行时调用 Amazon Polly; 这些文件是 Web 构建的一部分。
配置驱动案例
接下来考虑一下 gen_config.sh
:
该脚本与默认情况下的脚本类似,但粗体线表示主要区别。 我们的方法是配置驱动的。 我们通过配置而不是代码指定要提取的内容来定制要从页面中提取的内容。 特别是,我们使用 JSON 文件 transform_config.json
,它指定要包含的内容是具有 ID 的元素 title
, main
, maintable
及 qbtable
. 带有 ID 的元素 wrapup
应排除。 请参阅以下代码:
我们运行 Python 程序 ModGenericXSLT.py
修改 generic.xslt
,在默认情况下使用,以使用我们在 transform_config.json
. 程序将结果写入临时文件(example/tmp.xslt
),它传递给 gen_ssml.sh
作为它的 XSLT 转换。
这是一个低代码选项。 Web 发布者不需要知道如何编写 XSLT。 但他们确实需要了解 HTML 页面的结构及其主要组织元素中使用的 ID。
定制案例
最后,考虑 gen_custom.sh
:
该脚本几乎与默认脚本相同,只是它使用自己的 XSLT——example/custom.xslt
——而不是通用的 XSLT。 以下是 XSLT 的片段:
如果您想详细研究代码,请参阅 GitHub 存储库中的脚本和程序。
浏览器设置和亮点
静态页面包含一个 HTML5 音频控件,该控件将 Amazon Polly 生成并驻留在 Web 服务器上的 MP3 文件作为其音频源:
在加载时,该页面还会加载 Amazon Polly 生成的标记文件。 这发生在 PRTP.js
HTML 页面包含的文件。 以下是标记文件的片段 PRTPStaticDefault
:
在音频播放期间,有一个音频计时器事件处理程序 PRTP.js
检查音频的当前时间,找到要突出显示的文本,找到它在页面上的位置,然后突出显示它。 要突出显示的文本是类型的条目 sentence
在标记文件中。 位置是句子前面的 SSML 类型条目的名称属性中的 XPath 表达式。 例如,如果时间是 18400,根据标记文件,要突出显示的句子是“跳过隐藏段落”,从 18334 开始。位置是时间 17667 的 SSML 条目: /html/body[1]/div[2]/ul[1]/li[1]
.
测试动态页面
页面 PRTPDynamic.html
演示使用默认、配置驱动和自定义音频提取方法的动态音频回读。
默认情况
在浏览器中,导航到 PRTPDynamic.html
. 该页面有一个查询参数, dynOption
,它接受值 default
, config
及 custom
. 它默认为 default
,所以在这种情况下你可以省略它。 该页面有两个包含动态内容的部分:
- 最新文章 – 全天频繁变化
- 希腊哲学家按日期搜索 - 允许访问者按日期搜索希腊哲学家并将结果显示在表格中
在里面创建一些内容 希腊哲学家 如示例所示,输入 -800 到 0 的日期范围。 然后选择 找到最适合您的地方.
现在通过选择播放音频 播放 在音频控制中。
在幕后,页面运行以下代码来渲染和播放音频:
首先它调用函数 buildSSMLFromDefault
in PRTP.js
从 HTML 页面正文中提取大部分文本。 该函数遍历 DOM 树,在常见元素中查找文本,例如 p
, h1
, pre
, span
及 td
. 它会忽略通常不包含要大声朗读的文本的元素中的文本,例如 audio
, option
及 script
. 它构建 SSML 标记以输入到 Amazon Polly。 以下是显示从 philosopher
表:
chooseRenderAudio
功能 PRTP.js
首先为 Amazon Cognito、Amazon S3 和 Amazon Polly 初始化 AWS 开发工具包。 这种初始化只发生一次。 如果 chooseRenderAudio
由于页面内容发生变化而再次调用,则跳过初始化。 请参阅以下代码:
它从 Amazon Polly 生成 MP3 音频。 小型 SSML 输入的生成是同步的,而大型 SSML 输入(超过 3 个字符)的生成是异步的(输出发送到 S6,000 存储桶)。 在同步情况下,我们要求 Amazon Polly 使用预签名 URL 提供 MP3 文件。 当合成输出准备好时,我们设置 src
将音频控件的属性添加到该 URL 并加载控件。 然后我们请求标记文件并以与静态情况相同的方式加载它。 请参阅以下代码:
配置驱动案例
在浏览器中,导航到 PRTPDynamic.html?dynOption=config
. 播放音频。 音频播放与默认情况类似,但有细微差别。 特别是,某些内容被跳过。
在幕后,当使用 config
选项,页面提取内容的方式与默认情况不同。 默认情况下,页面使用 buildSSMLFromDefault
. 在配置驱动的情况下,页面指定它想要包含和排除的部分:
buildSSMLFromConfig
函数,定义在 PRTP.js
, 遍历每个部分中的 DOM 树,其 ID 在下面提供 inclusions
. 它从每个内容中提取内容,并按照指定的顺序将它们组合在一起,形成一个 SSML 文档。 它不包括下指定的部分 exclusions
. 它以相同的方式从每个部分中提取内容 buildSSMLFromDefault
从页面正文中提取内容。
定制案例
在浏览器中,导航到 PRTPDynamic.html?dynOption=custom
. 播放音频。 有三个明显的区别。 让我们注意这些并考虑在幕后运行的自定义代码:
- 它按 NW、SW、NE、SE 顺序读取主要图块。 自定义代码从
maintable
并将它们按 NW、SW、NE、SE 顺序添加到 SSML:
- “汤姆布雷迪”的声音很大。 自定义代码将“Tom Brady”文本放入 SSML
prosody
标签:
- 它只读取四分卫表的前三行。 它读取每一行的列标题。 检查 GitHub 存储库中的代码以了解它是如何实现的。
清理
为避免产生未来费用,请删除 CloudFormation 堆栈。
结论
在这篇博文中,我们展示了一个解决高价值业务问题的技术解决方案:如何使用 Amazon Polly 阅读网页内容并在阅读内容时突出显示内容。 我们使用静态和动态页面展示了这一点。 为了从页面中提取内容,我们使用了 DOM 遍历和 XSLT。 为了便于突出显示,我们使用了 Amazon Polly 中的语音标记功能。
通过访问其了解有关 Amazon Polly 的更多信息 服务页面.
欢迎在评论中提问。
关于作者
迈克·哈维 是 AWS 的解决方案架构师,在构建企业应用程序方面拥有超过 25 年的经验。 迈克是两本书和许多文章的作者。 访问他的亚马逊 作者页面 阅读更多。
维内特·卡恰瓦哈 是 AWS 的解决方案架构师,拥有机器学习方面的专业知识。 他负责帮助客户在 AWS 上构建可扩展、安全且经济高效的工作负载。