新增 Mimi 与仅用户 VAP 对比并统一流式评测

This commit is contained in:
Xin Wang
2026-10-28 22:44:36 +08:00
parent 19d4e3c767
commit 6785e3a07b
55 changed files with 6160 additions and 31 deletions
@@ -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>