1. 讯飞语音转写API基础配置

双人对话场景下的语音转写需求在实际开发中非常常见,比如会议记录、访谈整理等场景。讯飞开放平台提供的语音转写API能够很好地支持这类需求,但官方文档中的示例代码往往没有包含角色分离的关键参数配置。

首先需要完成API的基础配置。在Python中调用讯飞API主要涉及以下几个核心参数:

  • appid :在讯飞开放平台创建应用后获取的应用ID
  • secret_key :应用对应的密钥
  • upload_file_path :待转写的音频文件路径

这里有个容易踩坑的地方:讯飞API对音频文件有明确要求,支持wav、mp3、m4a等格式,但需要注意:

  1. 文件大小不超过500MB
  2. 音频时长建议5分钟以上(太短的音频可能影响转写准确率)
  3. 采样率支持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个说话人

在实际项目中,我发现如果音频质量较差(比如有背景噪音),角色分离的准确率会明显下降。建议在录音时:

  1. 使用指向性麦克风
  2. 确保两个说话人与麦克风的距离相近
  3. 避免突然的噪音干扰
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调用过程中常见的错误包括:

  1. 签名错误(检查时间戳和密钥)
  2. 音频格式不支持(转换音频格式)
  3. 请求频率限制(添加延时重试机制)

建议的异常处理方式:

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分钟),建议:

  1. 使用分片上传
  2. 添加进度提示
  3. 考虑使用回调通知机制

6. 实际应用案例

以一个真实的访谈场景为例,我们处理了45分钟的双人对话音频。关键处理步骤:

  1. 预处理:使用ffmpeg统一音频格式
ffmpeg -i input.m4a -ar 16000 -ac 1 output.wav
  1. 转写后得到结构化数据:
speaker | text                      | pos
-------------------------------------------
0       | 您好,请简单介绍一下自己   | n
1       | 我是某公司产品经理...     | n
0       | 您如何看待AI技术...       | n
  1. 后续分析:
  • 计算每个说话人的发言时长占比
  • 提取关键词生成访谈摘要
  • 构建对话轮次关系图

在另一个在线会议场景中,我们实现了实时转写功能,关键技术点:

  1. 使用WebSocket保持长连接
  2. 每5秒发送一次音频片段
  3. 实时更新前端显示
  4. 支持中英文混合识别

7. 进阶技巧与注意事项

经过多个项目的实践,我总结出以下经验:

  1. 音频预处理很重要:
  • 使用sox工具降噪
sox input.wav output.wav noisered noise.prof 0.2
  1. 提升角色分离准确率:
  • 在安静环境下录音
  • 说话人保持适当距离
  • 避免同时说话
  1. 处理特殊场景:
  • 中英文混合:设置 language 参数
  • 专业术语:上传术语表
  • 方言识别:开启对应方言选项
  1. 性能优化:
  • 使用异步IO处理多个文件
  • 缓存常用音频的转写结果
  • 批量处理时限制并发数

最后提醒几个容易忽视的问题:

  • 注意API的QPS限制
  • 结果缓存时间(通常72小时后删除)
  • 企业级应用考虑私有化部署方案
Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