Vue 3 实时字幕:用 Deepgram 把语音变成工作流

人工智能在媒体与内容产业By 3L3C

用 Vue 3 composables + Deepgram WebSocket 做实时字幕,并把语音转写接入内容生产、审核与自动化工作流。

Vue3DeepgramSpeech-to-TextWebSocketWorkflow AutomationLive Streaming
Share:

Featured image for Vue 3 实时字幕:用 Deepgram 把语音变成工作流

Vue 3 实时字幕:用 Deepgram 把语音变成工作流

做实时字幕这件事,很多团队一上来就写成“一个巨大的函数”:拿 API Key、要麦克风权限、开 WebSocket、拼接转写结果、更新 UI。功能能跑,但维护起来会很痛苦——尤其当你把它接进客服、会议纪要、内容审核这些业务流程后,需求会快速膨胀。

这篇文章把 Deepgram 的 Vue 3 实时字幕组件思路重新整理成一套更“可复用、可扩展、可自动化”的实现方式:用 Vue 3 composables(组合式函数) 拆分责任,用 异步控制(async/await、Promise 链、watch) 保证事件发生顺序,然后把**语音转文字(speech-to-text)**变成可触发后续动作的“数据流”。

它也属于我们「人工智能在媒体与内容产业」系列的一部分:实时字幕不只是“可访问性功能”,更是内容生产、分发、审核与用户画像的入口数据。

为什么实时语音转写是“自动化工作流”的入口

实时字幕的价值不止在于“屏幕上出现文字”。真正的价值在于:语音一旦被结构化成文本,就能被搜索、归档、摘要、打标签、触发工单

在媒体与内容行业里,这个链条很常见:

  • 直播/访谈:实时字幕 + 关键词触发“热点片段标记”,生成可剪辑 timecode
  • 客服/销售通话:实时转写 + 意图识别,自动创建 CRM 记录、跟进任务
  • 会议/创作协作:实时转写 + 自动总结,沉淀知识库并做检索(RAG)
  • 内容合规:实时转写 + 敏感词/风险话术检测,提示审核或暂停推流

这里的关键点是:你不是在“做一个组件”,而是在搭一条 实时数据管道。而实时管道最怕两件事:

  1. 异步顺序失控(key 还没到就开 socket、权限没给就开始录)
  2. 状态散落在各处(UI、socket、录音器各自维护状态,越改越乱)

Vue 3 的 composables + 明确的异步策略,正好解决这两点。

组合式拆分:把“字幕功能”拆成三块可复用能力

直接把所有逻辑塞进 useDeepgram() 往往是错误起点。更可靠的做法是拆成三类 composable,每个只做一件事:

1)useDeepgramKey:拿临时 token,保护主密钥

把 API Key 放前端是典型事故。更稳妥的方式是:后端用主密钥换一个短时有效的临时 token给前端。

实现要点:

  • composable 本身写成 async,内部 await fetch()
  • 返回 ref 状态:keyDGStatus
  • 组件端用 .then()await 等待 Promise 完成后再继续

这种模式的好处是:同一套 token 获取逻辑可以被字幕、语音助手、录音转写、语音质检等多个模块复用。

可提炼的一句话:把“认证”做成一个可独立测试、可复用的 composable,是所有语音能力上墙之前的第一步。

2)useMicrophone:只负责拿到可录音的 MediaRecorder

浏览器麦克风权限是异步的,用户可能拒绝、也可能拖很久才点允许。

这个 composable 的职责应该很纯粹:

  • navigator.mediaDevices.getUserMedia({ audio: true })
  • 创建并返回 MediaRecorder

当它足够纯粹,你就可以在别的场景复用:例如“按住说话”的语音助手输入、语音笔记、UGC 投稿录音等。

3)useDeepgramSocket:只负责把音频推到 WebSocket 并回传转写

这个 composable 依赖前两个 composable 的“结果”,也就是典型的异步依赖链

  • 没 token,socket 不该开
  • 没 microphone,音频没法送

源内容里给了一个实用策略:用 .then() 把 Promise 串起来,让两个返回值出现在同一个作用域里,便于调用 openDeepgramSocket(apiKey, microphone)

我个人的立场是:早期 demo 用 .then() 链没问题,但生产代码更建议统一改成 async/await 并加上取消/清理机制(后面会讲)。

异步顺序的三种写法:什么时候用哪种?

下面这三种策略,是把实时语音转写做稳定的关键。

策略 A:在 composable 内用 async/await,让“获取资源”可控

适用:拿 token、请求权限、加载 SDK 这类“必须先完成再继续”的步骤。

你会得到两个收益:

  1. 顺序明确(读代码就知道先后)
  2. 错误更容易集中处理(try/catch)

策略 B:用 Promise 链把多个 composable 的结果放在同一作用域

适用:当你需要“多个异步结果同时可用”才能启动下一步,例如开 WebSocket。

