写点什么

Whooshkaa + Amazon Polly:结合阅读与收听,拓宽发布渠道

  • 2019 年 11 月 04 日
  • 本文字数:5351 字

    阅读完需:约 18 分钟

Whooshkaa + Amazon Polly:结合阅读与收听,拓宽发布渠道

本文是特邀文章,由 Whooshkaa 的创始人兼 CEO Robert Loewenthal 撰写。


Whooshkaa 总部位于澳大利亚,提供创新的点播式音频播客平台,帮助出版商和广告商赢得听众。我们一直在尝试新的产品和方法,并将二者结合起来,为我们的客户开创全新的解决方案。


Amazon Polly 文本转语音 (TTS) 功能的采用就是极好的例证。很多顶级出版商、体育机构,以及澳大利亚最大的电信公司已在使用 Amazon Polly 来扩充其既有的发行方式。


这些传统信息提供商发现,客户现在不只需要阅读信息,还希望能够收听信息。借助 Amazon Polly TTS,Whooshkaa 让信息提供商能够用 48 种语音和 24 种语言向听众发布信息。


今年早些时候,Amazon Polly 为澳大利亚的主要全国性报纸《The Australian》提供语音版本。订阅者在驾车、锻炼或其他不方便阅读的情况下可以收听 Amazon Polly 朗读的新闻报道、食谱或体育赛事比分。


通过 Amazon Polly,Whooshkaa 的优秀合作伙伴可以方便地选择任何新闻报道,在几秒之内将文本转换为播客内容。我们还提供一些工具,可以合并多个报道,并通过更改口音、音调、速度和音量对声音进行自定义。


Whooshkaa 有庞大的发布网络,也就是说,听众可以选择多种方式来收听内容。最直接的选择是听众常用的播客应用程序。不过,因为 Whooshkaa 与 Facebook 存在独特的合作关系,我们的播客可以通过 Facebook 的音频播放器播放。我们的 Web 播放器可进行自定义,在 Twitter 上也受支持,实际上它可以嵌入任何网站。


我们相信,当这项技术成熟时,出版商能够以任何语言在世界上任何地方提供其新闻报道。新闻报道可以根据听众的偏好和需求进行自定义。


我们还与澳大利亚最大的电信公司 Telstra 和澳大利亚全国橄榄球联赛合作,通过任何联网的智能播音设备发布用户最爱球队的现场比分。用户可以直接向其设备询问当前比分,设备能够立即播报结果。


我们的开发人员 Christian Carlsson 认为,Amazon Polly TTS 的即时性和对各种语言的广泛支持可以为各类出版商带来无限机会。


“通过将功能强大的 Whooshkaa 平台与人工智能集成,我们现在可以在 30 秒内从文字创建完全自动化的播客内容,而这仅仅是开始。”Carlsson 说。


AFL 集成的技术实现

澳大利亚橄榄球联赛 (AFL) 希望粉丝们可以通过与智能播音设备进行语音互动来关注其最爱的球队。为此,Whooshkaa 需要创建一个 RSS 源,每两分钟更新一次,以提供最新结果。下面是我们实现方法的简单概图。



为触发 AFL 的 API 爬网 (其中包含我们需要的数据),我们开发了一个简单的 AWS Lambda 函数来调用 API。该 Whooshkaa API 提取数据、分析数据,然后将数据转换为语音,通过新创建的 RSS 源发布到 Amazon S3。


首先,我们编写 serverless.yml 文件,它负责每两分钟初始化一次请求。这没有什么出奇之处。


Serverless.yml:
createAFLFeeds: handler: api.createAFLFeeds events:   - schedule:       rate: rate(2 minutes)       enabled: ${self:custom.${opt:stage}.ScheduledEvents}
复制代码


这就会触发以下代码:


WhooshkaaAPI.js

JavaScript


createAFLFeeds() {    return new Promise((resolve, reject) => {      this.fetchAFLTeams().then(result => {        for (const team of result) {          this.createAFLFeedByTeamID(team['id']);        }      }, error => {        console.log(error);        reject(error);      });      resolve({message: "success"});    });}
复制代码


接下来,


