☰
腾讯云语音识别实现会议录音转文字小工具
2026/10/20 11:46:00 网站建设 项目流程

如果你也经历过这种场景,一定懂我为什么突然想做这个“会议小帮手”:一场一小时的项目讨论,结束之后大家各凭记忆行动,有人记住了下周交付,有人把负责人听岔了,等到对需求的时候才发现每个人手里的版本都不一样。我以前试过边开会边手打纪要,结果完全跟不上现场节奏,一边是讨论已经跑到第三个话题,一边是手指还停在上上句话里。后来我干脆放弃手工记录,把精力转向语音识别,用腾讯云 AI 语音识别做了一个自动转写会议录音的小工具。经过几个晚上的折腾,这个工具已经能稳定把录音转成带时间戳的文本,再经过一道简单的后处理,就能变成一份勉强能发给同事的会议纪要。

这篇文章就把我从选型、接口调用、代码实现到踩坑的完整过程记录下来。如果你是开发者,想快速用云服务实现语音转文字,可以参考里面的接口调用和后处理思路;如果你不是技术人员,只是受够了手动整理会议纪要,也可以直接照抄思路,找个会写脚本的同事帮你搭一个。

1. 先想清楚:会议纪要为什么需要一台“语音转写机”

1.1 会议的三种痛点和语音识别的解法

首先要承认,不是所有会议都需要转写。五分钟同步一下进度的小会,转不转意义不大。真正有价值的是那种信息密度高、参与人数多、时间又长的会议。这类会议有三个特别典型的问题。

第一是记录跟不上。口头讨论的语速在每分钟两百字左右,正常人手打每分钟也就四五十字,差距摆在那里。第二是人脑天然会遗漏细节,尤其是打断频繁的会议,上一段还没落地,下一段已经开始,等回到刚才的话题时,很多细节已经被冲掉了。第三是事后核对没有依据。明明会上说了,会后有人说“没听到”,这时候拿不出文本就只能靠争辩。

语音转写解决的正是这三件事。录音交给云端识别,转录出来的文本不管多少字都不嫌累,等于给会议装了一台永恒完整的记录仪。文本带时间戳,想确认某句话出现在第多少分钟,拖一下播放器就能找到上下文,谁说了什么、前后怎么衔接,一目了然。

1.2 为什么选腾讯云 ASR,而不是自建模型或离线工具

聊到语音识别方案时,大家通常有三个方向:自己训练模型、用本地开源工具、用云服务。我直接选了云服务里最省事的一条路。

自建模型确实能做得非常“私有化”,数据不出内网,但代价也同样清晰:需要准备带标注的语料、一台还过得去的训练机器,以及一个能持续优化模型的团队。普通会议单位如果没有这样的条件,第一步就卡住了。

本地开源工具我也试过,胜在免费、不用联网,但配置门槛不低。轻量模型识别率一般,上了大模型对 CPU 和内存又不友好,而且会议录音里出现人名、产品名、口头语时,开箱效果很难让人满意。更难受的是,会议是突发需求,不是每天都在处理,没必要为它长期养一套本地识别环境。

所以最终落到云服务上。腾讯云 AI 语音识别对我来说最大的优点是接口简单、模型已经训练得很成熟,对中文口语、日常表述的容错度不错,而且支持直接传录音文件,不用自己去管分帧、解码、流式推送这些底层细节。对于“把会议录音变成文字”这个目标来说,这是性价比最高的路径。

1.3 整体方案架构

确定了方向以后,整个工具的结构就很清晰了,大致分成四层。

第一层是音频采集,我用手机自带的录音功能,或者电脑的会议录制功能,把整场会议存成 mp3、m4a 或者 wav。完事后丢到一个临时目录里。第二层是音频预处理,统一口径,把文件转成腾讯云接口最友好的格式,也就是 16kHz 采样率、单声道、wav 编码。第三层是云端识别,通过腾讯云 ASR 的录音文件识别接口,提交音频文件 URL,然后轮询任务状态,拿到转写结果。第四层是后处理,把转写文本里明显的口语词清理掉,利用时间戳分段落、提取高频关键词,最后生成一份结构化文本。

