新增 Mimi 与仅用户 VAP 对比并统一流式评测
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useMemo, useRef, useState, useId } from "react";
|
||||
import { scoreAt, scorePath, type ModelId, type ScoreResponse, type ScoreSeries } from "@/lib/model-scores";
|
||||
import { checkpointsForDisplay, scoreAt, scorePath, type ModelId, type ScoreResponse, type ScoreSeries } from "@/lib/model-scores";
|
||||
import { createPortal } from "react-dom";
|
||||
import { SCORE_MODELS, SCORE_MODEL_IDS, readScorePreferences } from "@/lib/score-models";
|
||||
import type { TimelineAnnotation } from "./timeline";
|
||||
@@ -169,7 +169,8 @@ export default function ModelScoreTrack({ series, width, durationMs, currentMs,
|
||||
}) {
|
||||
const [hoverMs, setHoverMs] = useState<number | null>(null);
|
||||
const paths = useMemo(() => series.map(row => ({ ...row,
|
||||
path: scorePath(row.points, durationMs, width, SCORE_HEIGHT, row.sample_interval_ms) })), [series, durationMs, width]);
|
||||
checkpoints: checkpointsForDisplay(row, annotations.map(annotation => annotation.decision_ms)),
|
||||
path: scorePath(row.points, durationMs, width, SCORE_HEIGHT, row.sample_interval_ms) })), [series, annotations, durationMs, width]);
|
||||
const y = (p: number) => 12 + (1 - p) * (SCORE_HEIGHT - 24);
|
||||
const x = (ms: number) => ms / durationMs * width;
|
||||
const inspect = hoverMs ?? currentMs;
|
||||
@@ -180,7 +181,7 @@ export default function ModelScoreTrack({ series, width, durationMs, currentMs,
|
||||
};
|
||||
return <div className={styles.scoreTrack} onPointerLeave={() => setHoverMs(null)}>
|
||||
<svg width={width} height={SCORE_HEIGHT} viewBox={`0 0 ${width} ${SCORE_HEIGHT}`}
|
||||
role="group" aria-label="VAP、Smart Turn、Silero VAD、LiveKit v1-mini 与 TurnSense 分数对比,纵轴 0 到 1,横轴与录音时间一致"
|
||||
role="group" aria-label="VAP CPC 双声道与仅用户版本、Mimi 标准与降噪双声道、Smart Turn、Silero VAD、LiveKit v1-mini 与 TurnSense 分数对比,纵轴 0 到 1,横轴与录音时间一致"
|
||||
onPointerMove={event => {
|
||||
const bounds = event.currentTarget.getBoundingClientRect();
|
||||
setHoverMs(Math.max(0, Math.min(durationMs, (event.clientX - bounds.left) / bounds.width * durationMs)));
|
||||
@@ -194,12 +195,12 @@ export default function ModelScoreTrack({ series, width, durationMs, currentMs,
|
||||
<path d={row.path} fill="none" stroke={COLORS[row.model]} strokeWidth={focusedModel === row.model ? 2.8 : 1.6} strokeLinejoin="round" pointerEvents="none" />
|
||||
{row.checkpoints.map(([ms, score]) => <circle key={ms} cx={x(ms)} cy={y(score)} r={3.8}
|
||||
fill="#fffefb" stroke={COLORS[row.model]} strokeWidth={1.8} tabIndex={0} role="button"
|
||||
aria-label={`${row.name} 原标注点评分 ${time(ms)},${score.toFixed(3)},点击定位`}
|
||||
aria-label={`${row.name} ${row.checkpoint_mode === "streaming" ? "流式判断点" : "原标注点评分"} ${time(ms)},${score.toFixed(3)},点击定位`}
|
||||
onPointerDown={event => event.stopPropagation()}
|
||||
onClick={event => { event.stopPropagation(); selectPoint(ms); }}
|
||||
onKeyDown={event => {
|
||||
if (event.key === "Enter" || event.key === " ") { event.preventDefault(); event.stopPropagation(); selectPoint(ms); }
|
||||
}}><title>{row.name} · 原标注点评分 {score.toFixed(3)} · {time(ms)}</title></circle>)}
|
||||
}}><title>{row.name} · {row.checkpoint_mode === "streaming" ? "流式判断点" : "原标注点评分"} {score.toFixed(3)} · {time(ms)}{row.checkpoint_mode === "streaming" ? ` · 最近更新 ${time(scoreAt(row.points, ms, row.sample_interval_ms * 2)![0])}` : ""}</title></circle>)}
|
||||
</g>)}
|
||||
{hoverMs !== null && <line x1={x(hoverMs)} x2={x(hoverMs)} y1={0} y2={SCORE_HEIGHT} stroke="#77816c" opacity=".5" pointerEvents="none" />}
|
||||
</svg>
|
||||
|
||||
@@ -345,7 +345,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></>
|
||||
: <>实线:连续回放评分 · 空心点:原标注点评分 · 虚线:参考阈值。Smart Turn、LiveKit 表示完成倾向,TurnSense 为 P(complete);VAP 使用 1 − 用户近期发声分数,Silero 使用 1 − 当前发声分数,仅为非发声基线,不是语义 EOT 概率。{scores.messages.join(" ")}</>}
|
||||
: <>实线:连续回放评分 · 空心点:判断时评分(VAP 为流式取点) · 虚线:参考阈值。Smart Turn、LiveKit 表示完成倾向,TurnSense 为 P(complete);VAP 使用 1 − 用户近期发声分数,Silero 使用 1 − 当前发声分数,仅为非发声基线,不是语义 EOT 概率。{scores.messages.join(" ")}</>}
|
||||
</div>}
|
||||
|
||||
<div className={styles.trackLayout}>
|
||||
@@ -474,7 +474,7 @@ export default function Timeline({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{scoresOpen && scores.series.length > 0 && <p className={styles.scoreFootnote}>点击曲线定位录音;悬停查看分数。VAP 约每 100 ms、Smart Turn 每 200 ms、Silero 每 32 ms、LiveKit、TurnSense 每 200 ms 更新。TurnSense 使用过去 8 秒用户音频;LiveKit 使用过去 1.2 秒用户音频,中文参考阈值 0.355;Silero 空心点取判断前最后完整帧;VAP 和 Smart Turn 原标注点评分使用独立历史窗口,与连续曲线可能不同;TurnSense 的 0.5 参考线不等同于原生三分类取最大值规则;编辑标注或转写不会重算已有分数。</p>}
|
||||
{scoresOpen && scores.series.length > 0 && <p className={styles.scoreFootnote}>点击曲线定位录音;悬停查看分数。VAP CPC 约每 100 ms,Mimi 标准与降噪版约每 80 ms;Smart Turn 每 200 ms、Silero 每 32 ms、LiveKit、TurnSense 每 200 ms 更新。原 VAP 为 CPC 降噪双声道,“仅用户”版将机器人输入全程置为静音;Mimi 两版均输入用户和机器人双声道,20 秒上下文。回放仍为原录音。TurnSense 使用过去 8 秒用户音频;LiveKit 使用过去 1.2 秒用户音频,中文参考阈值 0.355;Silero 空心点取判断前最后完整帧;VAP 各版本圆点与悬停分数均取判断前最后可用的连续流评分,圆点应落在对应阶梯曲线上;Smart Turn 的原判断点仍为独立窗口结果;TurnSense 的 0.5 参考线不等同于原生三分类取最大值规则;编辑标注或转写不会重跑模型;VAP 圆点随当前判断位置从连续曲线重新取点。</p>}
|
||||
|
||||
<div className={styles.bottomBar}>
|
||||
<div className={styles.timeReadout}><span className={styles.playheadDot} /> 播放 <strong>{timeLabel(current, true)}</strong></div>
|
||||
|
||||
Reference in New Issue
Block a user