文字转语音工具搭建:初尝后端+前端流程

Published:

念头起源:

这学期教《大学商务英语一》新教材的课程,因为出版社配套的电子资料,比如音频等都是以篇章为单位的录音,有时候在课上讲解段落会不太方便。我自己更喜欢逐段地讲解,有时候让学生跟读,这样的话,如果语音速度、音色等能调整的话,对于课堂上不同的场景会有更好的应用,也就能抓住课堂上学生们宝贵的注意力时间,来完成一些高质量的学习。

那么,最需要的功能就是文字转语音(text-to-speech, tts)。据我的经验来看,TTS 是一个非常常规的功能了,很多的大厂比如微软、科大讯飞、阿里云都开发了自己的工具。其中微软的应该是行业龙头,因为近年来做的 cognitive speech 音色更加丰富,还加入了情绪、风格等,偶尔听到的测试声音让人惊艳。更好的一点,在于这个功能既然已经成熟,调用成熟功能的 API 几乎已经不花什么钱,只有最新的一些测试功能,或者多模态的生成才更贵一些。

但是,作为学生和老师,在使用上仍然有很大的痛点。第一就是能直接使用的产品基本上都要收费,特别是每天超过一定量的字符数之后。这其中的产品包括之前介绍给学生的 Speechify, elevenlabs, 以及 text-to-speech.cn,都是只能用一点点,然后就不让生成及下载了。对于我备课来说,就非常难受,因为我集中时间备课时,也许需要生成很多段的多种音色来测试,就必然会超过阈值,然后就不让用了。这种感觉,就是已经知道这个产品很常规,但是又不得不从二道贩子那里买服务,又不方便,又要被赚差价。所以,就有了要自己做一个文字转语音工具的想法。

功能初步搭建:阿里云 TTS

之后就开始打开 cursor, 准备在目前 class 目录下的门户网页上加一个文字转语音工具的页面。网页初建非常顺利,因为和我以往做 github pages 的流程类似,基本上就是设计交互框、功能、按钮、页面布局这些,外观很快就确定了。

然后,就是选一个 TTS 功能的提供商。微软 Azure 是最先进入我视野的,因为它的音色实在丰富,又是英美国家的原生声音,所以英文发音必然地道且便宜,这是比阿里云大很多的优势。但是,上周末开始探索 Azure 平台的时候,发现一个很大很基础的门槛:虽然每月有很多免费的额度,但是必须要绑定一个外币信用卡(visa或mastercard 信用卡),也是平台怕被盗刷的常见方法,很合理。但是问题是我现在没有visa卡。想想之后再用很多国外的服务,都会用到这个,所以当天就做了点工作,和 claude 聊了一下,马上在中国银行app上办了一张美元visa 卡,直到这周五才收到,这是后话。

所以上周末开始开发网页时,我没办法使用微软的TTS服务,退而求其次,那就是国内的阿里云了。API 测试很顺利,但是问题出在了我搭建网站用的 Github pages 上。我以往还没有在网站上直接调用过其他服务的API, 这次开始使用,一时忘记了 Github 是完全开源的,所以我的全部代码也是公开的,那就出现了硬编码的 API 会直接泄露,会被盗用的风险。虽然我本身并没觉得有很大可能性会被盗用,但是奈何 Github 和 阿里云两方都很谨慎,在我 push 了第一版硬编码了 API 的代码时,两方都给我发了预警消息,并且 阿里云当时就把我账号给封禁了。OK, 怕了怕了,重新想办法。

和 Claude 讨论后,确定了使用 vercel 后端代理的办法。这是我第一次接触到后端的部署,之前的网页都是前端。虽然不太明白具体的原理,但是 Claude 告诉我使用 vercel 后端代理可以把 API 信息保存在云端加密,这样就不会显示在我的 Github 代码上,问题解决。很棒,确实行得通了,经过AI 一步步告诉我怎么注册 vercel 账号,怎么样填写环境变量,怎么样测试。当然,测试过程中出现了多个 bug, 比如 vercel 默认要生成一个 index.html,但是帮我写代码的 cursor 有点固执,总觉得不需要这个东西,然后就来回了很多次,最终它认了,给我生成了一个,测试了几轮可以生成部署页面。之后又是 API 调用失败的错误,基本上也和阿里云TTS 服务的调用方式有关,这个最后是我跑到阿里云TTS的官方文档,去学习了一下基本步骤,之后再让 cursor 学习 debug。这样的过程基本上就跑通了。

之后我把网页推荐给同事,但是当时没挂梯子的情况下,好像还是没有走通。我当时没太在意,以为是网络环境的问题,到今天我才明白,其实根源是 vercel 部署在海外,本质上把在国内的服务绕了一圈出去,又被墙了。

功能升级:微软 Azure

这周五左右,我收到了银行寄来的信用卡,激活起来,也终于拥有了 Azure 的账号。然后就到了周末,开始全力转移后台的 TTS 服务,昨天一天,搭建 API, 更换后台 vercel 的环境变量,测试跑通,很开心周六晚上上线了微软 Azure 的语音服务。

这次功能的升级主要是增加了音色、说话风格的选择,以及语音、语速、语调的调整。初步上线时,调整了最多的方面是页面交互,昨天同事的反馈说希望能够调整语速,可以适应不同场景下的学习,比如慢速,这个想法很好。我就和 claude 交流可行性,然后就学到了 SSML 特征的知识。SSML 是获取 API response 时可选的内容,即设置不同的自定义选项。了解了 SSML 能提供的所有选项之后,我又增加了比较适合的音调和音量。在加入音色、风格的过程中,有很多轮的调试,主要是抓取的顺序,比如先语言,再音色,再说法风格。但是各个语言的音色不同,各个音色所有的说话风格也不同,就需要网站即时抓取填充选项。这里做了很多调试和测试,才最后给出逻辑顺畅的工作流。

