音频标注
在 Potato 中切分音频,在交互式波形上标记时间区段,支持播放速度控制、缩放,以及用于转写的逐段问题。
Potato 的音频标注工具让标注者通过基于波形的界面切分音频文件,并给时间区段分配标签。
功能
- 波形可视化
- 按时间创建区段
- 给区段分配标签
- 可变速的播放控制
- 缩放与滚动导航
- 键盘快捷键
- 服务端波形缓存
基本配置
默认模式要求标注者划出区段并给每一段打标签,所以说话人分离任务只需要写好标签:
annotation_schemes:
- name: "speakers"
description: "Mark when each speaker is talking"
annotation_type: "audio_annotation"
labels:
- name: "Speaker 1"
color: "#3B82F6"
- name: "Speaker 2"
color: "#10B981"配置选项
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name | 字符串 | 必填 | 该标注的唯一标识 |
description | 字符串 | 必填 | 展示给标注者的说明 |
annotation_type | 字符串 | 必填 | 必须是 "audio_annotation" |
mode | 字符串 | "label" | 标注模式:"label"、"questions" 或 "both" |
labels | 列表 | 视情况 | label 或 both 模式下必填 |
segment_schemes | 列表 | 视情况 | questions 或 both 模式下必填 |
min_segments | 整数 | 0 | 至少需要的区段数 |
max_segments | 整数 | null | 允许的最大区段数(null 表示不限) |
zoom_enabled | 布尔值 | true | 启用缩放控件 |
playback_rate_control | 布尔值 | false | 显示播放速度选择器 |
waveform | 布尔值 | true | 显示波形 |
spectrogram | 布尔值 | false | 在波形旁显示声谱图 |
spectrogram_options | 字典 | — | 声谱图的 FFT 大小、频率范围和配色 |
source_field | 字符串 | "" | 当一个条目带有多个音频文件时,本方案所标注的展示字段 |
方案缺了它所在模式需要的输入,Potato 就拒绝加载,所以 label 和 both 缺 labels 会失败,questions 和 both 缺 segment_schemes 会失败。
标签配置
给每个标签配一个 key_value,标注者不用离开波形就能给区段打标签;在区段一个接一个出现的说话人分离任务里,这一点很要紧:
labels:
- name: "speech"
color: "#3B82F6"
key_value: "1"
- name: "music"
color: "#10B981"
key_value: "2"
- name: "silence"
color: "#64748B"
key_value: "3"标注模式
标签模式(默认)
区段拿到类别标签。每个区段回答的都是同一个单选问题时,用这个模式:
annotation_schemes:
- name: "emotion"
description: "Label the emotion in each segment"
annotation_type: "audio_annotation"
mode: "label"
labels:
- name: "happy"
color: "#22C55E"
- name: "sad"
color: "#3B82F6"
- name: "angry"
color: "#EF4444"
- name: "neutral"
color: "#64748B"问题模式
每个区段回答专门的问题。segment_schemes 里的子方案就是普通的标注方案,只是按区段逐个渲染,所以每个子方案都要写齐它自己那种类型需要的字段,比如 likert 量表需要 size、min_label 和 max_label:
annotation_schemes:
- name: "transcription"
description: "Transcribe each segment"
annotation_type: "audio_annotation"
mode: "questions"
segment_schemes:
- name: "transcript"
annotation_type: "text"
description: "Enter the transcription"
- name: "confidence"
annotation_type: "likert"
description: "How confident are you?"
size: 5
min_label: "Not confident"
max_label: "Very confident"两者兼用模式
把打标签和逐段问卷结合起来。每个区段都要标注者既选标签又填一份表单,所以只在确实两样都要的那一遍标注里用它:
annotation_schemes:
- name: "detailed_diarization"
description: "Label speakers and add notes"
annotation_type: "audio_annotation"
mode: "both"
labels:
- name: "Speaker A"
color: "#3B82F6"
- name: "Speaker B"
color: "#10B981"
segment_schemes:
- name: "notes"
annotation_type: "text"
description: "Any notes about this segment?"全局音频配置
Potato 在服务端计算波形数据并缓存,因为浏览器要自己渲染波形,就得先把整个文件下载下来解码。缓存在配置文件里设置:
audio_annotation:
waveform_cache_dir: "waveform_cache/"
waveform_look_ahead: 5
waveform_cache_max_size: 1000
client_fallback_max_duration: 1800| 字段 | 默认值 | 说明 |
|---|---|---|
waveform_cache_dir | — | 存放缓存波形数据的目录 |
waveform_look_ahead | 5 | 预先计算的后续条目数量 |
waveform_cache_max_size | 100 | 缓存波形文件的最大数量 |
client_fallback_max_duration | 1800 | 没有可用缓存波形时,浏览器愿意渲染的最长文件时长(秒) |
标注者翻条目的速度快过服务端预计算时,调高 waveform_look_ahead;研究涉及的文件多过缓存容量时,调高 waveform_cache_max_size。
示例
说话人分离
说话人分离最能体现播放速度的价值:标注者会放慢音频,好把边界卡在说话人切换的位置,又会在某个人连说很久的地方加快播放:
annotation_schemes:
- name: "diarization"
description: "Identify who is speaking at each moment"
annotation_type: "audio_annotation"
mode: "label"
labels:
- name: "Interviewer"
color: "#8B5CF6"
key_value: "1"
- name: "Guest"
color: "#EC4899"
key_value: "2"
- name: "Overlap"
color: "#F59E0B"
key_value: "3"
zoom_enabled: true
playback_rate_control: true声音事件检测
设置 min_segments: 1 可以拦住标注者提交一段什么都没标的录音。只有在每段录音都至少含一个事件时才用它:
annotation_schemes:
- name: "sound_events"
description: "Mark all sound events"
annotation_type: "audio_annotation"
labels:
- name: "speech"
color: "#3B82F6"
- name: "music"
color: "#10B981"
- name: "applause"
color: "#F59E0B"
- name: "laughter"
color: "#EC4899"
- name: "silence"
color: "#64748B"
min_segments: 1转写校对
把自由文本字段和一个质量评分配在一起,就记录下了转写为什么没被改动,输出里也就能把干净的区段和听不清的区段区分开:
annotation_schemes:
- name: "transcription_review"
description: "Review and correct the transcription for each segment"
annotation_type: "audio_annotation"
mode: "questions"
segment_schemes:
- name: "transcript"
annotation_type: "text"
description: "Enter or correct the transcription"
- name: "quality"
annotation_type: "radio"
description: "Audio quality"
labels:
- "Clear"
- "Noisy"
- "Unintelligible"已经有转写文本了?
上面这些都是从一张空白波形开始的:标注者听音频、划边界、给听到的内容打标签。如果转写文本已经存在,无论来自 Whisper 还是下载的字幕,该走的是另一条路。Potato 能读 21 种转写和字幕格式,把每一轮发言渲染成与音频同步的对话气泡,标注者于是给已有的区段打标签,而不是重新划一遍。
{"id": "int_001", "conversation": {"audio": "media/int_001.mp3",
"transcript": "media/int_001.srt"}}格式清单见转写格式,完整流程见标注 Whisper 转写。两样都需要时,波形切分和转写标注也可以放在同一个任务里跑。
键盘快捷键
| 按键 | 操作 |
|---|---|
Space | 播放/暂停 |
← / → | 前后跳 5 秒 |
[ / ] | 设置区段起点/终点 |
Enter | 创建区段 |
Del | 删除区段 |
+ / - | 放大/缩小 |
0 | 适应视图 |
在 label 和 both 模式下,每个带 key_value 的标签还会占一个自己的按键。
数据格式
输入数据
数据文件里要写上音频文件的路径或 URL:
[
{
"id": "audio_001",
"audio_url": "https://example.com/audio/recording1.mp3"
},
{
"id": "audio_002",
"audio_url": "/data/audio/recording2.wav"
}
]把 text_key 指向存放音频路径的字段,因为 Potato 交给标注组件的就是这个字段:
item_properties:
id_key: id
text_key: audio_url输出格式
{
"id": "audio_001",
"annotations": {
"diarization": [
{
"start": 0.0,
"end": 5.5,
"label": "Interviewer"
},
{
"start": 5.5,
"end": 12.3,
"label": "Guest"
},
{
"start": 12.3,
"end": 14.0,
"label": "Overlap"
}
]
}
}问题模式下,区段里会带上嵌套的回答:
{
"start": 0.0,
"end": 5.5,
"transcript": "Hello and welcome to the show.",
"quality": "Clear"
}支持的音频格式
- MP3(推荐)
- WAV
- OGG
- M4A
实践建议
- 预先缓存波形 - 数据集较大时使用服务端缓存
- 开启播放控制 - 变速有助于精确切分
- 使用键盘快捷键 - 比点击快,标注者的视线也能一直留在波形上
- 明确边界的定义 - 说清楚什么算区段的起点和终点
- 选择合适的模式 - 分类用 "label",细致标注用 "questions"
- 限制区段数量 - 用
min_segments保证覆盖