新增 Silero VAD 时间轴评分对比与可复现推理

This commit is contained in:
Xin Wang
2026-10-22 21:25:47 +08:00
parent 43724c13e4
commit c9b618e634
14 changed files with 379 additions and 14 deletions
+6 -6
View File
@@ -90,8 +90,8 @@ export default function Timeline({
const helpId = useId();
const scoreRegionId = useId();
const [scoresOpen, setScoresOpen] = useState(false);
const [thresholds, setThresholds] = useState<ScoreThresholds>({ maai: .5, smart_turn: .5 });
const [scoreVisibility, setScoreVisibility] = useState<ScoreVisibility>({ maai: true, smart_turn: true });
const [thresholds, setThresholds] = useState<ScoreThresholds>({ maai: .5, smart_turn: .5, silero_vad: .5 });
const [scoreVisibility, setScoreVisibility] = useState<ScoreVisibility>({ maai: true, smart_turn: true, silero_vad: true });
const scores = useModelScores(callId, recordingPath, scoresOpen);
const visibleScores = useMemo(() => scores.series.filter(row => scoreVisibility[row.model]), [scores.series, scoreVisibility]);
const viewportRef = useRef<HTMLDivElement>(null);
@@ -336,7 +336,7 @@ export default function Timeline({
<button type="button" className={styles.scoreToggle} aria-expanded={scoresOpen} aria-controls={scoreRegionId}
onClick={() => setScoresOpen(value => !value)}>
<span aria-hidden="true" className={scoresOpen ? styles.chevronOpen : styles.chevron}>›</span>
<strong>模型 EOT 分数</strong><span>{scoresOpen ? "收起" : "展开 MaAI / Smart Turn 对比"}</span>
<strong>模型分数对比</strong><span>{scoresOpen ? "收起" : "展开 VAP / Smart Turn / Silero VAD 对比"}</span>
</button>
{scoresOpen && <ScoreControls series={scores.series} currentMs={current}
visibility={scoreVisibility} onVisibility={(model, visible) => setScoreVisibility(previous => ({ ...previous, [model]: visible }))}
@@ -344,7 +344,7 @@ export default function Timeline({
</div>
{scoresOpen && <div className={styles.scoreDescription} role="status">
{scores.status === "loading" ? "正在读取模型分数…" : scores.status === "error" ? <>{scores.messages.join(" ")} <button type="button" onClick={scores.retry}>重新读取</button></>
: <>实线:连续回放评分 · 空心点:原标注点评分 · 虚线:参考阈值。分数越高越倾向接话,MaAI 使用 1 − 用户近期发声分数。{scores.messages.join(" ")}</>}
: <>实线:连续回放评分 · 空心点:原标注点评分 · 虚线:参考阈值。Smart Turn 表示完成倾向;VAP 使用 1 − 用户近期发声分数,Silero 使用 1 − 当前发声分数,仅为非发声基线,不是语义 EOT 概率。{scores.messages.join(" ")}</>}
</div>}
<div className={styles.trackLayout}>
@@ -354,7 +354,7 @@ export default function Timeline({
<div className={styles.speechName}><span className={styles.agentDot} />机器人</div>
<div className={styles.speechName}><span className={styles.userDot} />用户</div>
<div className={styles.markerName}>判断点</div>
{scoresOpen && <div className={styles.scoreAxis} style={{ height: SCORE_HEIGHT }}><span>1.0</span><span>接话分数</span><span>0.0</span></div>}
{scoresOpen && <div className={styles.scoreAxis} style={{ height: SCORE_HEIGHT }}><span>1.0</span><span>对比分数</span><span>0.0</span></div>}
</div>
<div className={styles.viewport} ref={viewportRef}>
<div
@@ -473,7 +473,7 @@ export default function Timeline({
</div>
</div>
{scoresOpen && scores.series.length > 0 && <p className={styles.scoreFootnote}>点击曲线定位录音;悬停查看分数。MaAI 约每 100 ms、Smart Turn 每 200 ms 更新。原标注点评分使用独立历史窗口,与连续曲线可能不同;编辑标注或转写不会重算已有分数。</p>}
{scoresOpen && scores.series.length > 0 && <p className={styles.scoreFootnote}>点击曲线定位录音;悬停查看分数。VAP 约每 100 ms、Smart Turn 每 200 ms、Silero 每 32 ms 更新。Silero 空心点取判断前最后完整帧;其他模型原标注点评分使用独立历史窗口,与连续曲线可能不同;编辑标注或转写不会重算已有分数。</p>}
<div className={styles.bottomBar}>
<div className={styles.timeReadout}><span className={styles.playheadDot} /> 播放 <strong>{timeLabel(current, true)}</strong></div>