@@ -0,0 +1,125 @@
# EOT 标注与离线对话转写格式
本版用于 VAD 判断静音过长之后的额外 EOT 判断。每个用户话轮对应一个判断位置,标签回答:**在该位置,让机器人接话是否合适。**
对话转写和 EOT 标注分别保存在两份 CSV 中。本版按录音时间组织离线转写,用于结合音频和对话文本进行标注与回测。
## 文件组织
| 文件 | 内容 | 一行代表什么 |
| --- | --- | --- |
| `asr_history.csv` | 整通对话的 agent/user 转写。 | 一段有起止时间的实际语音及其转写内容。 |
| `eot_labels.csv` | EOT 判断位置、该位置的当前用户文本及人工标签。 | 一个判断位置的 EOT 标注。 |
两份文件通过 `call_id` 关联,可以包含多通对话。EOT 样本用 `call_id + decision_ms` 唯一标识,不再填写话轮 ID。
## 对话转写 CSV
固定表头:
``` csv
call_id , role , start_ms , end_ms , transcript
```
| 字段 | 填写规则 |
| --- | --- |
| `call_id` | 通话 ID,与录音和 EOT 标注对应。 |
| `role` | `agent` 表示机器人,`user` 表示用户。 |
| `start_ms` | 该段语音在整通录音中的起点,单位为毫秒。 |
| `end_ms` | 该段语音在整通录音中的终点,单位为毫秒。 |
| `transcript` | 该段语音的转写内容,可由 ASR 生成并人工核对。 |
每段语音只保存一份转写,按录音顺序排列。同一角色可以连续出现多行。用户说话中途有停顿时,可以将停顿前后分成两段;分段仅用于对齐文本与时间,不表示用户话轮一定已经结束。
机器人记录实际说出的内容。被打断时只转写已播放的部分。转写应保留原意,不补充录音中没有说出的内容。
虚构示例见 [示例/asr_history.csv ](示例/asr_history.csv ):
``` csv
call_id , role , start_ms , end_ms , transcript
demo , agent , 1000 , 2400 , 您什么时候方便接电话?
demo , user , 3000 , 4400 , 我明天下午
demo , user , 5600 , 7100 , 不行,后天可以
demo , agent , 7900 , 8500 , 后天上午可以吗?
demo , user , 9000 , 9250 , 可以
```
## EOT 标注 CSV
固定表头:
``` csv
call_id , decision_ms , user_text_at_decision , can_reply_now , confidence , reason , annotator
```
| 字段 | 填写规则 |
| --- | --- |
| `call_id` | 通话 ID,与转写和录音对应。 |
| `decision_ms` | 把音频交给 EOT 判断的位置,单位为毫秒。 |
| `user_text_at_decision` | 截至 `decision_ms` ,当前用户话轮已说出的文本。尚未说完时填写部分文本,已说完时填写完整文本,不包含后续内容。 |
| `can_reply_now` | `1` 表示可以接话,`0` 表示接话会过早打断,空表示无法判断。 |
| `confidence` | 可选,填写 `high` 、`medium` 或 `low` ,表示标注员的把握。 |
| `reason` | 简短判断原因,取值见下表。 |
| `annotator` | 标注员 ID;仲裁后的最终标签填写仲裁员 ID。 |
`user_text_at_decision` 只保存本次判断的当前用户表达,全部对话历史仍从转写表获取。按截至判断位置的音频核对,或依据词级时间对齐填写;当前文本无法辨认时可留空。
时间统一使用整通录音的媒体时钟:以回放一致的音频起点为零,填写非负整数毫秒。裁剪片段中的时间也要换算回整通录音时间。
**decision_ms 是 EOT 的判断位置。 ** 例如,录音播放到第 5.2 秒时 VAD 请求 EOT 判断,就填 `5200` 。它与用户最后一个字的结束位置、机器人开始播放的位置分别记录。
判断位置优先取 VAD 日志;没有日志时,可用固定版本和配置重放录音生成,并在配套配置中记录其来源。
## 按判断时间获取全部对话历史
对每一条 EOT 标注:
1. 从转写表筛选相同 `call_id` 的记录。
2. 保留 `end_ms <= decision_ms` 的所有记录。
3. 按 `start_ms` 排序;起点相同则保留 CSV 中的原有顺序,形成截至判断位置的全部对话文本。
4. 将历史、EOT 表中的 `user_text_at_decision` 和截至 `decision_ms` 的音频作为输入。`user_text_at_decision` 可作为单独的当前用户文本字段;组装成消息列表时,当前表达只保留一份,避免将历史里已有的同一内容重复追加。`agent` 可映射为模型消息中的 `assistant` , `user` 保持为 `user` 。
如果某一行满足 `start_ms <= decision_ms < end_ms` ,它横跨判断位置,不把该行整段文本加入历史;用户在该位置之前已说出的部分直接填写到 EOT 表的 `user_text_at_decision` 列。仅凭一段完整转写无法按时间准确截出前半句,应听音频或使用词级时间对齐核对。
转写文件保留整通对话全部内容,取上下文时保留判断位置之前的全部记录。上述规则按语音结束时间筛选离线转写,不记录 ASR 返回延迟。
## 标签和原因
标签依据音频、语气和对话上下文判断。短回答如“可以”“明天下午”也可能已经完成回答;句子完整或存在句号,不自动代表可以接话。ASR 错识别或漏识别不直接决定 EOT 标签。
| `reason` | 含义 | `can_reply_now` |
| --- | --- | --- |
| `completed_turn` | 当前轮次表达完成,可以接话。 | `1` |
| `completed_answer` | 已完成对机器人当前问题的回答。 | `1` |
| `mid_turn_pause` | 只是同一话轮内的停顿。 | `0` |
| `hesitation` | 正在犹豫或组织语言,尚未结束。 | `0` |
| `unfinished_expression` | 表达尚未完成,此刻接话会打断。 | `0` |
| `uncertain` | 判断有争议或上下文不足。 | 空 |
| `audio_issue` | 音频质量或录音缺失影响判断。 | 空 |
| `interrupted_unclear` | 机器人插话后用户停止,无法判断其原本是否准备结束。 | 空 |
虚构标注示例见 [示例/eot_labels.csv ](示例/eot_labels.csv ):
``` csv
call_id , decision_ms , user_text_at_decision , can_reply_now , confidence , reason , annotator
demo , 5200 , 我明天下午 , 0 , high , mid_turn_pause , A
demo , 9400 , 可以 , 1 , high , completed_answer , A
```
第 5.2 秒的 `user_text_at_decision` 为“我明天下午”,文本上下文包含机器人问题和这段用户表达。示例设定为用户正在同一话轮内停顿,之后继续说“不行,后天可以”,所以标 `0` ;后续这段文本不进入第 5.2 秒的输入。
第 9.4 秒的 `user_text_at_decision` 为“可以”,文本上下文包含上面五条转写记录。示例设定为用户已用“可以”完成回答且语气收束,所以标 `1` 。
## 标注步骤和数据核对
1. 核对通话,在时间轴上定位 `decision_ms` 。
2. 查看按上述规则取出的全部对话历史,播放截至判断位置的音频,填写 `user_text_at_decision` 、标签、原因和标注员 ID;置信度可选。
3. 必要时听后续录音辅助仲裁;后续内容不加入该位置的输入。无法判断时留空标签,不强行填 `0` 或 `1` 。
多人独立标注时,每个人各保存一份标签文件,使用同一份转写;仲裁后的最终文件每个 `call_id + decision_ms` 只有一行。
CSV 使用 UTF-8 编码和标准 CSV 读写规则。转写内容含英文逗号、双引号或换行时,用双引号包裹,内部双引号写成两个双引号。
核对 `0 <= start_ms < end_ms` 、`decision_ms >= 0` ,并检查角色和标签取值。`0` 是有效负例,空标签不进入二分类训练和评分。
原始表格中的“是”(发生过早打断)和“否”(未发生过早打断)可用于挑选候选样本,仍需针对本次判断位置重新核对。音频路径、声道映射和转写配置保存在配套数据中。