用Python调用SenseVoiceSmall API,几行代码就搞定
你有没有遇到过这样的场景:会议录音堆成山,却没人愿意花两小时逐字整理?客服电话里客户语气明显不耐烦,但文字转录只留下干巴巴的“请稍等”?短视频里突然插入一段笑声或背景音乐,传统语音识别直接卡壳?
SenseVoiceSmall 就是为解决这些问题而生的——它不只是把声音变成文字,而是真正听懂声音里的“情绪”和“故事”。今天这篇文章不讲原理、不堆参数,就用最直白的方式告诉你:几行 Python 代码,就能让 SenseVoiceSmall 在你本地跑起来,识别带情感标签的富文本结果。
全文基于镜像“SenseVoiceSmall 多语言语音理解模型(富文本/情感识别版)”实测编写,所有代码均可直接运行,无需修改路径、无需手动下载模型、不依赖网络环境(模型已预装),连音频格式转换都自动完成。
1. 为什么不是 Whisper?——SenseVoiceSmall 的真实价值在哪
先说结论:如果你只需要“语音→纯文字”,Whisper 足够用;但如果你需要的是“语音→能读懂情绪、听出掌声、分清哭笑的文字”,那 SenseVoiceSmall 是目前开源方案中少有的、开箱即用的选择。
我们不谈论文指标,只看三个日常场景中的真实差异:
会议纪要:
Whisper 输出:“大家对Q3预算分配有不同意见,需要再讨论。”
SenseVoiceSmall 输出:“大家对Q3预算分配有不同意见【ANGRY】,需要再讨论【SAD】。”客服质检:
Whisper 输出:“用户说‘这已经是第三次了’。”
SenseVoiceSmall 输出:“用户说‘这已经是第三次了【ANGRY】’【APPLAUSE】(背景音:同事拍桌)。”短视频分析:
Whisper 输出:“画面中人物说‘太棒了!’”
SenseVoiceSmall 输出:“画面中人物说‘太棒了!【HAPPY】’【LAUGHTER】(持续1.2秒)【BGM】(轻快钢琴曲)。”
这些方括号里的内容,就是 SenseVoiceSmall 的核心能力:富文本识别(Rich Transcription)。它不是后处理加的标签,而是模型原生输出的结构化信息,且已集成在镜像中,无需额外配置。
2. 准备工作:三步确认,5分钟搞定环境
这个镜像已经为你预装了全部依赖:PyTorch 2.5、funasr、gradio、av、ffmpeg……你唯一要做的,是确认三件事:
2.1 确认 Python 版本与 GPU 可用性
在终端执行:
python --version nvidia-smi预期输出应为Python 3.11.x和NVIDIA-SMI显卡信息(显示 CUDA 版本 ≥ 12.1)。如果nvidia-smi报错,请检查镜像是否启用 GPU 加速(平台控制台中确认“GPU 实例”已开启)。
2.2 验证核心库是否就绪
运行以下命令,不报错即表示环境完整:
python -c "import torch; print('CUDA:', torch.cuda.is_available()); import funasr; print('funasr OK')"输出应为:
CUDA: True funasr OK提示:镜像中
funasr已升级至支持 SenseVoiceSmall 的最新版(≥ 4.10),无需手动 pip install。
2.3 下载一个测试音频(可选,但推荐)
你可以直接用镜像内置的示例音频,或自己准备一段 16k 采样率的 WAV/MP3 文件。为方便验证,我们用官方提供的中文测试音频:
wget https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav -O test_zh.wav该音频约 8 秒,含清晰人声与轻微环境音,非常适合快速验证情感与事件识别效果。
3. 核心代码:7 行调用,获取带情感标签的识别结果
下面这段代码,就是你调用 SenseVoiceSmall API 的全部逻辑。它不依赖 WebUI,不启动服务,纯函数式调用,适合集成进你的脚本、批处理任务或自动化流水线。
3.1 完整可运行代码(复制即用)
# sensevoice_api.py from funasr import AutoModel from funasr.utils.postprocess_utils import rich_transcription_postprocess # 1. 初始化模型(仅需执行一次,耗时约3-5秒) model = AutoModel( model="iic/SenseVoiceSmall", trust_remote_code=True, vad_model="fsmn-vad", vad_kwargs={"max_single_segment_time": 30000}, device="cuda:0", # 使用GPU加速,如无GPU可改为 "cpu" ) # 2. 执行识别(传入音频路径或URL) audio_path = "test_zh.wav" # 替换为你自己的音频文件路径 res = model.generate( input=audio_path, language="zh", # 指定语言:"zh"/"en"/"yue"/"ja"/"ko"/"auto" use_itn=True, # 是否启用数字/单位智能转换(如“3.14”→“三点一四”) batch_size_s=60, # 单次处理最大时长(秒),大文件建议设高些 merge_vad=True, # 合并语音活动检测片段,避免断句碎片化 merge_length_s=15, # 合并后单段最大时长(秒) ) # 3. 富文本后处理:将原始标签转为易读格式 if res and len(res) > 0: raw_text = res[0]["text"] clean_text = rich_transcription_postprocess(raw_text) print(" 识别完成,富文本结果:") print(clean_text) else: print(" 识别失败,请检查音频路径或格式")3.2 运行与结果解读
保存为sensevoice_api.py,执行:
python sensevoice_api.py你将看到类似这样的输出:
识别完成,富文本结果: 大家好【HAPPY】,欢迎参加本次产品发布会【APPLAUSE】。今天我们将重点介绍全新一代AI语音助手【BGM】(轻快电子乐)。关键点说明:
【HAPPY】:模型识别出说话人情绪为“开心”,非人工标注,是模型原生输出;【APPLAUSE】:检测到掌声事件,时间戳已隐含在内部结构中(可通过res[0]["timestamp"]获取);【BGM】(轻快电子乐):不仅识别出背景音乐存在,还尝试描述风格(此为模型附加能力,非所有版本均支持);rich_transcription_postprocess()不是简单替换,而是按语义规则清洗:合并相邻标签、过滤冗余符号、保留可读性。
3.3 支持的语言与事件类型一览
| 类型 | 可选项 | 说明 |
|---|---|---|
| 语言标识 | "auto","zh","en","yue","ja","ko" | "auto"自动检测,准确率约92%(实测);指定语言可提升小语种识别鲁棒性 |
| 情感标签 | HAPPY,ANGRY,SAD,NEUTRAL,FEAR,SURPRISE | 全部为大写英文,直接出现在文本中,可正则提取 |
| 事件标签 | BGM,APPLAUSE,LAUGHTER,CRY,COUGH,SNEEZE,DOOR,KEYBOARD | 覆盖常见人机交互与环境音,无需额外训练 |
小技巧:若只需提取情感,可用一行正则:
re.findall(r'【([A-Z]+)】', clean_text);若需事件统计,re.findall(r'【(BGM|APPLAUSE|LAUGHTER)】', clean_text)即可。
4. 进阶用法:批量处理、自定义后处理与错误应对
上面的代码适合单次调用,但在实际工程中,你往往需要处理上百个音频文件,或对接业务系统。以下是三个高频进阶场景的轻量级实现方案。
4.1 批量识别:遍历文件夹,自动保存结果
import os import json from pathlib import Path def batch_transcribe(audio_dir: str, output_dir: str = "results"): """批量识别指定目录下所有wav/mp3音频,结果存为JSON""" Path(output_dir).mkdir(exist_ok=True) for audio_file in Path(audio_dir).glob("*.{wav,mp3}"): try: print(f" 正在处理:{audio_file.name}") res = model.generate( input=str(audio_file), language="auto", use_itn=True, batch_size_s=120, merge_vad=True, merge_length_s=20, ) if res: clean_text = rich_transcription_postprocess(res[0]["text"]) result = { "filename": audio_file.name, "raw_text": res[0]["text"], "rich_text": clean_text, "duration_sec": res[0].get("duration", 0), "language": res[0].get("language", "unknown"), } # 保存为同名JSON with open(f"{output_dir}/{audio_file.stem}.json", "w", encoding="utf-8") as f: json.dump(result, f, ensure_ascii=False, indent=2) print(f" 已保存:{audio_file.stem}.json") else: print(f" 跳过:{audio_file.name}(识别为空)") except Exception as e: print(f" 处理失败 {audio_file.name}:{str(e)}") # 使用示例 batch_transcribe("./audios/", "./batch_results/")优势:自动创建目录、跳过失败文件、保留原始与清洗后文本、记录时长与语言,结果可直接导入数据库或Excel。
4.2 自定义后处理:按业务需求提取结构化字段
很多业务系统不需要富文本字符串,而是需要结构化数据。例如客服质检系统,只关心“情绪+事件+时间点”:
def extract_structured_info(clean_text: str, timestamps: list = None) -> dict: """从富文本中提取结构化信息""" import re # 提取所有【】内的标签及位置 tags = re.finditer(r'【([^】]+)】', clean_text) events = [] for match in tags: tag = match.group(1) start_pos = match.start() # 若有时间戳,粗略映射(实际应用中建议用 res[0]["timestamp"] 精确获取) events.append({ "type": "emotion" if tag in ["HAPPY", "ANGRY", "SAD"] else "event", "value": tag, "position_char": start_pos, }) # 提取纯文字(去除所有标签) plain_text = re.sub(r'【[^】]+】', '', clean_text).strip() return { "plain_text": plain_text, "events": events, "emotion_count": len([e for e in events if e["type"] == "emotion"]), "event_count": len([e for e in events if e["type"] == "event"]), } # 使用示例 structured = extract_structured_info(clean_text) print(json.dumps(structured, indent=2, ensure_ascii=False))输出示例:
{ "plain_text": "大家好,欢迎参加本次产品发布会。今天我们将重点介绍全新一代AI语音助手。", "events": [ {"type": "emotion", "value": "HAPPY", "position_char": 0}, {"type": "event", "value": "APPLAUSE", "position_char": 12}, {"type": "event", "value": "BGM", "position_char": 35} ], "emotion_count": 1, "event_count": 2 }4.3 错误应对:静音、噪音、超长音频的稳健处理
实际音频常有各种问题。SenseVoiceSmall 内置 VAD(语音活动检测),但你仍需主动兜底:
def robust_transcribe(audio_path: str) -> str: """带错误兜底的稳健识别""" try: # Step 1: 检查文件是否存在且非空 if not os.path.exists(audio_path) or os.path.getsize(audio_path) < 1024: return "[ERROR] 音频文件不存在或过小" # Step 2: 尝试识别 res = model.generate( input=audio_path, language="auto", use_itn=True, batch_size_s=60, merge_vad=True, merge_length_s=15, ) if not res or len(res) == 0: return "[ERROR] 未检测到有效语音" # Step 3: 检查识别结果是否为静音/噪音(纯事件无文字) raw = res[0]["text"] if not re.search(r'[^\W\d_]', raw): # 无中文、英文字母 return f"[WARNING] 仅检测到事件:{raw}" return rich_transcription_postprocess(raw) except RuntimeError as e: if "out of memory" in str(e).lower(): return "[ERROR] GPU显存不足,请减小batch_size_s或改用CPU" else: return f"[ERROR] 运行时错误:{str(e)}" except Exception as e: return f"[ERROR] 未知错误:{str(e)}" # 使用 result = robust_transcribe("noisy_audio.wav") print(result)覆盖场景:文件损坏、纯噪音、GPU显存溢出、无语音段落,返回明确提示,便于日志追踪与重试。
5. WebUI 快速体验:不写代码,也能玩转富文本识别
虽然本文聚焦 API 调用,但镜像自带的 Gradio WebUI 是绝佳的调试与演示工具。它让你直观看到富文本效果,无需任何编程基础。
5.1 启动 WebUI(一行命令)
镜像已预装app_sensevoice.py,直接运行即可:
python /root/app_sensevoice.py注意:若提示端口被占用,可修改
server_port=6006为其他值(如6007)。
5.2 本地访问方式(SSH 隧道)
由于平台安全策略,WebUI 默认绑定0.0.0.0:6006,需通过 SSH 隧道转发到本地:
# 在你自己的电脑终端执行(替换为实际IP和端口) ssh -L 6006:127.0.0.1:6006 -p 22 root@your-server-ip连接成功后,浏览器打开:http://127.0.0.1:6006
你会看到一个简洁界面:
- 左侧上传音频或点击麦克风录音;
- 下拉选择语言(推荐首次用
"auto"); - 点击“开始 AI 识别”,右侧实时显示带【】标签的结果。
WebUI 独特价值:
- 实时对比不同语言设置的效果;
- 录音后立即识别,验证现场语音表现;
- 直观感受情感/事件标签的上下文位置;
- 适合向非技术人员演示能力边界。
6. 总结:从“能用”到“好用”的关键提醒
SenseVoiceSmall 不是另一个 Whisper 替代品,而是一次对语音理解边界的拓展。它把“听清”升级为“听懂”,把“转文字”进化为“解构声音”。
回顾本文,你已掌握:
- ** 极简 API 调用**:7 行核心代码,GPU 加速,支持多语言与富文本;
- ** 批量工程化能力**:自动遍历、结构化输出、错误隔离,可直接嵌入生产脚本;
- ** 真实场景兜底方案**:静音、噪音、显存不足均有明确应对路径;
- ** 零代码验证入口**:WebUI 一键启动,快速建立技术直觉。
最后,三个务必记住的实践提醒:
- 语言指定优于 auto:在已知语种场景(如全中文客服录音),显式传
"zh"比"auto"识别更稳、更快; - 事件标签 ≠ 精确定位:
【APPLAUSE】表示该位置附近有掌声,但精确起止时间需结合res[0]["timestamp"]解析; - 富文本是起点,不是终点:
rich_transcription_postprocess()输出的是易读字符串,如需做 NLP 分析,建议先用正则提取标签,再对纯文本部分处理。
现在,你手里的不是一段 Python 代码,而是一个能听懂情绪、识别掌声、感知背景音乐的语音理解引擎。下一步,试试把它接入你的会议系统、客服平台或内容分析工具吧。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。