Python实战:讯飞语音转写API双人对话角色分离与结构化数据提取
1. 讯飞语音转写API基础配置
双人对话场景下的语音转写需求在实际开发中非常常见,比如会议记录、访谈整理等场景。讯飞开放平台提供的语音转写API能够很好地支持这类需求,但官方文档中的示例代码往往没有包含角色分离的关键参数配置。
首先需要完成API的基础配置。在Python中调用讯飞API主要涉及以下几个核心参数:
-
appid:在讯飞开放平台创建应用后获取的应用ID -
secret_key:应用对应的密钥 -
upload_file_path:待转写的音频文件路径
这里有个容易踩坑的地方:讯飞API对音频文件有明确要求,支持wav、mp3、m4a等格式,但需要注意:
- 文件大小不超过500MB
- 音频时长建议5分钟以上(太短的音频可能影响转写准确率)
- 采样率支持8kHz和16kHz
class RequestApi(object):
def __init__(self, appid, secret_key, upload_file_path):
self.appid = appid
self.secret_key = secret_key
self.upload_file_path = upload_file_path
self.ts = str(int(time.time()))
self.signa = self.get_signa()
签名生成是调用API的关键步骤,讯飞使用的是HMAC-SHA1加密算法。很多开发者在这里会遇到签名错误的问题,主要是因为时间戳格式不正确或密钥处理有误。
2. 双人对话角色分离配置
要实现双人对话的角色分离,关键在于正确设置
roleType
和
roleNum
这两个参数:
-
roleType=1:表示开启角色分离功能 -
roleNum=2:表示对话中有2个说话人
在实际项目中,我发现如果音频质量较差(比如有背景噪音),角色分离的准确率会明显下降。建议在录音时:
- 使用指向性麦克风
- 确保两个说话人与麦克风的距离相近
- 避免突然的噪音干扰
def upload(self):
param_dict = {
'appId': self.appid,
'signa': self.signa,
'ts': self.ts,
"fileSize": os.path.getsize(self.upload_file_path),
"fileName": os.path.basename(self.upload_file_path),
"duration": "200", # 预估音频时长
"roleNum": 2, # 双人对话
"roleType": 1 # 开启角色分离
}
# 其余上传代码...
实测中发现,角色分离的效果与音频质量强相关。在安静的会议室环境下,角色识别的准确率能达到90%以上,但在嘈杂的咖啡厅等环境,准确率可能下降到70%左右。
3. 获取与解析转写结果
API返回的结果是复杂的嵌套JSON结构,提取有效信息需要理解其数据结构。主要包含以下几个关键字段:
-
content:包含转写结果的核心内容 -
orderInfo:任务状态信息 -
lattice:详细的转写结果,包含时间戳和说话人信息
{
"content": {
"orderId": "123456789", # 任务ID
"lattice": [
{
"json_1best": {
"st": {
"rt": [
{
"ws": [
{
"cw": [
{
"w": "你好", # 转写文本
"wp": "n" # 词性标注
}
]
}
],
"speaker": "0" # 说话人标识
}
]
}
}
}
]
}
}
处理这个JSON时,我建议使用递归方式遍历数据结构,比多层嵌套的for循环更清晰。下面是我在实际项目中总结出的解析方法:
def parse_result(result):
dialogues = []
for lattice in result['content']['lattice']:
rt_list = lattice['json_1best']['st']['rt']
for rt in rt_list:
speaker = rt.get('speaker', '0')
for ws in rt['ws']:
for cw in ws['cw']:
dialogues.append({
'speaker': speaker,
'text': cw['w'],
'pos': cw.get('wp', '')
})
return dialogues
4. 结构化数据转换与输出
将解析后的数据转换为结构化格式(如DataFrame)可以方便后续分析处理。Pandas库非常适合这种场景:
import pandas as pd
def to_dataframe(dialogues):
df = pd.DataFrame(dialogues)
# 添加时间序列信息
df['time'] = pd.to_datetime(df.groupby('speaker').cumcount(), unit='s')
# 按说话人分组
speaker_df = df.groupby('speaker').agg({'text': ' '.join})
return df, speaker_df
对于需要导出为文档的场景,可以进一步处理:
def export_to_txt(dialogues, filename):
with open(filename, 'w', encoding='utf-8') as f:
current_speaker = None
for item in dialogues:
if item['speaker'] != current_speaker:
f.write(f"\nSpeaker {item['speaker']}:\n")
current_speaker = item['speaker']
f.write(item['text'] + " ")
在实际项目中,我还遇到过需要将转写结果与原始音频时间轴对齐的需求。这时可以利用返回结果中的时间戳信息(bg/ed字段),实现点击文本跳转到对应音频位置的功能。
5. 错误处理与性能优化
API调用过程中常见的错误包括:
- 签名错误(检查时间戳和密钥)
- 音频格式不支持(转换音频格式)
- 请求频率限制(添加延时重试机制)
建议的异常处理方式:
import time
from requests.exceptions import RequestException
def safe_get_result(api, max_retries=3):
for i in range(max_retries):
try:
result = api.get_result()
if result['content']['orderInfo']['status'] == 4:
return result
time.sleep(5)
except RequestException as e:
print(f"请求失败,重试 {i+1}/{max_retries}: {str(e)}")
time.sleep(2**i) # 指数退避
raise Exception("获取结果失败")
对于长音频文件(超过30分钟),建议:
- 使用分片上传
- 添加进度提示
- 考虑使用回调通知机制
6. 实际应用案例
以一个真实的访谈场景为例,我们处理了45分钟的双人对话音频。关键处理步骤:
- 预处理:使用ffmpeg统一音频格式
ffmpeg -i input.m4a -ar 16000 -ac 1 output.wav
- 转写后得到结构化数据:
speaker | text | pos
-------------------------------------------
0 | 您好,请简单介绍一下自己 | n
1 | 我是某公司产品经理... | n
0 | 您如何看待AI技术... | n
- 后续分析:
- 计算每个说话人的发言时长占比
- 提取关键词生成访谈摘要
- 构建对话轮次关系图
在另一个在线会议场景中,我们实现了实时转写功能,关键技术点:
- 使用WebSocket保持长连接
- 每5秒发送一次音频片段
- 实时更新前端显示
- 支持中英文混合识别
7. 进阶技巧与注意事项
经过多个项目的实践,我总结出以下经验:
- 音频预处理很重要:
- 使用sox工具降噪
sox input.wav output.wav noisered noise.prof 0.2
- 提升角色分离准确率:
- 在安静环境下录音
- 说话人保持适当距离
- 避免同时说话
- 处理特殊场景:
-
中英文混合:设置
language参数 - 专业术语:上传术语表
- 方言识别:开启对应方言选项
- 性能优化:
- 使用异步IO处理多个文件
- 缓存常用音频的转写结果
- 批量处理时限制并发数
最后提醒几个容易忽视的问题:
- 注意API的QPS限制
- 结果缓存时间(通常72小时后删除)
- 企业级应用考虑私有化部署方案
更多推荐



所有评论(0)