Delegate wearer boundary semantics to review
This commit is contained in:
+23
-12
@@ -27,6 +27,9 @@ from threading import Lock
|
||||
from typing import Any, Iterable
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
from easycom_event_taxonomy import (
|
||||
EXCLUDE_REASONS, LEGACY_EXCLUDE_REASONS, exclude_reason_group,
|
||||
)
|
||||
from prepare_easycom_eot_int_review import requires_semantic_adjudication
|
||||
|
||||
|
||||
@@ -34,7 +37,7 @@ SOURCE_FPS = 20.0
|
||||
STATIC_ROOT = Path(__file__).resolve().parent / "floor_event_review_web"
|
||||
VIDEO_ROOT_PARTS = ("Main", "Video_Compressed")
|
||||
TRANSCRIPT_ROOT_PARTS = ("Main", "Speech_Transcriptions")
|
||||
REVIEW_SCHEMA_VERSION = 5
|
||||
REVIEW_SCHEMA_VERSION = 6
|
||||
MAX_REQUEST_BYTES = 128 * 1024
|
||||
|
||||
PROTOCOL_DISPOSITION_VALUES = {"positive", "hard_negative", "exclude"}
|
||||
@@ -71,11 +74,7 @@ HUMAN_SUBTYPE_VALUES = {
|
||||
"INT_OTHER_BACKCHANNEL", "INT_NON_TAKEOVER_OVERLAP", "INT_WEARER_HOLDS_FLOOR",
|
||||
"OTHER_HARD_NEGATIVE",
|
||||
}
|
||||
EXCLUDE_REASON_VALUES = {
|
||||
"ANNOTATION_ERROR", "RECORDING_BOUNDARY", "MISSING_CONTEXT", "NON_SPEECH_ARTIFACT",
|
||||
"TIMESTAMP_CORRUPTION", "OUT_OF_SCOPE_NORMAL_COMPLETION", "OUT_OF_SCOPE_NON_EVENT",
|
||||
"UNRESOLVABLE",
|
||||
}
|
||||
EXCLUDE_REASON_VALUES = EXCLUDE_REASONS | LEGACY_EXCLUDE_REASONS
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -341,6 +340,8 @@ class CandidateRepository:
|
||||
"ai_verdict": row.get("ai_verdict"),
|
||||
"ai_event_type": row.get("ai_event_type"),
|
||||
"ai_subtype": row.get("ai_subtype"),
|
||||
"ai_exclude_reason": row.get("ai_exclude_reason"),
|
||||
"ai_exclude_reason_group": row.get("ai_exclude_reason_group"),
|
||||
"participant_role": row.get("participant_role") or row.get("holder_role"),
|
||||
"event_time_seconds": event_time,
|
||||
"region_start_seconds": row.get("region_start_seconds", event_time),
|
||||
@@ -458,14 +459,19 @@ class ReviewStore:
|
||||
selected_opportunity_uid = candidate.get("ai_selected_opportunity_uid") or (
|
||||
candidate.get("llm_suggestion") or {}
|
||||
).get("selected_opportunity_uid")
|
||||
exclude_reason = candidate.get("ai_exclude_reason") or (
|
||||
candidate.get("llm_suggestion") or {}
|
||||
).get("exclude_reason")
|
||||
if verdict not in HUMAN_VERDICT_VALUES:
|
||||
raise ValueError("Accept requires an AI pre-label; use Relabel when no AI label is available")
|
||||
elif action == "exclude":
|
||||
verdict, event_type, subtype = "EXCLUDE", None, None
|
||||
selected_opportunity_uid = None
|
||||
exclude_reason = payload.get("exclude_reason")
|
||||
else:
|
||||
verdict, event_type, subtype = payload.get("human_verdict"), payload.get("human_event_type"), payload.get("human_subtype")
|
||||
selected_opportunity_uid = payload.get("selected_opportunity_uid")
|
||||
exclude_reason = payload.get("exclude_reason")
|
||||
if verdict not in HUMAN_VERDICT_VALUES:
|
||||
raise ValueError(f"Invalid human_verdict: {verdict!r}")
|
||||
if verdict == "POSITIVE" and event_type not in HUMAN_EVENT_TYPE_VALUES:
|
||||
@@ -514,11 +520,12 @@ class ReviewStore:
|
||||
candidate.get("event_time", candidate.get("dense_start_seconds")),
|
||||
),
|
||||
)
|
||||
exclude_reason = payload.get("exclude_reason")
|
||||
if action == "exclude" and exclude_reason not in EXCLUDE_REASON_VALUES:
|
||||
raise ValueError("Exclude requires an exclude_reason")
|
||||
if action != "exclude" and exclude_reason is not None:
|
||||
raise ValueError("exclude_reason is only valid for Exclude")
|
||||
if verdict == "EXCLUDE" and exclude_reason not in EXCLUDE_REASON_VALUES:
|
||||
raise ValueError(
|
||||
"EXCLUDE requires an exclude_reason; legacy AI exclusions must be manually categorized"
|
||||
)
|
||||
if verdict != "EXCLUDE" and exclude_reason is not None:
|
||||
raise ValueError("exclude_reason is only valid for EXCLUDE")
|
||||
correction = payload.get("boundary_correction_seconds")
|
||||
if correction not in {-0.2, 0, 0.2, None}:
|
||||
raise ValueError("boundary_correction_seconds must be -0.2, 0, 0.2, or null")
|
||||
@@ -535,6 +542,7 @@ class ReviewStore:
|
||||
else [selected_opportunity_seconds, behavior_anchor_seconds]
|
||||
),
|
||||
exclude_reason=exclude_reason,
|
||||
exclude_reason_group=exclude_reason_group(exclude_reason),
|
||||
relabeled=action == "relabel",
|
||||
boundary_correction_seconds=correction,
|
||||
original_event_time=candidate.get("event_time", candidate.get("anchor_dense_seconds")),
|
||||
@@ -597,6 +605,8 @@ class ReviewStore:
|
||||
"ai_verdict": candidate.payload.get("ai_verdict"),
|
||||
"ai_event_type": candidate.payload.get("ai_event_type"),
|
||||
"ai_subtype": candidate.payload.get("ai_subtype"),
|
||||
"ai_exclude_reason": candidate.payload.get("ai_exclude_reason"),
|
||||
"ai_exclude_reason_group": candidate.payload.get("ai_exclude_reason_group"),
|
||||
"review": normalized,
|
||||
"updated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"candidate": candidate.payload,
|
||||
@@ -650,9 +660,10 @@ class ReviewStore:
|
||||
"automatic_protocol_label",
|
||||
"automatic_hard_negative_type",
|
||||
"ai_verdict", "ai_event_type", "ai_subtype",
|
||||
"ai_exclude_reason", "ai_exclude_reason_group",
|
||||
"human_action", "human_status", "human_verdict", "human_event_type", "human_subtype",
|
||||
"selected_opportunity_uid", "selected_opportunity_seconds",
|
||||
"valid_prediction_interval_seconds", "exclude_reason", "relabeled",
|
||||
"valid_prediction_interval_seconds", "exclude_reason", "exclude_reason_group", "relabeled",
|
||||
"boundary_correction_seconds", "original_event_time",
|
||||
"confidence",
|
||||
"reviewer",
|
||||
|
||||
Reference in New Issue
Block a user