You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在UI中无重复拼接Twilio实时通话转录文本

解决Twilio增量通话转录的重复内容显示问题

Twilio流式语音识别返回的增量转录会包含重复前缀,核心原因是每次返回的是当前已识别的完整临时结果,而非纯新增片段。要实现无重复的UI显示,关键是区分「临时增量」和「最终确认」的转录内容,以下是具体方案:

核心思路

  1. 维护两个状态变量:
    • finalTranscript:存储已确认的完整语句(对应isFinal: true的识别结果)
    • partialTranscript:存储当前正在识别的临时增量内容
  2. 利用Twilio返回结果中的isFinal标记:
    • 当isFinal为true时,说明这段转录已确认,将其合并到finalTranscript并清空临时内容
    • 当isFinal为false时,仅更新临时增量内容,用于实时显示用户正在说的内容

最佳实践

  • 分开显示已确认文本和临时文本(比如已确认文本用常规样式,临时文本用浅灰色),提升用户体验
  • 通过状态变量跟踪内容,避免直接拼接所有返回的转录文本,减少不必要的字符串操作
  • 每轮对话确认结束(isFinal: true)时,可添加换行或分隔符,让对话结构更清晰

代码示例

修改你的WebSocket回调代码,加入状态管理和去重逻辑:

// 初始化状态变量
let finalTranscript = '';
let partialTranscript = '';

ws.on("message", function incoming(message) {
  const msg = JSON.parse(message);
  switch (msg.event) {
    case "connected":
      console.log(`A new call has connected.`);
      break;
    case "start":
      recognizeStream = client
        .streamingRecognize(request)
        .on("error", console.error)
        .on("data", data => {
          // 遍历所有识别结果(处理多备选情况)
          data.results.forEach(result => {
            const transcript = result.alternatives[0].transcript;
            if (result.isFinal) {
              // 确认的转录:合并到最终文本,清空临时内容
              finalTranscript += transcript + ' ';
              partialTranscript = '';
            } else {
              // 临时增量:更新临时文本
              partialTranscript = transcript;
            }
            // 更新UI:显示最终文本 + 临时文本
            updateTranscriptUI(finalTranscript + partialTranscript);
          });
        });
      break;
    case "media":
      console.log(`Receiving Audio...`);
      break;
    case "stop":
      console.log(`Call Has Ended`);
      break;
  }
});

// 示例UI更新函数
function updateTranscriptUI(text) {
  document.getElementById('transcript-display').textContent = text.trim();
}

额外优化

如果遇到isFinal标记延迟的场景,可通过字符串比对提取新增片段:

// 保存上一次的临时转录内容
let lastPartial = '';
// 在非isFinal的分支里:
const newPartial = transcript;
// 提取新增部分(假设新内容是旧内容的超集)
const addedText = newPartial.slice(lastPartial.length);
partialTranscript = newPartial;
lastPartial = newPartial;
// 可单独处理新增文本,比如追加到UI而非替换整个内容

内容的提问来源于stack exchange,提问作者amal m reji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 11:42:50