createAFLFeedByTeamID 方法向我们的终端节点发送 POST 请求,终端节点执行以下操作:


  1. 从 AFL API 获取数据。为使此方法尽可能易读,数据标准化功能已分离到单独的 AFL 程序包。待分析数据由几个不同的条件确定。如果某个球队正在比赛或者在之前 24 小时内进行过比赛,则获取其比赛数据,否则默认获取该球队的最新新闻。

  2. 通过在 Amazon S3 中存储所返回数据的哈希,确保这些数据是新的。

  3. $this->publisher 也是一个抽象类,它包含三个不同存储适配器:本地、Whooshkaa S3 存储桶和 AFL S3 存储桶。我们使用本地适配器处理数据,使用 Whooshkaa S3 存储桶存储相应哈希,将生成的 RSS 源发布到 AFL S3 存储桶。

  4. 通过 Amazon Polly 获取文本并将其转换为音频流。您可以在

  5. makeAudio 方法中看到我们如何处理某些字词,使之按我们的预期发音。例如,体育场馆 MCG 之前被理解成了“McGee”,于是我们改为让 Amazon Polly 逐个字母地读出来。

  6. 创建 RSS 源,将它发布到 AFL 的 S3 存储桶。


AFLController.php:

PHP


public function team(string $id){    if (!$team = Team::findById($id)) {        $this->response->errorNotFound('Invalid team ID.');    }
if ($team->isPlayingOrHasRecentlyPlayed()) { $story = $team->match; } else { $story = $team->news; }
$this->publisher->setTeamId($id); $this->publisher->setStory($story->getStory());
$hash = Hash::make($story, $this->publisher->getRemoteStorageAdapter()); if ($hasBeenUpdated = $hash->hasBeenUpdated()) { $fileName = $this->publisher->getFileName();
$audio = $this->makeAudio($story); $this->publisher->store($fileName, $audio->getContent());
$feed = $this->makeFeed($team, $story); $this->publisher->store('feed.xml', $feed->getContent());
$this->publisher->moveToCloud([$fileName, 'feed.xml']); $this->publisher->cleanUp();
$hash->store(); }
return response([ 'rss' => $this->publisher->getRemoteUrl('feed.xml'), 'updated' => $hasBeenUpdated, ]);}
private function makeAudio($story){ $polly = new Polly; $polly->setPhonemes(['live' => 'laɪve']); $polly->setProsody('AFL', ['rate' => 'fast']); $polly->setSayAs(['MCG' => 'spell-out']);
$text = $story->getStory(); // Trim the text to a maximum of 1500 characters. if (strlen($text) > 1499) { $text = $this->text->setText($text)->trimToWordBoundary(1499); }
try { $audioStream = $polly->fetchAudioStream($text); } catch (\Exception $e) { $this->response->error($e->getMessage(), $e->getStatusCode()); }
return response()->make($audioStream)->header('Content-Type', 'audio/mpeg');}
private function makeFeed(Team $team, $story){ $feed = new Feed($this->publisher->getRemoteURL('feed.xml')); $feed->setTitle($team->getName() . "'s Official Live Feed"); $feed->setDescription('An official live feed from the Australian Football League.'); $feed->setLink('http://www.afl.com.au'); $feed->setOwner('The Australian Football League', 'podcast@afl.com.au'); $feed->setImage($team->getImage()); $feed->appendElements([ 'itunes:subtitle' => "Follow {$team->getName()}'s Live Matches and Latest News", 'itunes:explicit' => 'no', 'language' => 'en-us', 'lastBuildDate' => Carbon::now('UTC')->toRssString(), 'ttl' => 2, 'copyright' => 'The Australian Football League', ]);
$feed->setCategories([ 'Sports & Recreation' => [ 'Professional', ] ]);
$fileName = $this->publisher->getFileName(); $metaData = $this->getMetaData($fileName);
$item = $feed->addItem([ 'title' => $story->getTitle(), 'link' => $story->getArticleURL(), 'pubDate' => Carbon::now('UTC')->toRssString(), 'itunes:duration' => $metaData['playtime_string'], ]); $item->appendDescription($story->getStory()); $item->appendEnclosure($this->publisher->getRemoteUrl($fileName, true), $metaData['filesize'], $metaData['mime_type']); $item->append('itunes:image', null, ['href' => $team->getImage()]); $item->append('guid', $this->publisher->getGuid(), ['isPermaLink' => 'false']);
return response()->make($feed->output())->header('Content-Type', 'text/xml');}
复制代码


