2026-09-14 16:29:25 +08:00
<!doctype html>
< html lang = "zh-CN" >
2026-09-14 18:43:58 +08:00
< head >
< meta charset = "utf-8" />
< meta name = "viewport" content = "width=device-width, initial-scale=1" />
2026-09-15 13:23:59 +08:00
< title > Egocentric Floor Event Review</ title >
2026-09-14 18:43:58 +08:00
< link rel = "stylesheet" href = "/app.css" />
</ head >
< body >
< header class = "topbar" >
2026-09-15 13:23:59 +08:00
< div class = "brand" >< span class = "brand-mark" ></ span >< div >< h1 > Floor Event Review</ h1 >< p > EasyCom / Ego4D AV · AI 粗标注 → 人工确认</ p ></ div ></ div >
2026-09-14 18:43:58 +08:00
< div class = "progress-block" >< div class = "progress-copy" >< strong id = "progressText" > 载入中</ strong >< span id = "progressMeta" > —</ span ></ div >< div class = "progress-track" >< span id = "progressBar" ></ span ></ div ></ div >
< nav class = "export-actions" >< a href = "/api/export.jsonl" download > 导出 JSONL</ a >< a href = "/api/export.csv" download > 导出 CSV</ a ></ nav >
</ header >
2026-09-14 16:29:25 +08:00
2026-09-14 18:43:58 +08:00
< section class = "filters" aria-label = "候选筛选" >
< label >< span > Session</ span >< select id = "sessionFilter" >< option value = "all" > 全部</ option ></ select ></ label >
2026-09-15 13:23:59 +08:00
< label >< span > Split</ span >< select id = "splitFilter" >< option value = "all" > 全部</ option >< option value = "train" > train</ option >< option value = "val" > val</ option >< option value = "test" > test</ option ></ select ></ label >
2026-09-15 01:25:39 +08:00
< label >< span > 任务</ span >< select id = "familyFilter" >< option value = "all" > 全部</ option >< option value = "entry" > WEARER ENTRY</ option >< option value = "int" > INT / YIELD</ option ></ select ></ label >
2026-09-14 18:43:58 +08:00
< label >< span > 审核状态</ span >< select id = "statusFilter" >< option value = "unreviewed" > 未审核</ option >< option value = "all" > 全部</ option >< option value = "reviewed" > 已审核</ option ></ select ></ label >
< label class = "search-field" >< span > 搜索</ span >< input id = "searchFilter" type = "search" placeholder = "事件来源、AI 标签、session" /></ label >
< button id = "clearFilters" class = "button ghost" type = "button" > 清除筛选</ button >
</ section >
2026-09-14 16:29:25 +08:00
2026-09-14 18:43:58 +08:00
< main class = "workspace" >
< aside class = "queue-panel panel" >
< div class = "panel-heading" >< div >< span class = "eyebrow" > QUEUE</ span >< h2 id = "queueTitle" > 待审核</ h2 ></ div >< span id = "queueCount" class = "count-pill" > 0</ span ></ div >
< div id = "queueList" class = "queue-list" ></ div >< p id = "queueLimit" class = "queue-limit" hidden ></ p >
</ aside >
2026-09-14 16:29:25 +08:00
2026-09-14 18:43:58 +08:00
< section class = "evidence-panel panel" >
2026-09-14 23:04:21 +08:00
< div class = "event-header" >< div >< div class = "event-badges" >< span id = "familyBadge" class = "badge accent" > —</ span >< span id = "splitBadge" class = "badge" > —</ span ></ div >< h2 id = "eventTitle" > 请选择候选</ h2 >< p id = "eventSubtitle" > —</ p ></ div >< div class = "event-position" >< strong id = "eventPosition" > 0 / 0</ strong ></ div ></ div >
2026-09-14 16:29:25 +08:00
2026-09-14 23:04:21 +08:00
< section class = "decision-guide" aria-label = "当前审核目标" >
< div class = "review-question" >< span > 本条需要判断</ span >< strong id = "reviewQuestion" > —</ strong ></ div >
< div id = "llmSuggestion" class = "ai-decision-card" hidden >
< div class = "ai-decision-heading" >< span >< i ></ i > AI 建议</ span >< em id = "aiConfidence" > 置信度 —</ em ></ div >
< div class = "ai-decision-main" >
< strong id = "aiVerdict" class = "ai-verdict" > —</ strong >
< span class = "decision-arrow" > →</ span >
< div >< b id = "aiLabel" > —</ b >< p id = "aiMeaning" > —</ p ></ div >
</ div >
< div class = "ai-rationale" >< span > 判断依据</ span >< p id = "aiRationale" > —</ p ></ div >
</ div >
2026-09-14 16:29:25 +08:00
</ section >
2026-09-14 23:04:21 +08:00
< section class = "timeline-section" >
< details class = "session-overview-details" >
< summary >< span >< b > Session overview</ b >< small > 全局候选与说话活动</ small ></ span >< em > 按需展开</ em ></ summary >
< div class = "session-overview-body" >
< div class = "section-heading timeline-heading" >< div >< span class = "eyebrow" > SESSION OVERVIEW</ span >< h3 > 本 Session 候选分布</ h3 ></ div >< div class = "timeline-controls" aria-label = "时间轴缩放" >< button id = "timelinePanLeft" type = "button" title = "向前平移" > ←</ button >< button id = "timelineZoomOut" type = "button" title = "缩小" > − </ button >< button id = "timelineFocus" type = "button" title = "聚焦当前事件" > 聚焦</ button >< button id = "timelineZoomIn" type = "button" title = "放大" > + </ button >< button id = "timelinePanRight" type = "button" title = "向后平移" > →</ button >< button id = "timelineReset" type = "button" title = "显示完整 Session" > 全局</ button ></ div ></ div >
< div class = "timeline-readout" >< strong id = "timelineZoomLabel" > 8× </ strong >< span id = "timelineRange" > —</ span >< small > marker 跳转 · Shift + 滚轮缩放</ small ></ div >
< div id = "sessionTimeline" class = "session-timeline" ></ div >
</ div >
</ details >
< div class = "section-heading local-heading" >< div >< span class = "eyebrow" > LOCAL SPEAKER ACTIVITY</ span >< h3 > 事件附近 participant timeline</ h3 ></ div >< span > W = wearer · P# = Participant_ID</ span ></ div >
< div id = "speakerTimeline" class = "speaker-timeline" ></ div >
< div id = "speakerEvidence" class = "speaker-evidence" aria-live = "polite" >< span > 悬停或点击任意 activity 区段,转写会固定显示在这里。</ span ></ div >
</ section >
2026-09-14 18:43:58 +08:00
2026-09-14 23:04:21 +08:00
< div class = "evidence-grid" >
< div class = "media-column" >
< div class = "video-shell" >< video id = "eventVideo" controls preload = "metadata" ></ video >< div id = "mediaEmpty" class = "empty-state" hidden >< strong > 未找到视频</ strong >< span > 检查 dataset root 与 clip。</ span ></ div ></ div >
< div class = "transport" >< button type = "button" data-seek = "-2" > − 2 s</ button >< button type = "button" data-seek = "-0.2" > − 0.2 s</ button >< button id = "jumpEvent" class = "jump-event" type = "button" > 事件点</ button >< button type = "button" data-seek = "0.2" > +0.2 s</ button >< button type = "button" data-seek = "2" > +2 s</ button >< span id = "timeReadout" > —</ span ></ div >
</ div >
< div class = "transcript-column" >
< section class = "transcript-section" >< div class = "section-heading" >< div >< span class = "eyebrow" > TRANSCRIPT</ span >< h3 > 事件上下文</ h3 ></ div >< span id = "clipLabel" > —</ span ></ div >< div id = "transcriptList" class = "transcript-list" >< div class = "empty-copy" > 选择事件后显示 transcript。</ div ></ div ></ section >
< details class = "raw-details" >< summary > Structured timing / 原始候选</ summary >< pre id = "rawCandidate" > {}</ pre ></ details >
</ div >
</ div >
2026-09-14 18:43:58 +08:00
</ section >
< aside class = "review-panel panel" >
2026-09-14 23:04:21 +08:00
< div class = "panel-heading review-heading" >< div >< span class = "eyebrow" > HUMAN REVIEW</ span >< h2 > 选择你的操作</ h2 ></ div >< span id = "saveState" class = "save-state" > 未保存</ span ></ div >
2026-09-14 18:43:58 +08:00
< form id = "reviewForm" >
2026-09-14 23:04:21 +08:00
< fieldset >< legend > AI 建议正确就接受,否则改标 < span class = "required" > 必填</ span ></ legend >
2026-09-14 18:43:58 +08:00
< div class = "choice-grid two action-grid" >
2026-09-14 23:04:21 +08:00
< label class = "accept-option" >< input id = "acceptRadio" type = "radio" name = "human_action" value = "accept" />< span >< em > AI 建议</ em >< b id = "acceptTitle" > 接受 AI 结论</ b >< small id = "acceptSummary" > 载入候选后显示具体标签</ small ></ span ></ label >
2026-09-14 18:43:58 +08:00
< label >< input type = "radio" name = "human_action" value = "relabel" />< span >< b > Relabel</ b >< small > 展开并选择正确标签</ small ></ span ></ label >
2026-09-15 01:25:39 +08:00
< label >< input type = "radio" name = "human_action" value = "exclude" />< span >< b > Exclude</ b >< small > 非目标事件或不可可靠评分</ small ></ span ></ label >
2026-09-14 16:29:25 +08:00
</ div >
2026-09-14 18:43:58 +08:00
</ fieldset >
2026-09-14 16:29:25 +08:00
2026-09-14 18:43:58 +08:00
< section id = "relabelFields" class = "conditional-fields" hidden >
2026-09-15 01:25:39 +08:00
< label >< span > 一级 verdict</ span >< select name = "human_verdict" >< option value = "" > 请选择</ option >< option > POSITIVE</ option >< option > HARD_NEGATIVE</ option ></ select ></ label >
< label id = "eventTypeField" hidden >< span > Positive event</ span >< select name = "human_event_type" >< option value = "" > 请选择</ option >< option > WEARER_ENTRY</ option >< option > INT_YIELD</ option ></ select ></ label >
< label id = "opportunityField" hidden >< span > 前序 release(可选 metadata) </ span >< select id = "opportunitySelect" name = "selected_opportunity_uid" >< option value = "" > 无/不确定</ option ></ select ></ label >
< 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 >
2026-09-14 18:43:58 +08:00
</ section >
2026-09-14 16:29:25 +08:00
2026-09-15 11:41:13 +08:00
< 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_WEARER_BACKCHANNEL_OFFSET" > Wearer backchannel 的尾边界,不重复计 INT</ 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 >
2026-09-14 16:29:25 +08:00
2026-09-14 18:43:58 +08:00
< 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 >
2026-09-14 16:29:25 +08:00
2026-09-14 23:04:21 +08:00
< label class = "confidence-field" >< span > 置信度</ span >< select name = "confidence" >< option value = "high" > 高</ option >< option value = "medium" selected > 中</ option >< option value = "low" > 低</ option ></ select ></ label >
< details class = "optional-details" >< summary > 备注(可选)</ summary >< label class = "text-field" >< textarea name = "notes" maxlength = "4000" rows = "2" placeholder = "只记录必要的歧义或证据" ></ textarea ></ label ></ details >
2026-09-14 18:43:58 +08:00
< div id = "formError" class = "form-error" role = "alert" hidden ></ div >
2026-09-14 23:04:21 +08:00
< div class = "review-actions" >< button id = "saveButton" class = "button primary" type = "submit" > 保存并看下一个 < kbd > ⌘↵</ kbd ></ button ></ div >
2026-09-14 18:43:58 +08:00
</ form >
< div class = "shortcuts" >< span >< kbd > ←</ kbd >< kbd > →</ kbd > 前后事件</ span >< span >< kbd > [</ kbd >< kbd > ]</ kbd > ±200 ms</ span >< span >< kbd > Space</ kbd > 播放/暂停</ span ></ div >
</ aside >
</ main >
< div id = "toast" class = "toast" role = "status" ></ div >< script src = "/app.js" defer ></ script >
</ body >
2026-09-14 16:29:25 +08:00
</ html >