[控场AI]
· 7 分钟阅读· 3,898 字

用Gemini TTS打造免费乌尔都语AI语音:踩过的三个坑

用Gemini TTS打造免费乌尔都语AI语音:踩过的三个坑

巴基斯坦团队为乌尔都语TTS踩坑实录:三个真实Bug与一套低成本免费开放架构。

本文记录了巴基斯坦团队为乌尔都语写作应用 Sitey 构建 TTS 功能时遭遇的工程细节。选声音阶段,他们用包含混合语言句子的真实测试集让真人试听,最终选定 Gemini 的 Aoede 语音。开发过程中依次踩中三个典型坑:样式指令和 emoji 被模型当正文朗读、新版 API 已返回完整 WAV 但旧示例逻辑再套一层文件头导致噪音、WhatsApp 分享后音频尾部被截断。针对成本控制,团队通过 Cloudflare Worker 隔离密钥、多层限额与安卓自带引擎降级实现免费开放。文章最终提炼出四条可直接复用的多语言 TTS 落地原则,核心结论是:TTS 的难点不在于「让它发声」,而在于格式兼容、语言适配与端到端交付质量。

为非英语语言构建文本转语音(TTS)系统,往往比想象中复杂得多。巴基斯坦团队在为乌尔都语写作应用 Sitey 添加语音朗读功能时,就遇到了一连串典型但容易被忽视的工程问题。他们把每个AI回答都做成了可朗读的乌尔都语语音,还能作为语音消息发送到WhatsApp,并在网页端免费开放试用。

让语音「开口说话」很快就能实现,但真正做到可用却花了不少功夫。以下是他们在构建非英语 TTS 时踩过的坑,对任何面向多语言场景做语音功能的开发者都有参考价值。

选声音:用耳朵听,别只看跑分

团队最初试了另一家乌尔都语 TTS 服务,但创始人听过后并不满意。于是他们做了一个小测试:把同样的四句话分别喂给两个 Gemini TTS 模型和平板自带的安卓乌尔都语语音引擎。

这四句话的设计很有讲究:

  • 一句标准乌尔都文字
  • 同一句的罗马化乌尔都语(用英文字母拼写乌尔都语,当地人发短信的主流方式)
  • 一句英文
  • 一句乌尔都语和英语混合的句子,因为这才是人们真实的说话方式

他们把多个 Gemini 语音各自生成的 .wav 文件集中到一个文件夹,由真人逐一试听。整个测试成本不到十美分。最终胜出的是 gemini-3.8-flash-lite-tts 上的 Aoede 语音——它能驾驭全部四种句子,而且能正确读出品牌名「Sitey」。

用Gemini TTS打造免费乌尔都语AI语音

其中混合语句才是真正的试金石。很多语音在纯乌尔都语上表现不错,一旦句子中间冒出英文品牌名就彻底崩溃。这个教训提醒我们:评估 TTS 不能只看官方 benchmark,要用真实用户的说话方式去测,而且必须有人真的去听。

Bug 1:语音把指令本身读了出来

在测试过程中,团队发现了一个尴尬的问题:放在文本里的风格指令(类似「用温暖的语气朗读这段」)被某些语音当成正文内容读了出来。

修复思路很直接——只把要朗读的文字发给模型,样式配置通过 API 参数而非正文传递:

body: JSON.stringify({
  contents: [{ parts: [{ text }] }],
  generationConfig: {
    responseModalities: ['AUDIO'],
    speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName: 'Aoede' } } },
  },
}),

同样的问题在 App 里也出现过,只是换了形式。一张标题为「Short and sweet」的祝福卡片,会把标题也朗读出来;表情符号被读成莫名其妙的音节(蛋糕 🎂 被读成了「chha」)。现在朗读器只接收消息正文,且会先剥离表情符号,并为此写了单元测试。

这个坑揭示了一个共性:模型只会忠实处理你给它的全部文本,任何混入的标签、标题、emoji 都可能被当作内容发声。

Bug 2:播放出来的是一阵噪音

老的示例代码返回的是原始 16-bit PCM 数据,需要开发者自己手动包上一个 44 字节的 WAV 文件头。团队照做了,结果手机播放出来却是一阵刺耳的噪音。

问题根源在于 Gemini 现在已经直接返回完整的 WAV 文件,并在音频数据之后附带了一段 C2PA 内容凭证信息。而团队又在这个本已完整的文件外面套了第二层 WAV 头,导致手机把内层文件头和那段凭证数据当成音频播了出来。

修复方法是先检查前四个字节,判断是否已经是完整 WAV,是的话原样透传:

const bytes = fromBase64(part.inlineData.data)
const isWav = bytes.length > 12 && String.fromCharCode(...bytes.subarray(0, 4)) === 'RIFF'
if (isWav) return { ok: true, audio: part.inlineData.data, usage }
// 否则是原始 PCM:从 mime type 读取采样率,并添加我们自己的文件头。

