实时翻译中的大部分延迟都来自等待:等音频流、等下一个词、等整句话。唯一可由你掌控的部分,是延迟模式:更低的延迟,还是更少的修订。
在实时翻译中,听众看到每一行字幕时,往往已经比讲者说出那句话晚了几秒。这段延迟并非来自单一环节,而是沿着一条链路逐段累加,其中大部分都是在等待:等音频流、等下一个词、等整句话说完。弄清每段等待的来源,选择延迟模式就会变得简单,也能让开发者知道该在读取端渲染什么内容、何时渲染。
在看具体数字之前,先有一个参照:人类同声传译通常比讲者慢两到四秒。口译员称这段间隔为「耳声差」。面对动词后置的语言,他们的应对方法不是等到动词出现,而是预判动词,或把句子切成能独立成立的片段。一两秒的延迟并不是软件的缺陷,而是一位优秀的人类译员本来就会有的水平。
VocalStack 上的每一次实时转录都会依次经过相同的环节,且每个环节都要等待前一个环节完成。
读者看到的原语言文本几乎与讲者说话同步。译文会晚一两秒出现,而语音总是排在译文之后,因此语音片段总是最后到达。不过,链路上第一个可见的效果出现得远早于语音:文字本身会移动。
人们在实时转录中最先注意到的,是最新的词在不断移动:一个短语先出现,然后改动,最后定下来。这是草稿环节在起作用,而它的存在理由适用于所有语音识别系统。
识别器判断一个词的写法,依赖的是它之后的内容。「I scream」和「ice cream」在下一个词出现之前听起来完全相同;词尾的 “s” 可能属于这个词,也可能属于下一个词。在词的右侧没有音频之前,它的拼写只是猜测,因此任何实时转录中最新的词,都是最不确定的。草稿不过是把这种猜测提前显示出来,而不是隐藏起来。
每份草稿都会完整替换实时尾部,也就是自上次定稿以来听到的、仍在变化的词。定稿则是最终结果:它永远不会改变,带有词级时间戳,而且定稿按编号连续排列,读者可以据此判断是否漏掉了某一条。
对开发者来说,实时 API 只有一条必须遵守的规则:先渲染所有已定稿的片段,再渲染它们之后的最新草稿;收到定稿时清除草稿。如果把草稿追加而不是替换,文字就会重复并闪烁;定稿会直接吞掉尾部内容。WebSocket 教程 正是围绕这一规则构建阅读器的。
对主持人而言,文字移动是降低延迟的代价。在短语完整说出之前就显示词语,正是实时转录让人感觉「在直播」的原因。但翻译无法采用这种做法:一个词也许能从半句话中猜出来,而译文不能靠猜。
词序是翻译跟不上草稿速度的原因。德语的动词可能位于分句末尾,日语则把动词放在最后。任何译者都需要拿到完整的分句,才能忠实地译出。逐词翻译只会给听众一堆碎片,等分句结束时,他们还得把这些碎片重新读通。早在软件尝试之前,德语就已经让口译员不得不等待动词了。
因此,VocalStack 翻译的是句子,而不是片段。句子翻译默认开启:开启时,服务器会把定稿内容组装成完整句子,并翻译整句。句子仍在进行中时,其译文只是暂定的;句子关闭后,译文才成为最终版本。读取端为每个句子保留一条记录,并随着更新不断替换它。
语音的等待时间更长。只有已关闭的句子才会被朗读,因为一个仍在变化的句子,每次修订都要重新合成一遍。较长的句子会分段朗读,因此第一段可以在其余部分合成的同时开始播放。
关闭句子翻译时,每个定稿都会获得各自的译文帧。这条路径无需等待,但整句的阅读效果明显更好。
以上所有等待时间,都从音频抵达 VocalStack 的那一刻开始计算。对许多直播而言,音频在到达之前就已经晚了。
当来源是流媒体而非麦克风时,音频在转录开始之前就已经落后了。它落后于实时边缘,也就是该流已发布的最新时刻。
普通的 HTTP 音频流(大多数网络电台所采用的形式)通常比实时落后一到三秒。服务器会保留一个突发缓冲区:保存最近几秒的音频,并一次性发送出去,好让新听众的播放器不会卡顿。所有听众,包括 VocalStack 在内,都会从这个位置开始接收。HLS 更慢:其播放列表会让客户端从落后实时边缘三个分段的位置开始播放,实际延迟取决于分段长度,从几秒到半分钟不等。标准 DASH 通常与 HLS 处于同一范围,只有其低延迟变体才会明显更低。电台宣传的「直播」流,其「实时」程度往往只像信件上写的「及时」一样名不副实。
这些数字只是近似值,而且它们属于音频流本身,而非转录过程:VocalStack 这一侧的任何设置都无法把这些延迟追回。如果这些秒数对某场活动很重要,请从麦克风或编码器输入音频,而不要使用公开的音频流。流媒体的延迟在 VocalStack 听到第一个词之前就已经固定了;真正可以调节的,是延迟模式。
延迟模式只做一件事:在延迟与准确率之间取得平衡。该设置位于创建实时转录时的 Advanced 下,运行期间则在 Speed 标签页中。在那里,标签显示 AUTO、SPEED 或 ACCURACY(Fast 对应 SPEED)。通过 API,session.update 可以在流传输过程中更改该模式。
两者的取舍与名称所示一致。Fast 让文字更快输出,但会修订更多内容;Accuracy 稍慢一些,修订也更少。坐在台下阅读译文字幕的观众很少会注意到多出的一秒,但会察觉到文字不断变化。因此,只要延迟图保持平稳,Accuracy 往往是更友好的选择。Auto 会表明自己的操作:为了缩小差距而加速的行,会在主持人的转录中带有 FAST MODE 徽章,并附注说明该处的准确率可能更低。
无论选择哪种模式,转录都必须在第一个词之前准备就绪,而这一准备过程是整条链路中唯一只付出一次的延迟。
在某些套餐下,实时转录需要几秒钟才能启动,具体时长取决于套餐:价格页面 中的 Start-up speed 一行显示,从按量付费最长 15 秒的冷启动,到 Enterprise 的始终预热。
通过 API,等待过程会表现为会话启动期间的 session.loading 帧,随后是 session.ready;客户端只有在收到 session.ready 之后才会发送音频。在此期间打开链接的听众会看到「Live. The first line appears in a moment.」一旦转录开始运行,这段延迟便已过去,剩下的唯一问题,就是你还要承担多少剩余延迟。
实时转录运行期间,主持人的 Speed 标签页会显示上述所有延迟累加的结果:讲者与文字之间的当前间隔,旁边是模式标签;还有一张图表,展示整个录制过程中的间隔变化,并标出平均值和峰值。在转录内容本身中,一行字幕若晚于听众收到的时间,会带有一个徽章,显示从说话到抵达之间的秒数。
如果图表保持在低位且平稳,说明所选模式与音频相符。如果图表持续攀升,说明流水线正在落后。在 Accuracy 模式下出现这种情况时,可以切换到 Auto,以牺牲一些准确率换取速度,直到间隔缩小。
开发者得到的则是一个单一数字。实时会话结束时,session.done 会携带 stats.realtimeFactor,即转录的音频时长除以转录所花费的时间。需要注意一个约定:在语音识别文献中,实时因子通常指其倒数,即处理时间除以音频时长,数值越低越好。VocalStack 的算法则相反,因此这里数值越高越好:正常的实时会话接近 1,低于 1 则意味着音频到达的速度超过了流水线的转录速度。
这些秒数都不神秘。有的属于音频流,有的属于等待后续词语的词,有的属于翻译所需的整句,其余的则属于你所选的延迟模式。API 参考 中有逐帧的详细说明,首页 上的演示则展示了整条链路的运行过程。