EOT 标注工作台
基于 Next.js Minimal 模板的本地网页工具,独立放在 labels/eot-studio,按项目的 EOT 标注格式查看对话、回放音频并编辑判断位置和标签。
启动
cd labels/eot-studio
npm install
npm run dev
打开终端显示的本地地址,通常为 http://localhost:3000。生产构建使用 npm run build,随后 npm start。请从 labels/eot-studio 目录运行,API 以其上两级作为项目根目录。
使用
- 默认载入“韩泰机器人抢话”的 6 通录音,以及原 XLSX 转换出的 76 条转写、39 个 EOT 判断点。已有工作数据时优先读取工作数据,初稿保留在
labels/EOT标注/韩泰初稿/。 - 左右声道分别显示波形,共用时间刻度。机器人、用户转写作为对应轨道上的块显示;点击块在右侧栏编辑说话人、文本和起止时间;拖动左右边界直接调整片段范围。拖动结束作为一次修改,可撤销。查看模式的字段为只读。点击“在播放位置新增”的下拉菜单,选择机器人转写、用户转写或 EOT 判断点。
- 点击判断点轨道空白处直接新增 EOT;聚焦该轨道后按 Enter 可在播放位置新增。点击已有标记选择标签,直接拖动判断点轴上的标记调整时间,聚焦标记后可用方向键微调;拖动时吸附转写边界、播放位置和其他判断点,按住 Alt 暂停吸附,松开后作为一次修改可撤销。同一通话的判断点不能重合。放大时间轴便于查看短片段。顶部只保留播放头。播放头在点击或拖动定位时,会吸附附近的转写块边界及 EOT 判断点;按住 Alt 暂停吸附。
- 右侧编辑判断时的用户文本、是否可以接话、判断原因、置信度和标注员。标注员可选,不影响处理状态。标签为“可以接话”或“继续等待”就计入已处理,只有空白标签(需要仲裁)算待处理。
- 时间轴下方“撤销上一步 / 重做上一步”支持最近 40 步转写、判断点和导入修改,Ctrl+Z 撤销,Ctrl+Y 或 Ctrl+Shift+Z 重做;Mac 也支持 ⌘+Z / ⌘+Shift+Z。在时间轴的块或判断点上聚焦时同样有效,文本输入框内保留原生文字撤销。撤销后作新修改会清空重做记录;刷新页面后历史记录清空,浏览器草稿仍按原规则恢复。
- 时间轴显示整段对话,模型输入仍仅使用
end_ms <= decision_ms的完整历史;当前用户表达跨越判断点时需回听填写user_text_at_decision,不按字符比例推算。 - 点击“保存到项目”写入
labels/EOT标注/工作数据/。切换数据集只改变浏览范围;导出菜单可选当前数据集或全部,项目保存保留全部数据。
浏览器草稿自动保留,刷新后可恢复。网页保存不覆盖原 XLSX、初稿和录音。初稿转换方法、标签映射与限制见 转换说明,原行号及原结论保留在初稿目录的 source_rows.json 中。原表没有时间信息,录音中未收录的开场与其他发言需人工补充。
模型分数对比
点击时间轴上方的“模型分数对比”展开对比,默认收起。VAP / MaAI(紫色)、Smart Turn(青色)、Silero VAD(橙色)、LiveKit v1-mini(蓝色)和 TurnSense 1.0(玫红色)共用录音的时间刻度、缩放、播放头及判断点参考线。点击或拖动曲线区域定位播放,悬停查看当时已产生的分数;点击空心评分点定位到判断时刻。顶部显示播放位置最近的有效评分,暂无评分时显示“—”,不将缺失数据当作 0。
新增橄榄绿色 VAP / MaAI(仅用户),在“选择模型”中勾选。它复用相同 MaAI ch_kyoto 权重,保留用户声道,将机器人输入全程置零;连续曲线约每 100 ms 更新,空心点取当前判断时刻之前最后可用的连续流评分。分数仍为 1 - p_now[user],可独立切换 0.11 / 0.5 / 0.8 参考线。原双声道版及页面播放录音保留;用户声道内已有的机器人串音不因此消失。当前流式结果位于 experiments/maai-ch-kyoto/results/streaming/cpc-user-only/,原始独立窗口结果保留在 results/user-only/,复现方式和同点双声道对照见仅用户评测说明。
另有 VAP / MaAI Mimi(标准双声道)(蓝灰色)和 VAP / MaAI Mimi(降噪双声道)(金棕色),均输入用户与机器人原双声道,使用 FP32 Mimi 编码器、12.5 Hz(80 ms)和 20 秒上下文;两版分别使用标准/降噪 VAP 权重。分数映射、独立开关及参考阈值与 CPC 版一致。当前流式结果分别位于 MaAI 目录的 results/streaming/mimi-standard/ 和 results/streaming/mimi-mc/;原独立窗口结果保留在 results/mimi-standard/ 和 results/mimi-mc/;复现、权重校验及比较边界见 Mimi 评测说明。
- 实线阶梯曲线来自对六通完整录音的真实推理,不是用44个点插值。MaAI每100ms输入一块音频,因流式重采样缓冲,部分评分间隔为200ms;Smart Turn每200ms计算一次,并包含原标注的精确时刻。
- MaAI使用双声道连续回放、20秒KV缓存,分数为
1 - p_now[user],是接话候选分数,不是校准的EOT概率。Smart Turn沿用原回测的用户声道、过去ASR定位、500ms前置音频、3秒内续说及最多8秒窗口;没有额外的结束信号、VAD停止门槛或超时放行。 - VAP 的四个配置统一按流式场景评估:连续处理完整录音并维护模型状态;判断点、悬停分数和准确率均取判断时刻之前最后可用的输出,不在判断点重置或插值。时间戳包含流式重采样缓冲;尚未输出或分数年龄超过两倍标称更新间隔时显示不可用,并单独计数,不补成 0。空心点应落在阶梯线上。Smart Turn 的原判断点仍保留独立窗口结果。
- Silero VAD 为用户声道逐个完整 32 ms 帧的真实 ONNX 推理,使用
1 - speech_probability,仅为非发声基线,不是语义 EOT 概率。时间戳为帧末;空心点取原判断时刻最后可用帧,不读取未来音频。独立环境和复现方法见 Silero 实验说明。 - 参考阈值只改变虚线位置,不修改人工标签。MaAI可选0.11、0.5、0.8,Smart Turn和Silero可选0.5、0.8。编辑不会重跑模型;新增或移动 VAP 判断点时,页面立即从已有连续曲线重新取点。磁盘上的统计需保存标注后运行下述流式评估命令更新。
- “选择模型”打开可搜索、按类型分组的多选面板,支持全选可用 / 清空;无评分模型保留在列表并说明状态。首次显示 VAP、Smart Turn、TurnSense 三条,之后记住显示选择和参考阈值,切换通话、收起和刷新均保留。紧凑图例只显示已选模型与当前分数,悬停或键盘聚焦会突出对应曲线。点击图例打开阈值和模型说明,可单独查看一个模型并恢复原选择。
- 仅在展开时读取当前项目录音的评分,并核对音频SHA256。更换为本地新录音、音频变化或没有对应推理数据时,不显示旧曲线。切换通话会取消旧请求,避免前一段数据覆盖当前段。
VAP 前端读取 MaAI 目录的 results/streaming/{cpc-stereo,cpc-user-only,mimi-standard,mimi-mc}/score-timeline.json;其他模型沿用各自的 results/score-timeline.json。仅更新当前标注对应的 VAP 流式取点和统计,无需重跑模型:
cd experiments/maai-ch-kyoto
uv run --locked python evaluate_streaming.py all
每点的 decision_ms、实际 score_time_ms 和 score_age_ms 记录在各配置 predictions.csv,四版汇总见 results/streaming/comparison-summary.json 和 对比分析.txt。MaAI 的 export_timeline.py、run_user_only.py all、run_mimi.py all 在重新生成连续推理后也会刷新对应配置的流式结果。原独立窗口文件保留作为另一评估口径的历史记录。
如需重新生成连续推理,在两个各自的本机 uv 环境中运行:
cd experiments/maai-ch-kyoto
uv run --locked python export_timeline.py
cd ../smart-turn-v3.2
uv run --locked python export_timeline.py
上述命令从项目根目录开始;生成脚本只读取录音及已有回测资料,不改人工标注。时间戳表示该评分输入已收到的时刻,MaAI使用流式重采样并计入其缓冲;Smart Turn先裁取过去音频再重采样,均不读取判断时刻之后的音频。
CSV 格式
对话转写 asr_history.csv:
call_id,role,start_ms,end_ms,transcript
demo,agent,1000,2400,您什么时候方便接电话?
demo,user,3000,4400,我明天下午
EOT 标注 eot_labels.csv:
call_id,decision_ms,user_text_at_decision,can_reply_now,confidence,reason,annotator
demo,5200,我明天下午,0,high,mid_turn_pause,A
role 为 agent 或 user;can_reply_now 为 1、0 或空;confidence 为 high、medium、low 或空。时间为非负整数毫秒,转写满足 start_ms < end_ms。同一 call_id + decision_ms 不能重复。CSV 使用 UTF-8,支持标准引号、逗号和多行文本。
全部对话保存在转写表,当前用户表达保存在 EOT 表。查看或预测时以通话 ID 和判断时间关联这两份文件;空标签保留为待判断样本。
本地接口
GET /api/workspace:读取工作数据和项目录音列表。工作数据的两份 CSV 都存在时使用它们,否则载入韩泰初稿;初稿不存在时载入示例;已保存 CSV 格式错误时返回错误,不用示例覆盖。GET /api/model-scores?callId=...&recordingPath=...:只读固定实验目录的已验证评分,按通话ID和项目录音路径精确匹配,并核对实际音频SHA256。缺少某模型时保留另一模型;未匹配或过期的评分不返回曲线。POST /api/workspace:接受{ transcripts, annotations },校验后保存到固定工作数据目录,并返回savedAt。同一进程的读写按顺序执行;文件锁防止不同进程同时操作,请求完成后释放。若进程在保存中被强制终止,请确认没有其他服务运行,检查残留.backup文件并恢复同一次保存前的两份 CSV,再移除工作数据目录的.workspace.lock。GET /api/audio?path=...:仅提供data内的 MP3、WAV、M4A、OGG、FLAC 和 WebM 录音,支持 Range 请求和 HEAD,便于跳转播放。路径相对data目录,不能通过..或符号链接访问目录之外的文件。
录音 call_id 默认取文件名去除扩展名后的部分;同一通话有多个项目录音时,默认使用发现的第一条,可点击“更换录音”重新关联本地文件。
LiveKit v1-mini
新增蓝色 LiveKit v1-mini 曲线,默认显示、每 200 ms 更新,并包含 44 个判断点的精确分数。只接收判断前的用户声道,16 kHz 最近 1.2 秒音频。参考阈值默认采用锁定 SDK 的中文阈值 0.355,可切换 0.5 / 0.8。它通过 LiveKit Agents 本地推理入口运行,不加服务层 VAD 门槛、静音等待或超时;不将这些曲线称为完整在线策略表现。模型许可与复现说明见 实验说明。
TurnSense 1.0 FP32
玫红色曲线为真实 ONNX 推理的 P(complete),每 200 ms 及原判断点精确时刻更新。输入仅为判断前的用户左声道,重采样到 16 kHz 后取最近 8 秒;官方前端/CMVN不改动。支持独立开关和 0.5 / 0.8 参考线。原生输出为 complete/incomplete/invalid 三分类,完整三项概率保存在实验 predictions.csv,原生 argmax complete 映射为可接话;网页 0.5 参考线不是原生 argmax 的等价规则。复现和评估结果见 TurnSense 实验说明。