这个坑非常值得警惕:API 的返回格式会随版本演进,针对旧示例写的「包头」逻辑在新版本下反而成了 bug 的源头。处理二进制音频时,先看字节头再决定如何处理,比盲目套用模板更可靠。

C2PA(Coalition for Content Provenance and Authenticity) 是一项开放技术标准,用于在数字内容(图像、音频、视频)中嵌入可验证的来源与历史记录,帮助识别内容是否由AI生成。Gemini TTS 在返回的 WAV 文件尾部附加 C2PA 元数据块,正是为了标注该音频的AI生成身份。这段尾部数据并非音频采样,但它确实存在于字节流中。当开发者误认为返回的是裸 PCM 并再套一层 WAV 文件头时,播放器就会将原始的 WAV 头、C2PA 数据块一并当作音频波形解析,产生刺耳噪声。这也意味着:即便未来某个 API 版本停止附加 C2PA,先做字节头检测的防御性编程仍然是正确的选择——它比假设返回格式不变要稳健得多。

Bug 3:WhatsApp 把语音消息尾部截断了

用户把生成的 WAV 作为语音消息发到 WhatsApp 后,发现消息末尾被截断了。

团队没有彻底追究到底是 WhatsApp 本身还是那段尾随的 C2PA 数据块导致的——因为他们也不需要搞清楚。现在 App 会在手机端用安卓自带的编码器把音频重新编码成 AAC 格式的 .m4a,并把编码器完整排空到流末尾,再分享出去。设备测试会验证 3 秒和 11.7 秒的语音消息都保持完整时长。在平板上,一条真实时长 4.60 秒的消息,输出后为 4.61 秒。

团队给出的建议一针见血:如果你要把生成的音频分享到聊天应用,务必测试接收端收到的文件的时长,而不只是检查它能不能播放。

AAC(Advanced Audio Coding) 是目前移动端最主流的有损音频压缩格式,也是 WhatsApp、微信等聊天应用语音消息的默认编码。与 WAV 的无压缩 PCM 数据不同,AAC 采用帧式结构,每帧独立编码,解码器需要读取完整的帧才能正确还原音频。「将编码器完整排空(drain)到流末尾」这一步骤至关重要:编码器内部通常有缓冲区,如果在所有帧写出前就关闭流,最后几帧的数据会被丢弃,导致音频被截断。安卓的 MediaCodec API 提供了显式的 BUFFER_FLAG_END_OF_STREAM 信号来触发这一排空过程,跳过这一步是移动端音频编码中最常见的坑之一。

如何在免费的同时不被成本拖垮

语音功能跑在一个 Cloudflare Worker 上,由它持有 Gemini 密钥,App 和网页端都接触不到密钥。几道限制让成本保持可控:

  • 网页端每天提供 5 次语音生成,每次最多 500 字符,并带 Cloudflare Turnstile 人机验证;App 端每天提供 40 次。
  • 对所有 AI 调用设置每日美元上限,另对 Gemini 设置独立的月度上限。
  • 如果 Gemini 繁忙、超限或离线,App 会回退到手机自带的乌尔都语语音。音质差一些,但至少还能说话。
  • 只存储每次调用的次数和成本,从不存储文本或音频。

按撰文时的 Lite TTS 定价,输入每百万 token 收费 0.50 美元,音频每百万 token 收费 6.00 美元。一条简短的乌尔都语播报,成本只有几分钱的零头。这种「密钥隔离 + 多层限额 + 优雅降级」的架构,对任何想免费开放 AI 能力又担心账单失控的小团队都很有借鉴意义。

Cloudflare Turnstile 是 Cloudflare 推出的无感知人机验证方案,用于替代传统的图形验证码(CAPTCHA)。它通过分析浏览器行为、设备指纹等信号在后台判断访问者是否为真实用户,大多数情况下无需用户主动操作。对于开放给匿名用户的 AI 功能,Turnstile 是阻止自动化脚本批量消耗配额的低摩擦方案——相比 Google reCAPTCHA,它对用户隐私的要求更宽松,且与 Cloudflare Worker 的集成几乎零配置。结合每日次数上限,这两层保护共同构成了「允许真实用户免费试用,同时防止滥用导致账单失控」的基础。

如果重新来过,我会这样做

团队最后总结了几条经验,几乎可以直接当作多语言 TTS 的落地清单:

  • 用真实的混合语言句子测试,按用户实际说话方式来测,并且让真人去听。
  • 只把你想让它朗读的文字发给模型,别把样式指令和标签混进去。
  • 在包装或转换音频之前,先看它开头的字节。
  • 在音频经过 WhatsApp 之后再检查其时长,而不是之前。

这些坑看似琐碎,但每一个都指向同一个道理:TTS 的难点很少在于「让它发声」,而在于真实链路上的格式兼容、语言适配和端到端的交付质量。对于英语之外的语言,这些细节往往没有现成答案,只能靠真实测试逐个踩实。

#Gemini TTS#乌尔都语语音#文本转语音#AI语音开发#多语言TTS#WAV音频处理#Cloudflare Worker#WhatsApp语音消息
分享:

相关推荐