这样一来,整个流水线就像一条组装流水线,每一个环节都有明确输入输出,出了问题也知道去哪排查。

2. 接口选型:录音文件识别还是实时语音识别

2.1 两个接口的本质区别

腾讯云语音识别的接口名很直白,容易让人迷茫的是到底该用哪个。我在这上面花了点时间,后来理清了。它主要分实时语音识别和录音文件识别两大方向。

实时语音识别的特点是流式处理。麦克风录音的同时,音频数据被切成小块不断送过去,识别文本也在同步输出。典型场景是机器人对话、语音助手、实时字幕,要求延迟尽量低,用户能接受边说边出词。调用方式通常是 WebSocket 或者带回调的接口,工程上要多处理一些状态同步。

录音文件识别则是“离线任务”模式。你把一个完整的音频文件丢过去,服务端异步开始识别,过一段时间后再去查询结果。它不在乎是几分钟还是几小时的音频,只在乎文件格式、大小和时长限制是否满足。因为不需要实时响应,它能把整段音频跑得更充分,稳定性也更高。会议转写显然属于这一类,不是要现场出字幕,而是要事后拿到完整文本。

2.2 会议场景的正确选择

当初我差点被实时接口吸引,心想实时出字幕多酷。但仔细一想,日常会议的录音通常是先录下来,开完会再整理,根本没有“边开边转”的强需求。即使有,实时识别如果要稳定跑完一小时,还要应对多人同时说话、网络抖动、麦克风远场等问题,实现的复杂度会远超预期。所以最后选了录音文件识别接口,把整段录音一次性交出去,等它处理完再拉结果。

录音文件识别的调用方式也很适合脚本化。不用维持长连接,就是一个创建任务请求,加一个轮询状态请求。如果音频在腾讯云对象存储上,或者能被公网访问到,直接传 URL 就能跑通。这样代码要维护的路径就少很多,没有网络断连后重连的麻烦。

2.3 开通服务与准备密钥

在写代码之前,需要先做三件事。注册腾讯云账号并完成实名认证,这个不用多讲。然后在控制台找到语音识别服务,开通对应的能力。最后在访问管理里创建一个 API 密钥,拿到 SecretId 和 SecretKey,这两个值就是后面代码里用于身份验证的凭证。

这里提醒一下,SecretKey 是敏感信息,千万别硬编码进代码后传到什么公开仓库里。我自己用了一个临时环境变量来存,脚本内部通过 os.environ 读取,这样就算文件偶尔发给别人,也不至于泄露密钥。密钥也能在控制台随时禁用或重建,丢了不用太慌,但尽量不要让这种事发生。

3. 核心实现:把录音变成带时间戳的文本

3.1 环境准备

我的运行环境是 Python 3.9。依赖方面,主要安装腾讯云官方的 Python SDK,命令行装一下即可:

pip install tencentcloud-sdk-python

这个 SDK 会把语音识别的客户端和请求模型都带进来,其它标准库基本够用。另外还需要准备一个命令行工具:ffmpeg。它负责格式转换,在 Mac 上可以用 brew 安装,在 Windows 上可以下载静态编译版本,把二进制加入 PATH。

3.2 音频先用 ffmpeg 统一格式

在我手机录音里,微信语音、手机备忘录导出的文件格式五花八门,有 m4a、mp3、amr。直接用这些格式去调接口,不是不行,但总有兼容性风险。索性我先统一转成 wav。

ffmpeg -y -i input.m4a -ar 16000 -ac 1 -f wav output.wav