《The Australian》“Daily News”的技术实现

The Australian 是 News Corp 旗下的报纸发行商。他们需要将每日 10 大头条新闻以音频形式提供给听众,并且要求头条新闻以播客形式每天更新五次。集成 Amazon Polly 让我们轻松实现了这些要求。下面是我们实现方法的简单概图。



此实现与 AFL 集成非常相似,但有一处不同。这次不生成 RSS 源,而是将播客发布到《The Australian》Whooshkaa 账户上的一栏指定节目。这样,内容几乎能够在 iTunes、Pocket Casts 或其他任何播客播放器中随即播放。


为了完成此实现,我们像之前在 AFL 实现中所做的那样,开发了一个 AWS Lambda 函数,这是因为我们需要在一天中几个特定时间触发“Daily News”终端节点。


Serverless.yml
createDailyNewsStory: handler: api.createDailyNewsStory events:   - schedule:       rate: cron(0 2,6,10,22 * * ? *)       enabled: ${self:custom.${opt:stage}.ScheduledEvents}   - schedule:       rate: cron(30 14 * * ? *)       enabled: ${self:custom.${opt:stage}.ScheduledEvents}
复制代码


WhooshkaaAPI.js

JavaScript


createDailyNewsStory() { const options = {   hostname: this.commonOptions.hostname,   port: this.commonOptions.port,   path: '/news-corp/daily-news',   method: 'POST', }; return new Promise((resolve, reject) => {   this.sendRequest(options).then(result => {     return resolve(result);   }, error => {     console.log(error);     return reject('Could not create "Daily News" story.');   }); });}
复制代码


接下来,


createDailyNewsStory 处理程序调用


createDailyNewsStory 函数,该函数通过我们的 API 触发 dailyNews 终端节点,如下所示。


NewsCorpController.php

PHP


public function dailyNews(){   $show = Show::find(DailyNewsStory::SHOW_ID);   $storyBuilder = new StoryBuilder($show);
$dateTime = Carbon::now('Australia/Sydney')->format('F j (g:00 a)'); $title = $show->title . ' - ' . $dateTime;
$story = new DailyNewsStory; $story->setLimit(10); $story->setTitle($title); $story->setDescription($title);
$episode = $storyBuilder->fetch($story)->publish();
return $this->response->item($episode, new EpisodesTransformer);}
复制代码


DailyNewsStory 扩展


StoryBase 类,该类对


NewsCorpApi 类进行依赖关系注入。来自


DailyNewsStory 的值传递到


NewsCorpApi 类,该类用于获取和标准化数据。


接下来,为获取的所有报道生成音频,以单集形式发布。这是通过


StoryBuilder 类实现的,如下所示。


StoryBuilder.php

PHP


public function publish(){   $title = $this->story->getTitle();   $description = $this->story->getDescription();
if (!$episode = $this->episodes->findByTitleAndDescription($title, $description)) { $audio = $this->makeAudio(); $fileName = $this->storage->putContent($audio->content(), Polly::OUTPUT_FORMAT);
$data = [ 'podcast_id' => $this->show->id, 'title' => $title, 'description' => $description, 'media_file' => $fileName, 'length' => $this->storage->getSize($fileName), ];
$episode = $this->episodes->create($data); }
return $episode;}
public function makeAudio(){ $polly = new Polly;
$audioStream = null; foreach ($this->story->getBody() as $body) { $audioStream .= $polly->makeAudioStream($body); }
return $polly->makeAudioResponse($audioStream);}
复制代码


循环执行


$this->story->getBody()因为它是包含前述所有 10 条报道的数组。这将通过 Amazon Polly 创建持续的音频流。然后音频流以 mp3 文件形式上传到 S3 存储桶,文件名和其余信息保存到数据库并在请求时返回。


我们很多客户生成大量的丰富内容。我们为他们提供由 Amazon Polly 支持的平台,将其内容转换为音频,然后进行发布、分析和商业化。一家新闻出版商计划通过 Whooshkaa 和 Amazon Polly 文本转语音功能提供其食谱库。


