Delegate wearer boundary semantics to review

This commit is contained in:
Xin Wang
2026-09-15 02:12:18 +08:00
parent 71dfd8808a
commit 3a127a3f9f
12 changed files with 596 additions and 404 deletions
+18 -5
View File
@@ -57,13 +57,23 @@ const decisionMeanings = {
INT_WEARER_HOLDS_FLOOR: "Other 不是单纯 backchannel,且 wearer 在重叠后明确继续或恢复原 turn。",
OTHER_HARD_NEGATIVE: "这是可解释的困难负例,但不符合任何命名子类型;不能用于替代 Exclude。",
EXCLUDE: "该区域是无需参评的非目标事件,或存在证据/数据问题,不进入评分。",
OUT_OF_SCOPE_NORMAL_COMPLETION: "有效语境中的自然结束,不是 interruption yield。",
OUT_OF_SCOPE_WITHIN_TURN_CONTINUATION: "这是同一 wearer turn 内的暂停或继续,不是新的 floor event。",
OUT_OF_SCOPE_POST_COMPLETION_ACTIVITY: "Other 在 wearer 已结束后才开始,不能构成导致停止的 takeover。",
OUT_OF_SCOPE_NON_EVENT: "数据有效且可解释,但该边界不属于目标行为。",
INSUFFICIENT_EVIDENCE: "数据未显示明确损坏,但现有证据不足以可靠确定 conversational function。",
DATA_ANNOTATION_ERROR: "参与者、语音、转写或 target 标注明显错误或互相矛盾。",
DATA_RECORDING_BOUNDARY: "录制或 clip 边界使该事件无法可靠解释。",
DATA_MISSING_CONTEXT: "判断所需上下文未被提供。",
DATA_NON_SPEECH_ARTIFACT: "候选由非语音伪影造成。",
DATA_TIMESTAMP_CORRUPTION: "时间戳损坏或无法对齐。",
};
const currentAiVerdicts = new Set(["POSITIVE", "HARD_NEGATIVE", "EXCLUDE"]);
function suggestionView(suggestion) {
const verdict = suggestion.verdict || suggestion.protocol_disposition || "—";
const label = suggestion.event_type || suggestion.subtype || suggestion.hard_negative_type || verdict;
const label = suggestion.event_type || suggestion.subtype || suggestion.exclude_reason || suggestion.hard_negative_type || verdict;
const rawConfidence = suggestion.confidence ?? suggestion.final_confidence;
const numericConfidence = Number(rawConfidence);
const confidence = Number.isFinite(numericConfidence)
@@ -170,7 +180,7 @@ function applyFilters({ keepCurrent = true } = {}) {
(elements.splitFilter.value === "all" || item.split === elements.splitFilter.value) &&
(elements.familyFilter.value === "all" || item.family === elements.familyFilter.value) &&
(status === "all" || (status === "reviewed" ? reviewed : !reviewed)) &&
(!search || `${item.uid} ${item.candidate_source || ""} ${item.rule_candidate_type || ""} ${item.ai_verdict || ""} ${item.ai_event_type || ""} ${item.ai_subtype || ""} ${item.session}`.toLowerCase().includes(search))
(!search || `${item.uid} ${item.candidate_source || ""} ${item.rule_candidate_type || ""} ${item.ai_verdict || ""} ${item.ai_event_type || ""} ${item.ai_subtype || ""} ${item.ai_exclude_reason || ""} ${item.session}`.toLowerCase().includes(search))
);
});
renderQueue();
@@ -206,7 +216,7 @@ function renderQueue() {
const label = document.createElement("div");
label.className = "queue-label";
label.textContent = item.ai_verdict
? `AI ${item.ai_verdict} · ${item.ai_event_type || item.ai_subtype || "—"}`
? `AI ${item.ai_verdict} · ${item.ai_event_type || item.ai_subtype || item.ai_exclude_reason || "—"}`
: `${item.rule_candidate_type || item.automatic_label} · 待 AI 粗标`;
button.append(line, meta, label);
button.addEventListener("click", () => selectCandidate(item.candidate_id));
@@ -292,7 +302,8 @@ function renderDetail(detail) {
const familyPrefix = detail.family === "entry" ? "ENTRY_" : detail.family === "int" ? "INT_" : null;
const canAccept = currentAiVerdicts.has(view.verdict)
&& (view.verdict !== "POSITIVE" || !familyEvent || suggestion.event_type === familyEvent)
&& (view.verdict !== "HARD_NEGATIVE" || !familyPrefix || suggestion.subtype === "OTHER_HARD_NEGATIVE" || String(suggestion.subtype || "").startsWith(familyPrefix));
&& (view.verdict !== "HARD_NEGATIVE" || !familyPrefix || suggestion.subtype === "OTHER_HARD_NEGATIVE" || String(suggestion.subtype || "").startsWith(familyPrefix))
&& (view.verdict !== "EXCLUDE" || Boolean(suggestion.exclude_reason));
elements.acceptRadio.disabled = !canAccept;
elements.acceptTitle.textContent = canAccept
? `接受 ${view.verdict.replaceAll("_", " ")}`
@@ -302,7 +313,9 @@ function renderDetail(detail) {
const anchorText = selectedOption ? ` · trigger ${formatTime(selectedOption.anchor_seconds)} P${selectedOption.participant_id}` : "";
elements.acceptSummary.textContent = canAccept
? `${view.label}${anchorText} · ${view.meaning}`
: "该标签已移除,请改标为正例/硬负例,或选择 Exclude。";
: (view.verdict === "EXCLUDE"
? "旧 AI EXCLUDE 没有 reason taxonomy,请选择 Exclude 并补充原因。"
: "该标签已移除,请改标为正例/硬负例,或选择 Exclude。");
} else {
elements.acceptRadio.disabled = true;
elements.acceptTitle.textContent = "没有 AI 结论";
+1 -1
View File
@@ -88,7 +88,7 @@
<label id="subtypeField" hidden><span>Hard-negative subtype</span><select name="human_subtype"><option value="">请选择</option><option>ENTRY_OTHER_MIDTURN_PAUSE</option><option>ENTRY_OTHER_TO_OTHER</option><option>ENTRY_WEARER_BACKCHANNEL</option><option>INT_OTHER_BACKCHANNEL</option><option>INT_NON_TAKEOVER_OVERLAP</option><option>INT_WEARER_HOLDS_FLOOR</option><option>OTHER_HARD_NEGATIVE</option></select></label>
</section>
<section id="excludeFields" class="conditional-fields" hidden><label><span>排除原因</span><select name="exclude_reason"><option value="">请选择</option><option value="OUT_OF_SCOPE_NORMAL_COMPLETION">OUT_OF_SCOPE_NORMAL_COMPLETION — wearer 正常说完</option><option value="OUT_OF_SCOPE_NON_EVENT">OUT_OF_SCOPE_NON_EVENT — 其他无需参评事件</option><option>ANNOTATION_ERROR</option><option>RECORDING_BOUNDARY</option><option>MISSING_CONTEXT</option><option>NON_SPEECH_ARTIFACT</option><option>TIMESTAMP_CORRUPTION</option><option>UNRESOLVABLE</option></select></label></section>
<section id="excludeFields" class="conditional-fields" hidden><label><span>排除原因(分类统计)</span><select name="exclude_reason"><option value="">请选择</option><optgroup label="OUT OF SCOPE — 数据有效但不是目标行为"><option value="OUT_OF_SCOPE_NORMAL_COMPLETION">正常说完,没有 INT yield</option><option value="OUT_OF_SCOPE_WITHIN_TURN_CONTINUATION">同一 wearer turn 内暂停/续说</option><option value="OUT_OF_SCOPE_POST_COMPLETION_ACTIVITY">Other 在 wearer 结束后才开始</option><option value="OUT_OF_SCOPE_NON_EVENT">其他明确的非目标事件</option></optgroup><optgroup label="INSUFFICIENT EVIDENCE — 数据未坏但语义无法确定"><option value="INSUFFICIENT_EVIDENCE">现有证据不足以可靠判断</option></optgroup><optgroup label="DATA QUALITY — 数据或边界不可用"><option value="DATA_ANNOTATION_ERROR">标注明显错误或矛盾</option><option value="DATA_RECORDING_BOUNDARY">录制/clip 边界截断语境</option><option value="DATA_MISSING_CONTEXT">所需上下文缺失</option><option value="DATA_NON_SPEECH_ARTIFACT">非语音伪影</option><option value="DATA_TIMESTAMP_CORRUPTION">时间戳损坏或错位</option></optgroup></select></label></section>
<details class="boundary-details"><summary>仅在原 annotation 明显错误时校正边界</summary><label><span>可选校正(原时间始终保留)</span><select name="boundary_correction_seconds"><option value="">不校正</option><option value="-0.2">−0.2 s</option><option value="0.2">+0.2 s</option></select></label></details>