这条命令的作用有几个:-ar 16000把采样率统一成 16kHz,符合识别模型的最佳输入;-ac 1强制转成单声道,避免双声道带来的数据量翻倍;-f wav指定输出格式。如果源文件很长,或者想降低传输体积,也可以转成 mp3,但 wav 在兼容性上更让我放心。

转换完成后,把文件放到一个临时目录里,接下来就是要让云端能读到它。

3.3 怎么把文件交给云端:URL 方式的取舍

录音文件识别接口支持两种方式传文件:一种是把音频内容 Base64 编码后放在请求体里,另一种是传一个公网可访问的 URL。Base64 方式对文件大小限制较严,适合几十秒钟到几分钟的短音频。会议录音动辄几十分钟到几小时,明显不适合硬塞在请求体里。

所以我采用了 URL 方式。为了简单,我临时把 wav 文件传到自己的对象存储桶里,生成一个带鉴权签名的临时链接,然后把链接传给接口。识别完成后再把临时文件删除。如果你手头没有对象存储,也可以用一台带公网的服务器做静态文件服务。总之核心原则是:识别服务需要有办法自己去下载这份录音。

3.4 提交识别任务与轮询结果

配置好密钥、准备好音频 URL 后,就进入正式的接口调用环节。创建任务的关键代码如下:

import os import json import time from tencentcloud.common import credential from tencentcloud.common.profile.client_profile import ClientProfile from tencentcloud.common.profile.http_profile import HttpProfile from tencentcloud.asr.v20190614 import asr_client, models SECRET_ID = os.environ.get("TENCENTCLOUD_SECRET_ID") SECRET_KEY = os.environ.get("TENCENTCLOUD_SECRET_KEY") cred = credential.Credential(SECRET_ID, SECRET_KEY) http_profile = HttpProfile() http_profile.endpoint = "asr.tencentcloudapi.com" client_profile = ClientProfile() client_profile.httpProfile = http_profile client = asr_client.AsrClient(cred, "ap-guangzhou", client_profile) def create_task(audio_url): req = models.CreateRecTaskRequest() req.EngineModelType = "16k_zh" req.ChannelNum = 1 req.ResTextFormat = 2 req.SourceType = 1 req.Url = audio_url req.FilterModal = 1 req.ConvertNumMode = 1 resp = client.CreateRecTask(req) return resp.Data.TaskId def wait_for_result(task_id, timeout=1800): start = time.time() while time.time() - start < timeout: req = models.DescribeTaskStatusRequest() req.TaskId = task_id resp = client.DescribeTaskStatus(req) status = resp.Data.Status if status == 1: return resp.Data if status == 2: raise RuntimeError("识别任务失败") time.sleep(3) raise TimeoutError("等待识别结果超时")

这里解释几个参数。

EngineModelType = "16k_zh"是最常用的中文普通话引擎,适配 16kHz 采样率音频。ChannelNum = 1表示单声道。ResTextFormat = 2很关键,它返回的是带词级时间戳的详细识别结果,后处理阶段可以依据它定位每句话的时间位置。SourceType = 1告诉接口我在传 URL,而不是 Base64 数据。FilterModal = 1负责过滤语气词,像“嗯”“啊”这类词在转写结果里会少很多。ConvertNumMode = 1会把数字转成标准写法,比如“3.14”不会变成“三点一四”的奇怪形态。

轮询的等待时长取决于音频长度。我自己的经验是,十分钟左右的录音大约需要二到三分钟能返回结果,稍微长一点的会议录音可能要等更久。这里有一个心态建设:它不是实时接口,等是正常机制,不是卡住。

3.5 解析返回结果

任务成功后,resp.Data里面会有识别文本。带时间戳的结果是一段 JSON 文本,包含若干句子级别的对象,每个对象里除了句子文本外,还有每个词对应的起始和结束时间,单位是毫秒。我习惯先把 JSON 解析出来,再存成结构化文本:

def parse_results(data): result_text = data.Result result_detail = json.loads(data.ResultDetail) if data.ResultDetail else [] lines = [] for item in result_detail: start = item.get("StartTime", 0) / 1000 end = item.get("EndTime", 0) / 1000 text = item.get("Text", "") minutes = int(start // 60) seconds = int(start % 60) lines.append(f"[{minutes:02d}:{seconds:02d}] {text}") return "\n".join(lines), result_text

这样处理后,我拿到的不再是一整段糊在一起的文字,而是一行一行带时间标记的转写稿。这一步是整个会议小帮手的关键,也是后面做会议纪要有底气的原因。

完整跑通的代码并不复杂,几个函数加起来一百行左右。真正决定工具好用程度的,反而是接下来这步:对转写结果的二次加工。原始转写文本只能叫“记录”,离“纪要”还有距离。

4. 识别结果的二次加工:让转写稿变成会议纪要素材

4.1 时间戳的妙用

拿到转写稿后,我第一反应是“终于有了文本”,但很快发现它还不能直接发到群里。一是夹杂着大量口语,二是整篇没有分段。这时候时间戳就成了最好的线索。

一般的会议流程都有内在节奏:前几分钟同步上次进展,中间讨论问题,最后排布任务。利用时间戳,我可以把转写稿按时间窗切成若干小段。比如每隔十分钟切一段,分别浏览每段的核心内容,很快就能抓住这段讨论的主题。也可以反过来搜索关键词,比如搜“下一步”“截止”“负责人”,然后利用时间戳定位到具体讨论位置,把上下文拉出来看。

我写了一个简单的“分段 + 段落摘要”的辅助逻辑,大致逻辑是:按预设时长窗口切分文本,统计每段中出现的高频词,作为候选标题。效果谈不上惊艳,但足够用来快速定位会议的高光片段,不用把整份录音从头到尾再听一遍。

4.2 口语化文本的清洗

转写结果里最常见的多余词是“那个”“然后”“就是说”“对吧”。虽然接口的 FilterModal 参数能过滤一部分语气词,但不可能做得太激进,因为一旦把所有候选语气词都删了,可能误伤正常表达。所以我在自己的代码里再跑一轮轻量清洗。

我用的是一个非常朴素的规则:维护一个“弱语义词表”,凡是命中这个词表的词,直接删除。数量不用太多,五六个高频词就够了。比如把文本里连续出现的“就是然后”替换成“然后”,把句尾的“对吧”直接去掉。清洗完以后,再按句号、问号、感叹号把长段切分成短句,转写稿的可读性会提高不少。

还有一个细节:语音识别有时会输出重复句。比如发言人被卡住,同一个词连说三遍,转写稿就会连着出现三个相同的词。加一个基于编辑距离的简单去重函数,对相邻短句做相似度比较,相似度超过某个阈值就只保留第一句。这个做法对减少噪音非常有效。

4.3 关键词与待办提取

会议纪要最实用的部分是“接下来谁做什么”。转写稿不会主动告诉你这一点,但可以通过关键词提取来辅助判断。我的做法是对清洗过的高频词做统计,再人工重点查看包含“下周”“今天”“明天”“截止”“需要”这些词的句子。

更省事的做法是直接把包含这些词的整句抽取出来,拼成一个“动作项候选列表”,然后自己快速浏览一遍。如果会议里有人明确说“由我来负责”“周三前给结论”,这些句子几乎都能被捞到。虽然这谈不上什么智能分析,但属于非常实用的小手段,能省下不少反复听录音的时间。

另外,如果办公室里经常出现产品代号、英文名词,腾讯云的识别结果偶尔会把它们转写成奇怪的中文。这种场景建议设置一个热词词表,把常用术语丢进去。识别准确率会明显改善,代价只是维护一份词表清单。

5. 实测数据和踩坑记录

5.1 识别准确率实测

工具跑通之后,我拿了真实会议录音做了几组测试。一段大约十分钟、说话人三位、普通话为主、室内安静环境的录音,整段转写文本基本能覆盖绝大多数内容。若按照“关键意思是否正确表达”来评判,我认为准确率在九成以上。个别地方会出现专有名词识别错、人名写错、数字听岔的情况,但配合时间戳回到原音频,很快就能纠正。

如果环境嘈杂,或者有两个人明显叠话,转写质量会下降。我测过一段在开放式工区录的音频,背景频繁有人走动和键盘声,转写结果明显变差。这告诉我一个道理:云端模型再强,也架不住输入端埋雷。录音设备离说话人近一点,环境安静一点,带来的提升比换任何参数都明显。

5.2 最常见的四类坑

第一类坑是格式不服。初次测试时我直接传了一个 m4a 文件,接口创建任务时没有报错,但轮询结果状态码回了失败。排查下来发现是音频编码格式和接口预期不匹配。所以后来一律先过 ffmpeg,把采样率、声道、编码统一好再传,这个问题再也没出现过。

第二类坑是文件体积与传输时长。录音文件全转成 wav 后体积很大,一份一小时的会议 wav 文件可能超过三百兆。传对象存储时,如果带宽不够,上传本身就能花掉不少时间。后来我改成转成 mp3 格式再做识别,体积小很多,识别效果差异不明显。

第三类坑是接口调用区域不一致。创建密钥和控制台资源所属区域之间如果不一致,可能调用报错。我一开始下意识填了上海区域,但资源在另一个区域,接口也报了几次错。后来索性统一用资源所在的区域,问题就消失了。

第四类坑是轮询太频繁。我最初每秒钟查询一次任务状态,跑了一段时间发现没有必要,还容易触发接口限流。把轮询间隔放宽到三秒甚至五秒以后,整个流程稳定得多,心理上也舒服很多。

5.3 成本和免费额度

关于成本,我只能说“按量付费,价格不高”,不展开具体的数字,因为控制台的计价规则经常调整。实际的感受是:一次一小时内的会议转写,折算下来的费用远低于请一个人工速记员的零头。而且云服务通常有免费额度,用来日常试用完全够。真到了量大的场景,再去控制台看实时账单就好。

6. 从“能跑”到“好用”:后续可以怎么扩展

6.1 目前做到什么程度

我现在的版本,基本就是一个命令行工具加一个后处理脚本。每次开完会把录音拖进来,运行命令,等几分钟,输出一份带时间戳的转写稿和一份清洗后的纪要文本。对于个人使用来说,这个程度已经让我很满足,因为我不用再花半小时去回听录音。

这个工具真正改变的是我对开会的态度。以前开会过程中我会一直焦虑“这得怎么记”,现在我会放心地让录音记录一切,自己更专注于讨论本身。这种心态上的变化,比代码本身更有价值。

6.2 扩展思路

基于现在的转写文本,可以扩展的方向还有不少。比如把转写文本接入大模型,让它自动生成一份更正式的会议纪要,并且列出待办项。原来的关键词提取只是粗糙方案,交给大模型以后,质量会提升很多。

再比如对接日历。识别结果里如果出现了“明天下午三点”“周五上午”这类时间表达,可以尝试解析成时间点,给每个待办配上时间提醒。这个功能做出来,就从一个“转写工具”进化成了真正意义上的“会议小帮手”。

我也考虑过把接口替换成实时语音识别,做成开会时旁边挂着一块屏幕,实时显示字幕。这个方案对硬件和网络的依赖不小,但万一以后团队需要远程参会同屏字幕,是可以再花时间尝试的。

根据我个人的经验,这类工具最适合的落地方式不是做成一个庞大的系统,而是先把“录音转文字”这条主干道跑通,再根据实际使用场景慢慢加料。一次的会议录音,从结束到拿到稿子,整个过程控制在五分钟以内,就已经超过很多手工整理了。如果你也有类似的痛点,不妨参考这个思路,挑一个周末把属于你自己的会议小帮手搭起来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询