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

Vue 3 实时字幕:用 Deepgram 把语音变成工作流
做实时字幕这件事,很多团队一上来就写成“一个巨大的函数”:拿 API Key、要麦克风权限、开 WebSocket、拼接转写结果、更新 UI。功能能跑,但维护起来会很痛苦——尤其当你把它接进客服、会议纪要、内容审核这些业务流程后,需求会快速膨胀。
这篇文章把 Deepgram 的 Vue 3 实时字幕组件思路重新整理成一套更“可复用、可扩展、可自动化”的实现方式:用 Vue 3 composables(组合式函数) 拆分责任,用 异步控制(async/await、Promise 链、watch) 保证事件发生顺序,然后把**语音转文字(speech-to-text)**变成可触发后续动作的“数据流”。
它也属于我们「人工智能在媒体与内容产业」系列的一部分:实时字幕不只是“可访问性功能”,更是内容生产、分发、审核与用户画像的入口数据。
为什么实时语音转写是“自动化工作流”的入口
实时字幕的价值不止在于“屏幕上出现文字”。真正的价值在于:语音一旦被结构化成文本,就能被搜索、归档、摘要、打标签、触发工单。
在媒体与内容行业里,这个链条很常见:
- 直播/访谈:实时字幕 + 关键词触发“热点片段标记”,生成可剪辑 timecode
- 客服/销售通话:实时转写 + 意图识别,自动创建 CRM 记录、跟进任务
- 会议/创作协作:实时转写 + 自动总结,沉淀知识库并做检索(RAG)
- 内容合规:实时转写 + 敏感词/风险话术检测,提示审核或暂停推流
这里的关键点是:你不是在“做一个组件”,而是在搭一条 实时数据管道。而实时管道最怕两件事:
- 异步顺序失控(key 还没到就开 socket、权限没给就开始录)
- 状态散落在各处(UI、socket、录音器各自维护状态,越改越乱)
Vue 3 的 composables + 明确的异步策略,正好解决这两点。
组合式拆分:把“字幕功能”拆成三块可复用能力
直接把所有逻辑塞进 useDeepgram() 往往是错误起点。更可靠的做法是拆成三类 composable,每个只做一件事:
1)useDeepgramKey:拿临时 token,保护主密钥
把 API Key 放前端是典型事故。更稳妥的方式是:后端用主密钥换一个短时有效的临时 token给前端。
实现要点:
- composable 本身写成
async,内部await fetch() - 返回
ref状态:key与DGStatus - 组件端用
.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 这类“必须先完成再继续”的步骤。
你会得到两个收益:
- 顺序明确(读代码就知道先后)
- 错误更容易集中处理(try/catch)
策略 B:用 Promise 链把多个 composable 的结果放在同一作用域
适用:当你需要“多个异步结果同时可用”才能启动下一步,例如开 WebSocket。
源实现逻辑如下(概念层面):
useDeepgramKey().then(keyRes => ...)- 在内部继续
useMicrophone().then(micRes => ...) - 得到
apiKey与microphone后启动 socket
可维护性建议:
- 给每个
.then(res => ...)的参数取有意义的名字(如keyRes、microphoneRes) - 不要在多个文件里“各自再获取一次 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: booleanlastFinalTranscript: stringpartialTranscript: string(非 final 的中间结果)error: string | null
结构化状态能让 UI 与工作流更清晰:UI 渲染各司其职,工作流只订阅自己关心的字段。
3)“final 才落库”:减少噪声、提升可用性
Deepgram 消息里有 received.is_final。源内容选择 只在 final 时更新字幕,这是正确方向。
如果你要做会议纪要或内容审核,建议策略更明确:
- 中间结果只用于“视觉反馈”(可选)
- final 结果才进入“可检索文本”“摘要输入”“合规模型输入”
4)节流与批处理:让自动化更便宜
实时流如果每来一句就调用一次后端,会把成本和延迟都打爆。更好的做法是:
- 每 10–30 秒批量发送一次 transcript 段落
- 或累计到 N 条 final 句子再触发摘要/标签
在内容生产场景,这个优化往往比“模型选型”更能省钱。
一个落地示例:直播字幕如何连接内容生产与审核
给一个具体的业务串联方式(你可以照着改):
- 前端 Vue 3 播放器旁边显示实时字幕(本篇方案)
watch(DGStatus_socket)收到 final 文本后:- 追加到本地
transcriptBuffer - 同时做一层轻量关键词扫描(如品牌词、竞品词、敏感词)
- 追加到本地
- 每 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;第二,把转写流当成数据资产设计清楚——它会影响你后面所有的自动化工作流。
你打算把实时字幕接到哪个环节:内容生产、内容审核、还是客户沟通?