Whooshkaa 一直在寻求音频创新方法。我们寻找新的市场和技术为创作者提供最庞大的发布网络。我们发现,传统出版商和 Amazon Polly 能够成功结合。




作者介绍:



Robert Loewenthal 是 Whooshkaa 的创始人兼 CEO。Whooshkaa 总部位于澳大利亚悉尼市,是一家提供全方位音频点播服务的公司,可帮助创作者和品牌生成、托管、共享、跟踪内容并进行内容货币化。


本文转载自 AWS 技术博客。


原文链接:


https://amazonaws-china.com/cn/blogs/china/whooshkaa-and-amazon-polly-combining-eyes-and-ears-to-widen-publishing-horizons/


2019 年 11 月 04 日 08:00463

评论

发布
暂无评论
发现更多内容

书单 | 阿里技术书单,满足你的“大厂情结”!

博文视点Broadview

并发编程概览-从Lock和Synchronized说起

追风少年

Java 并发编程

助力初创企业加速升级,华为云初创扶持计划微光训练营南京站开营仪式成功举办

科技热闻

云钉一体应用创新:音视频如何带来灵活高效的协同体验

阿里云视频云

阿里云 音视频

用C语言实现interface

实力程序员

NCRE考试感想 四级嵌入式(下)

万里无云万里天

嵌入式 6月日更 NCRE 考试经验

如何从Java字节码角度解决问题

叫我阿柒啊

Java 字节码

《漫画算法2》2021全新进阶版来袭!

博文视点Broadview

Java 并发编程—— Semaphore

Antway

6月日更

QQ春节红包活动如何应对10亿级流量?看看大佬的复盘总结

数列科技

活动 系统运维 高并发优化 高可用系统的架构 高可用架构

限流篇,欣赏guava的RateLimiter

下雨喽

Java 设计 限流 架构· Guava

☕️【Java 技术之旅】深入分析JDK动态代理的分析(源码深入)

浩宇天尚

Java JVM 动态代理 6月日更

毕业设计So Easy:基于Java Web学生选课系统

不脱发的程序猿

Java web 毕业设计 学生选课系统

机器学习- 吴恩达Andrew Ng 编程作业技巧 -John 易筋 ARTS 打卡 Week 50

John(易筋)

ARTS 打卡计划

先立个Flag

追风少年

HarmonyOS IoT首著,走进万物互联的世界!

博文视点Broadview

信息流动过程中的聚类问题

Ryan Zheng

架构实战营 - 模块五作业

Sun

如何快速分类整理电脑文件

TroyLiu

文件管理 文件整理 电脑文件 文件分类 快速整理文件

来自Linux老学员的经验分享,新生必看!

学神来啦

Linux 运维 安全 虚拟机

给你一台服务器,你能把你写的代码部署到线上吗?

小傅哥

小傅哥 ssl 云部署搭建 博客配置 安装宝塔

Webpack 系列4:彻底理解 module.issuer 属性

范文杰

webpack 6月日更

关于MySQL库表名大小写问题

Simon

MySQL

工作多年,Linux文件系统还不太了解?

架构精进之路

Linux 文件 6月日更

搞定研发知识管理,你的企业就能跑快一步

华为云开发者社区

知识管理 华为云 devcloud 研发团队 研发知识

Apache APISIX 开源 2 周年!

Apache APISIX 中国社区

开源 后端 网关 架构·

从原理到实践,手把手带你轻松get数仓双集群容灾

华为云开发者社区

容灾 集群 数仓 集群容灾 双集群

Apache Calcite:异质数据源优化查询框架

余生

sql Apache Calcite

支持边云协同终身学习特性,KubeEdge子项目Sedna 0.3.0版本发布!

华为云开发者社区

机器学习 学习 kubeedge Sedna 边云协同

一文讲懂服务的优雅重启和更新

万俊峰Kevin

微服务 web开发 Go 语言 优雅停机

Pandas之:Pandas高级教程以铁达尼号真实数据为例

程序那些事

Python 大数据 数据分析 pandas

Whooshkaa + Amazon Polly:结合阅读与收听,拓宽发布渠道_语言 & 开发_亚马逊云科技 (Amazon Web Services)_InfoQ精选文章