前言

最近接到了一个数据标注需求:需要对大量的音频进行标注。要求输出的 JSON 格式非常复杂,包含对话轮次、角色(A/B)、情感强度、语调、转写文本等。

起初我尝试手动听写 + Excel 记录,效率低到令人发指。后来折腾了一套 Label Studio + OpenAI Whisper 的自动化方案,效率直接提升 80%!

这篇博客记录了整个部署过程中遇到的巨多坑(尤其是 Windows 路径、404 报错、JSON 格式清洗),以及最终的完美解决方案。


一、 环境准备与安装

为了不污染电脑的 Python 环境,强烈建议使用 Conda。

1.1 创建虚拟环境

不要直接装在 base 环境里,否则以后包冲突会很麻烦。

codeBash

# 创建一个 python 3.9 的环境(Label Studio 对 3.8/3.9 支持最好)
conda create -n ls_env python=3.9

# 激活环境
conda activate ls_env

1.2 安装核心软件

codeBash

# 安装标注平台
pip install label-studio

# 安装 AI 语音转文字库 (用于预标注)
pip install openai-whisper
conda install ffmpeg  # Whisper 依赖这个处理音频

二、 Label Studio 启动与配置 (Windows 避坑指南)

2.1 编写启动脚本 (坑点 1:中文乱码与本地权限)

直接命令行启动虽然行,但每次都要打一堆字,而且 Windows 下默认编码会导致中文报错。我写了一个 .bat 脚本来实现一键启动。

启动标注.bat

codeBatch

@echo off
chcp 65001 >nul  :: 修复中文乱码

:: 开启本地文件读取权限(必须开!否则后面加载本地音频会报 404)
set LABEL_STUDIO_LOCAL_FILES_SERVING_ENABLED=true
set LABEL_STUDIO_LOCAL_FILES_DOCUMENT_ROOT=D:\

echo 正在启动 Label Studio...
call "D:\conda\Scripts\activate.bat" ls_env  :: 自动激活环境
cd /d %~dp0
label-studio --data-dir ./my_data  :: 指定数据存放在当前目录,不乱跑
pause

2.2 配置 XML 模版 (实现多轮对话标注)

需求是“多轮对话”,Label Studio 默认的音频模板只能标整段。我们需要用 Regions (区域标注) 功能。

Settings -> Labeling Setup -> Custom Template 代码:
(代码太长此处略,核心逻辑是使用 <Labels> 做说话人切分,<TextArea perRegion="true"> 做分段转写)

踩坑记录 (坑点 2:Validation Error)
现象:修改 XML 时提示 Validation error... These labels still exist...
原因:之前测试时生成了一些草稿数据,旧数据用到了旧标签,导致新模版无法保存。
解决:直接把项目删了重建,或者把所有 Tasks 全部删除,保持项目空白再改代码。


三、 解决音频加载 404 问题 (坑点 3:史诗级大坑)

这是最折磨的一步。我希望 Label Studio 直接读取我本地 D:\ls_data\raw_audio 里的文件,而不是手动一个个上传。但配置后总是报错:
Technical description: HTTP error status: 404

❌ 失败尝试

  1. 修改环境变量 DOCUMENT_ROOT:改了斜杠、反斜杠、大小写,依然时好时坏。

  2. Python 脚本生成绝对路径 URL:浏览器显示 blocked。

✅ 最终解决方案:UI 挂载法

官方推荐的最稳妥方案,不用改代码,直接在网页上配。

  1. 进入 Settings -> Cloud Storage

  2. 点击 Add Source Storage -> 选择 Local files

  3. Absolute local path: 填入音频文件夹路径 (如 D:\ls_data\raw_audio)。

  4. File Name Filter: 改成 .* (默认只读 JSON,必须改这个才能读音频!)。

  5. Treat every bucket object as a source file: 必须开启 (ON) (这是最关键的一步!)。

  6. 点击 Sync

配置完这一步,音频终于能正常播放了!


四、 引入 AI 预标注 (效率提升神器)

为了不手打字幕,我写了一个 Python 脚本调用 Whisper 模型,先把音频的文字时间轴生成出来。

4.1 编写 auto_label.py

思路:

  1. 遍历文件夹里的音频。

  2. 调用 whisper.load_model("medium") 识别。

  3. 将识别出的 start, end, text 封装成 Label Studio 的 JSON 格式。

  4. 生成 import_tasks.json

4.2 导入技巧

在 Label Studio 点击 Import 时,只需要拖入 import_tasks.json
因为我们在第三步已经配置了“本地存储挂载”,系统会自动把 JSON 里的任务和本地的音频文件关联起来。

工作流优化
Whisper 分不清说话人 A 和 B。
我的做法:脚本默认全标为 A。在标注界面,利用快捷键(键盘 1 是 A,2 是 B),左手按键盘,右手点鼠标,1秒钟改一个,比 AI 瞎猜要准得多且快。


五、 数据导出与格式清洗 (坑点 4:导出格式不可用)

Label Studio 导出的 JSON 是“源数据”(包含各种内部 ID、from_name 等),结构非常乱,无法直接交付给客户。而且它默认导出一个大文件,而我需要每个音频单独存一个 JSON。

5.1 编写 convert.py

我写了一个后处理脚本,功能包括:

  1. 清洗格式:提取 value 里的核心数据,丢弃系统字段。

  2. 数据拼接:把散落在不同 dict 里的 说话人、文本、情感 拼成一个对象。

  3. 幽灵数据过滤:自动剔除时长为 0 的无效标注。

  4. 自动切分:将大文件切分为 DIALOG_001.json, DIALOG_002.json ...

使用方法

codeBash

python convert.py

运行后会自动生成 output_files 文件夹,里面就是整整齐齐的交付标准格式。


六、 总结

这一套流程跑通后,我的工作流变成了:

  1. 扔音频:把几百个文件丢进文件夹。

  2. 跑脚本:一键生成预标注数据。

  3. 修数据:进网页只负责听和点选情感(不打字)。

  4. 一键导出:跑转换脚本,直接交付。

遇到的最大教训

  1. Windows 的路径问题(\/)真的很搞心态,能用 UI 界面配置挂载就别用脚本硬改路径。

  2. 文件后缀名一定要看清楚,别把 .py 存成了 .txt

  3. Label Studio 的 Import 逻辑要搞懂:要么同时拖音频和JSON,要么配置好 Local Storage 后只拖 JSON。

希望这篇踩坑记录能帮到同样在做音频标注的朋友!