源实现逻辑如下(概念层面):

  1. useDeepgramKey().then(keyRes => ...)
  2. 在内部继续 useMicrophone().then(micRes => ...)
  3. 得到 apiKeymicrophone 后启动 socket

可维护性建议:

  • 给每个 .then(res => ...) 的参数取有意义的名字(如 keyResmicrophoneRes
  • 不要在多个文件里“各自再获取一次 token”,避免竞态与重复请求

策略 C:用 watch 把“实时数据”推到 UI 或业务副作用

实时字幕的核心不是“拿到一次结果”,而是 不断收到消息并刷新界面watch 很适合把 composable 的实时 ref 变化,映射到组件状态:

  • composable 内维护 DGStatus_socket(实时转写文本)
  • 组件里 watch(DGStatus_socket, () => deepgramStatus.value = DGStatus_socket.value)

这也是把“AI 语音能力”接进自动化工作流的关键入口:你可以在 watch 里触发很多动作,比如:

  • 命中关键词就 emit('highlight', { text, ts })
  • 检测到“退款/投诉/法律风险”就弹出提示并创建工单
  • 每 30 秒把累积转写发送到后端做摘要

记住:**字幕是 UI 功能;转写流是业务资产。**别把它们绑死。

生产级细节:把字幕从“能跑”变成“可上线”

源代码演示了核心路径,但如果你要把它用在媒体内容生产或企业工作流里,我建议至少补上这些点。

1)清理与生命周期:别让麦克风和 socket 泄漏

在 Vue 组件卸载、路由切换、用户关闭字幕时,你需要:

  • socket.close()
  • microphone.stop()
  • 移除 dataavailable 监听器

做法:在 composable 里暴露 stop() 方法,组件在 onBeforeUnmount() 或按钮事件里调用。

2)更稳的状态模型:把状态从字符串升级为结构化对象

DGStatus_socket 直接塞字幕文本很好理解,但业务会很快要求:

  • connected: boolean
  • lastFinalTranscript: string
  • partialTranscript: string(非 final 的中间结果)
  • error: string | null

结构化状态能让 UI 与工作流更清晰:UI 渲染各司其职,工作流只订阅自己关心的字段。

3)“final 才落库”:减少噪声、提升可用性

Deepgram 消息里有 received.is_final。源内容选择 只在 final 时更新字幕,这是正确方向。

如果你要做会议纪要或内容审核,建议策略更明确:

  • 中间结果只用于“视觉反馈”(可选)
  • final 结果才进入“可检索文本”“摘要输入”“合规模型输入”

4)节流与批处理:让自动化更便宜

实时流如果每来一句就调用一次后端,会把成本和延迟都打爆。更好的做法是:

  • 每 10–30 秒批量发送一次 transcript 段落
  • 或累计到 N 条 final 句子再触发摘要/标签

在内容生产场景,这个优化往往比“模型选型”更能省钱。

一个落地示例:直播字幕如何连接内容生产与审核

给一个具体的业务串联方式(你可以照着改):

  1. 前端 Vue 3 播放器旁边显示实时字幕(本篇方案)
  2. watch(DGStatus_socket) 收到 final 文本后:
    • 追加到本地 transcriptBuffer
    • 同时做一层轻量关键词扫描(如品牌词、竞品词、敏感词)
  3. 每 20 秒把 transcriptBuffer 发到后端:
    • 生成直播摘要片段(用于内容推荐、回放目录)
    • 做风险话术检测(用于内容审核)
    • 写入可搜索索引(用于编辑快速定位片段)

这条链路很符合「人工智能在媒体与内容产业」的主线:语音转写把“声音内容”变成可计算的文本资产,后面才有智能推荐、智能创作辅助与审核自动化。

常见问题(团队里一定会问的那种)

Q1:为什么要用临时 token?直接把 API Key 放前端不行吗?

不行。前端密钥几乎等于公开。临时 token 的价值是:即使被截获也很快失效,并且你可以在后端做调用额度控制、来源限制与审计。

Q2:为什么用 watch,不用 computed?

computed 适合纯派生值;实时字幕往往要触发副作用(写 DOM、写缓存、触发工作流),watch 更合适。

Q3:可以把 .then() 链改成 async/await 吗?

可以,而且我建议改。async/await 更容易加 try/catch、更容易把“启动”和“停止”写成一组对称的 API。

下一步:把字幕变成“可触发动作”的语音工作流

实时字幕只是第一层。真正能带来线索(LEADS)和效率提升的,是把转写文本接到自动化链路:CRM 记录、知识库、内容标注、审核规则、甚至是语音助手的意图路由。

如果你正在做直播、播客、在线课程、客服质检或会议生产系统,我建议你现在就做两件事:第一,把语音转写接进你的前端 UI;第二,把转写流当成数据资产设计清楚——它会影响你后面所有的自动化工作流。

你打算把实时字幕接到哪个环节:内容生产、内容审核、还是客户沟通?

🇨🇳 Vue 3 实时字幕:用 Deepgram 把语音变成工作流 - China | 3L3C