接下来优化文本框和生成后播放的功能。我最近的场景就是想用一个随机文本来测试,但是手边没有合适的文本就得现找。我想起来世荣之前做口译评估网站会做一些随机文本的填充,就顺着这个思路,让 AI 生成了10个常见场景的 100字左右的示例文本,用于让用户来测试各个音色。这个功能的效果不错,至少对我测试来说很方便。然后的一个需求是调整音量。音量分为生成前和生成后,分别对应不同的需求。生成前的音量调整,也许是用户所需要的目标声音音量高低,而生成后是在网站上即时播放,可以测试效果,这就需要留有音量余地,避免音量太大或太小。所以我把默认的音量条设置为50%,留了可调整的范围。

TTS工具界面1

TTS工具界面2

这时,网页的基本面貌已经出来了,似乎没有问题了。但是,最大的问题马上来临。

核心诉求:阿里云函数计算-绕开境外托管

根据上周同事测试服务被墙的情况,以及我周六测试新版本 Azure 服务依旧被墙的情况,我最初的推断是微软的 TTS 需要翻墙,所以需要换一个境外的托管(当时我的脑回路真是不灵光)。后来发现,这个判断有两个错误:1. 微软的 TTS 不需要翻墙,根据经验,微软对大陆没有很强的屏蔽,2. 我当时其实已经在用境外的托管了,就是 vercel, 而 vercel 本身就是造成被墙的根源。

我后来才想明白 vercel 是根源这一点,但是在没想明白时,cursor 已经建议我改一个托管的方法,比如用阿里云的函数计算。然后,虽然我还没想到问题的根源是 vercel, 且API 本身是没有被墙的问题的,但是我还是切换到阿里云的托管。只是因为没想明白逻辑,所以在阿里云的后端托管部署时,居然选择了境外日本的服务器,我当时以为这样能绕过所谓的墙。唉。

所以这个错误逻辑浪费了我一天的时间来部署阿里云函数计算,非常挫败。Cursor 昨天晚上 1点钟的缓存已经拉满,自己神经兮兮地给我写了特别多 troubleshooting.md, bug_fixing.md 等等文档,堆满在 aliyun-fc 的文件夹里,但还是在死胡同里转悠。我也熬不住了,关机睡觉。

今天下午重新梳理文件,慢慢意识到阿里云的服务器也许不应该选日本。灵光一现之下,也放弃半死不活的 cursor, 回去跟 claude 聊天。它一语肯定了我的思路,然后我没让它托管,而是一步步告诉我怎么debug, 它也让我截图给他看,然后测试、看报错信息、修正。这样下来,终于更新了阿里云在华东上海的服务器节点,用新的函数计算托管了 azure 的 tts API. 很棒!这个过程也有点曲折,主要是阿里云函数计算的代码 request, CORS 表头这些问题绕了很久。Claude 让我用阿里云后台看实时日志+ 网页前端 F12 用 console 测试+日志的方法,解决了这些问题。不愧是我最好用的 Claude!


终于把这个漫长流程写完了。昨天晚上熬夜的时候,就已经想写这个文档了,测试过程实在是让人头大。如果不写下来,很难复原这两天的工作历程,因为实在是太快了。这次经历也很有趣,给我的 key takeaway 是:

  1. 感受到 AI 的能力是有范围的,而且也会像人一样鬼打墙,思路进入死胡同。这时候,就需要人跳出来,自己用观察、直觉、逻辑学习的方法去尝试新的选项,找突破点。结合以前的经验,有些 AI 一直解决不了的 bug 很可能是缺少人所在的 context, 而且不能有跳出问题本身的能力和魄力。这不是它们的问题,但是却是我们需要强烈意识到的问题。AI 能做到多好,取决于我们的思维维度有多高。

  2. 在 AI 辅助下的学习真的是神速。如果我是一个学习后端部署的新手,也许进入到今天这个步骤我需要好几周的课程,或者一些小练习来堆叠起来。但是今天从 bug 开始学习,被迫去理解部署的逻辑、甚至立刻要从陌生的知识中找出 bug 可能的所在,需要集中观察力和发现规律的能力,这种看似逆向的学习方式,真的非常高效。而且有破除从下而上学习的那种抵触感,因为在从上而下的场景下,实用、跑通是第一位的要求,不会有什么对新知识的情绪。

  3. 又是一个 reinvent the wheels 的工作。也许对于人类社会来说,我做的这个小工具没有太大用处,因为不是新知识、新应用,但是对我来说,这是一个从无到有,从不能到能的过程。在 AI 的辅助下,我基本上完成了从前端到后端的部署,不仅没花什么钱,而且我甚至对这些知识在今天之前都是一无所知。但是,今天之后,我甚至可以总结出来一些使用的经验,甚至还可以告诉我做算法工程师的老公,什么是 vercel, 什么是函数计算。他虽然会做很多代码的顶层设计,但是计算机的工种也有很多,前端、后端这些具体工程并不是广义上的每个“程序员”都会的东西。所以,自己做一个东西,就是自己的体验。重复发明轮子虽然不见得对他人有太大的贡献(甚至对我的学生、同事们还有些贡献,做出了一个免费的好用的工具),但是就当成是一个自我学习的项目。学习,本身就要刻意练习,不丢人噻!

Leave a Comment