vidhimudaliar commited on
Commit
d2aea71
·
verified ·
1 Parent(s): 743197f

Upload 4 files

Browse files
assets/js/all_videos.js ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // assets/js/all_videos.js
2
+
3
+ const CSV_PATH = new URL("cleaned_data.csv", window.location.href).href;
4
+
5
+ const searchInput = document.getElementById("search");
6
+ const tbody = document.querySelector("#segmentsTable tbody");
7
+
8
+ const rowsCountEl = document.getElementById("rowsCount");
9
+ const videosCountEl = document.getElementById("videosCount");
10
+
11
+ function parseCSV(text) {
12
+ const lines = text.trim().split("\n");
13
+ const header = lines[0].split(",").map(s => s.trim());
14
+ const rows = [];
15
+ for (let i = 1; i < lines.length; i++) {
16
+ const cols = lines[i].split(",");
17
+ const obj = {};
18
+ for (let j = 0; j < header.length; j++) obj[header[j]] = (cols[j] ?? "").trim();
19
+ rows.push(obj);
20
+ }
21
+ return rows;
22
+ }
23
+
24
+ function absVideoUrl(videoPath) {
25
+ try { return new URL(videoPath, window.location.href).href; }
26
+ catch { return videoPath; }
27
+ }
28
+
29
+ function render(rows) {
30
+ tbody.innerHTML = "";
31
+
32
+ const q = (searchInput.value || "").toLowerCase().trim();
33
+ const uniqueVideos = new Set();
34
+
35
+ let shown = 0;
36
+
37
+ for (const r of rows) {
38
+ const filename = r.filename || "";
39
+ const label = r.label || "";
40
+ const start = r.start || "";
41
+ const end = r.end || "";
42
+ const video_path = r.video_path || `videos/${filename}`;
43
+
44
+ const hay = `${filename} ${label}`.toLowerCase();
45
+ if (q && !hay.includes(q)) continue;
46
+
47
+ shown++;
48
+ uniqueVideos.add(filename);
49
+
50
+ const tr = document.createElement("tr");
51
+ const video_url = absVideoUrl(video_path);
52
+
53
+ tr.innerHTML = `
54
+ <td>${filename}</td>
55
+ <td><a href="category.html?cat=${encodeURIComponent(label)}" style="color: var(--accent); text-decoration: none;">${label}</a></td>
56
+ <td>${start}-${end}</td>
57
+ <td class="video-cell">
58
+ <video preload="metadata" controls>
59
+ <source src="${video_url}" type="video/mp4" />
60
+ Video not found
61
+ </video>
62
+ </td>
63
+ `;
64
+
65
+ const videoEl = tr.querySelector("video");
66
+ attachLabeledLoop(videoEl, {
67
+ label,
68
+ startFrame: start,
69
+ endFrame: end,
70
+ fps: DEFAULT_FPS
71
+ });
72
+
73
+ tbody.appendChild(tr);
74
+ }
75
+
76
+ rowsCountEl.textContent = `${shown} segments`;
77
+ videosCountEl.textContent = `${uniqueVideos.size} videos`;
78
+ }
79
+
80
+ fetch(CSV_PATH)
81
+ .then(r => r.text())
82
+ .then(text => {
83
+ const rows = parseCSV(text);
84
+ render(rows);
85
+ searchInput.addEventListener("input", () => render(rows));
86
+ })
87
+ .catch(err => {
88
+ console.error(err);
89
+ tbody.innerHTML = `<tr><td colspan="4">Could not load cleaned_data.csv</td></tr>`;
90
+ });
assets/js/category.js ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // assets/js/category.js
2
+
3
+ const CSV_PATH = new URL("cleaned_data.csv", window.location.href).href;
4
+
5
+ const params = new URLSearchParams(window.location.search);
6
+ const cat = (params.get("cat") || "").trim();
7
+
8
+ const titleEl = document.getElementById("catTitle");
9
+ const defEl = document.getElementById("catDef");
10
+ const repMetaEl = document.getElementById("repMeta");
11
+ const repGrid = document.getElementById("repGrid");
12
+ const repEmpty = document.getElementById("repEmpty");
13
+
14
+ const instCountEl = document.getElementById("instCount");
15
+ const instVideoCountEl = document.getElementById("instVideoCount");
16
+
17
+ const tbody = document.querySelector("#catTable tbody");
18
+
19
+ function parseCSV(text) {
20
+ const lines = text.trim().split("\n");
21
+ const header = lines[0].split(",").map(s => s.trim());
22
+ const rows = [];
23
+ for (let i = 1; i < lines.length; i++) {
24
+ const cols = lines[i].split(",");
25
+ const obj = {};
26
+ for (let j = 0; j < header.length; j++) obj[header[j]] = (cols[j] ?? "").trim();
27
+ rows.push(obj);
28
+ }
29
+ return rows;
30
+ }
31
+
32
+ function absVideoUrl(videoPath) {
33
+ try { return new URL(videoPath, window.location.href).href; }
34
+ catch { return videoPath; }
35
+ }
36
+
37
+ function renderRep(instance, failureInfo) {
38
+ repGrid.innerHTML = "";
39
+
40
+ if (!instance) {
41
+ repEmpty.hidden = false;
42
+ repMetaEl.textContent = "";
43
+ return;
44
+ }
45
+ repEmpty.hidden = true;
46
+
47
+ const filename = instance.filename;
48
+ const label = instance.label;
49
+ const start = instance.start;
50
+ const end = instance.end;
51
+ const video_url = absVideoUrl(instance.video_path || `videos/${filename}`);
52
+
53
+ repMetaEl.textContent = `Example: ${filename} (frames ${start}-${end})`;
54
+
55
+ const wrap = document.createElement("div");
56
+ wrap.className = "video-item";
57
+ wrap.innerHTML = `
58
+ <video preload="metadata" controls>
59
+ <source src="${video_url}" type="video/mp4" />
60
+ Video not found
61
+ </video>
62
+ <div class="video-label">${failureInfo?.name || label || ""}</div>
63
+ `;
64
+
65
+ const videoEl = wrap.querySelector("video");
66
+ attachLabeledLoop(videoEl, { label, startFrame: start, endFrame: end, fps: DEFAULT_FPS });
67
+
68
+ repGrid.appendChild(wrap);
69
+ }
70
+
71
+ function renderTable(instances) {
72
+ tbody.innerHTML = "";
73
+ const uniqueVideos = new Set();
74
+
75
+ for (const r of instances) {
76
+ uniqueVideos.add(r.filename);
77
+
78
+ const tr = document.createElement("tr");
79
+ const video_url = absVideoUrl(r.video_path || `videos/${r.filename}`);
80
+
81
+ tr.innerHTML = `
82
+ <td>${r.filename}</td>
83
+ <td>${r.start}-${r.end}</td>
84
+ <td class="video-cell">
85
+ <video preload="metadata" controls>
86
+ <source src="${video_url}" type="video/mp4" />
87
+ Video not found
88
+ </video>
89
+ </td>
90
+ `;
91
+
92
+ const videoEl = tr.querySelector("video");
93
+ attachLabeledLoop(videoEl, { label: r.label, startFrame: r.start, endFrame: r.end, fps: DEFAULT_FPS });
94
+
95
+ tbody.appendChild(tr);
96
+ }
97
+
98
+ instCountEl.textContent = `${instances.length} segments`;
99
+ instVideoCountEl.textContent = `${uniqueVideos.size} videos`;
100
+ }
101
+
102
+ function setHeader(failureInfo) {
103
+ if (!cat) {
104
+ titleEl.textContent = "No category specified";
105
+ defEl.textContent = "Return to Home and select a category.";
106
+ return;
107
+ }
108
+
109
+ titleEl.textContent = failureInfo?.name || cat;
110
+ defEl.textContent = failureInfo?.definition || "";
111
+ document.title = `${cat} — Failure Category`;
112
+ }
113
+
114
+ const failureInfo = window.FAILURE_MAP?.[cat] || window.FAILURES?.find(f => f.name === cat);
115
+ setHeader(failureInfo);
116
+
117
+ fetch(CSV_PATH)
118
+ .then(r => r.text())
119
+ .then(text => {
120
+ const rows = parseCSV(text);
121
+
122
+ const instances = rows
123
+ .filter(r => String(r.label || "").trim() === cat)
124
+ .filter(r => r.filename && r.start !== "" && r.end !== "");
125
+
126
+ instances.sort((a, b) => {
127
+ if (a.filename !== b.filename) return a.filename.localeCompare(b.filename);
128
+ return Number(a.start) - Number(b.start);
129
+ });
130
+
131
+ renderRep(instances[0], failureInfo);
132
+ renderTable(instances);
133
+ })
134
+ .catch(err => {
135
+ console.error(err);
136
+ repEmpty.hidden = false;
137
+ repEmpty.textContent = "Could not load cleaned_data.csv.";
138
+ tbody.innerHTML = `<tr><td colspan="3">Could not load cleaned_data.csv</td></tr>`;
139
+ });
assets/js/failures.js ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // assets/js/failures.js
2
+
3
+ window.FAILURES = [
4
+ // Added so your playback rules work when browsing these labels
5
+ {
6
+ name: "Time",
7
+ family: "Meta",
8
+ definition: "Timing annotation; clip plays from the beginning of the video until the end frame.",
9
+ onset: "Video start",
10
+ offset: "Annotated end frame"
11
+ },
12
+ {
13
+ name: "Success",
14
+ family: "Meta",
15
+ definition: "Successful trial (clip shows full video).",
16
+ onset: "Video start",
17
+ offset: "Video end"
18
+ },
19
+ {
20
+ name: "Failure",
21
+ family: "Meta",
22
+ definition: "Failed trial (clip shows full video).",
23
+ onset: "Video start",
24
+ offset: "Video end"
25
+ },
26
+
27
+ // Existing failures
28
+ {
29
+ name: "Safety Conflict",
30
+ family: "Safety",
31
+ definition: "Physical contact between participant and robot.",
32
+ onset: "Start of contact.",
33
+ offset: "End of contact."
34
+ },
35
+ {
36
+ name: "Safety Avoidance",
37
+ family: "Safety",
38
+ definition: "Participant avoids physical contact with robot.",
39
+ onset: "First frame when human backs their hand when robot is near.",
40
+ offset: "End of video (per playback rule)."
41
+ },
42
+ {
43
+ name: "Passive Wait",
44
+ family: "Efficiency",
45
+ definition:
46
+ "Task deviates from optimal performance OR the human waits until the robot is finished with its task before starting their task.",
47
+ onset: "Start frame of waiting/sub-optimal performance.",
48
+ offset: "End frame when the human proceeds."
49
+ },
50
+ {
51
+ name: "Redundant Retrieval",
52
+ family: "Safety/Efficiency",
53
+ definition: "Duplicate action by both agents for the same item.",
54
+ onset: "Second agent initiates duplicate action.",
55
+ offset: "End of video (per playback rule)."
56
+ },
57
+ {
58
+ name: "Task Model Uncertainty",
59
+ family: "Cognition",
60
+ definition:
61
+ "Human does not know or forget what to do next due to less task knowledge (exclude deferring because they expect the robot to do it).",
62
+ onset: "First uncertainty cue.",
63
+ offset: "End of video (per playback rule)."
64
+ },
65
+ {
66
+ name: "Capability Miscalibration",
67
+ family: "Cognition",
68
+ definition:
69
+ "Human waited because they expected the robot to do it (not because they were unsure what to do).",
70
+ onset: "Start frame of waiting due to expectation.",
71
+ offset: "End frame when the human proceeds."
72
+ },
73
+ {
74
+ name: "Missed Grab",
75
+ family: "Manipulation",
76
+ definition: "Robot or human missed the bottle and has to go back and retrieve it.",
77
+ onset: "10 frames before annotated start (per playback rule).",
78
+ offset: "50 frames after annotated end (clamped to end of video)."
79
+ },
80
+ {
81
+ name: "Slippage",
82
+ family: "Manipulation",
83
+ definition: "Bottle slips from grasp when moving.",
84
+ onset: "10 frames before annotated start (per playback rule).",
85
+ offset: "50 frames after annotated end (clamped to end of video)."
86
+ }
87
+ ];
88
+
89
+ window.FAILURE_MAP = Object.fromEntries(window.FAILURES.map(f => [f.name, f]));
90
+
assets/js/video_segment.js ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // assets/js/video_segment.js
2
+ const DEFAULT_FPS = 30;
3
+
4
+ /**
5
+ * Playback rules by label (case-insensitive):
6
+ *
7
+ * time : video start -> endFrame
8
+ * success : entire video
9
+ * failure : entire video
10
+ * safety conflict : startFrame -> endFrame
11
+ * safety avoidance : startFrame -> end of video
12
+ * passive wait : startFrame -> endFrame
13
+ * redundant retrieval : startFrame -> end of video
14
+ * task model uncertainty : startFrame -> end of video
15
+ * capability miscalibration : startFrame -> endFrame
16
+ * missed grab : (startFrame-10) -> (endFrame+50 or end of video)
17
+ * slippage : (startFrame-10) -> (endFrame+50 or end of video)
18
+ *
19
+ * Manual control requirements:
20
+ * 1) If user pauses, DO NOT auto-resume.
21
+ * 2) If user seeks/scrubs anywhere, allow it. When playback reaches the window end,
22
+ * it loops back to the window start (and continues only if user is playing).
23
+ */
24
+
25
+ function normalizeLabel(label) {
26
+ return String(label || "").trim().toLowerCase();
27
+ }
28
+
29
+ function computeWindowFrames(label, startFrame, endFrame) {
30
+ const lab = normalizeLabel(label);
31
+
32
+ let s = Number(startFrame);
33
+ let e = Number(endFrame);
34
+
35
+ if (!Number.isFinite(s)) s = 0;
36
+ if (!Number.isFinite(e)) e = 0;
37
+ if (s > e) [s, e] = [e, s];
38
+
39
+ let start = s;
40
+ let end = e;
41
+ let endIsVideo = false;
42
+
43
+ const isTime = lab === "time";
44
+ const isSuccess = lab === "success";
45
+ const isFailure = lab === "failure";
46
+
47
+ const isSafetyConflict = lab === "safety conflict";
48
+ const isSafetyAvoidance = lab === "safety avoidance";
49
+ const isPassiveWait = lab === "passive wait";
50
+ const isRedundantRetrieval = lab === "redundant retrieval";
51
+ const isTMU = lab === "task model uncertainty";
52
+ const isCapMis = lab === "capability miscalibration";
53
+ const isMissedGrab = lab === "missed grab";
54
+ const isSlippage = lab === "slippage";
55
+
56
+ if (isTime) {
57
+ start = 0;
58
+ end = e;
59
+ endIsVideo = false;
60
+ } else if (isSuccess || isFailure) {
61
+ start = 0;
62
+ endIsVideo = true;
63
+ } else if (isSafetyConflict || isPassiveWait || isCapMis) {
64
+ start = s;
65
+ end = e;
66
+ endIsVideo = false;
67
+ } else if (isSafetyAvoidance || isRedundantRetrieval || isTMU) {
68
+ start = s;
69
+ endIsVideo = true;
70
+ } else if (isMissedGrab || isSlippage) {
71
+ start = Math.max(0, s - 10);
72
+ end = e + 50; // will clamp to duration
73
+ endIsVideo = false;
74
+ } else {
75
+ // Unknown label: just use annotated segment
76
+ start = s;
77
+ end = e;
78
+ endIsVideo = false;
79
+ }
80
+
81
+ start = Math.max(0, Math.floor(start));
82
+ if (!endIsVideo) end = Math.max(start, Math.floor(end));
83
+
84
+ return { startFrameAdj: start, endFrameAdj: end, endIsVideo };
85
+ }
86
+
87
+ /**
88
+ * Attaches labeled looping to a <video>, while preserving manual user control.
89
+ *
90
+ * - Autoplays (muted) so the page is lively.
91
+ * - If user pauses, we do NOT force play().
92
+ * - If user seeks anywhere, we allow it.
93
+ * - When playback crosses the computed end time, we jump back to the start time.
94
+ * If the video was playing, we keep playing. If paused, it stays paused.
95
+ */
96
+ function attachLabeledLoop(videoEl, { label, startFrame, endFrame, fps = DEFAULT_FPS }) {
97
+ const { startFrameAdj, endFrameAdj, endIsVideo } = computeWindowFrames(label, startFrame, endFrame);
98
+
99
+ const startSec = Math.max(0, startFrameAdj / fps);
100
+ let endSec = Math.max(startSec, endFrameAdj / fps);
101
+
102
+ // Autoplay compatibility: muted + playsInline
103
+ videoEl.muted = true;
104
+ videoEl.playsInline = true;
105
+
106
+ // Track whether a pause was user-initiated (so we never override it)
107
+ let userPaused = false;
108
+
109
+ function safePlay() {
110
+ const p = videoEl.play();
111
+ if (p && typeof p.catch === "function") p.catch(() => { });
112
+ }
113
+
114
+ function jumpToStart(keepPaused) {
115
+ try {
116
+ videoEl.currentTime = startSec;
117
+ } catch (_) { }
118
+ if (!keepPaused) safePlay();
119
+ }
120
+
121
+ // Setup final endSec based on duration once known
122
+ videoEl.addEventListener("loadedmetadata", () => {
123
+ const dur = Number.isFinite(videoEl.duration) ? videoEl.duration : null;
124
+
125
+ if (dur != null) {
126
+ if (endIsVideo) {
127
+ endSec = dur;
128
+ } else if (endSec > dur) {
129
+ endSec = dur;
130
+ }
131
+ }
132
+
133
+ // Start at window start and autoplay (muted)
134
+ userPaused = false;
135
+ jumpToStart(false);
136
+ });
137
+
138
+ // If user pauses, respect it
139
+ videoEl.addEventListener("pause", () => {
140
+ // If it paused because it reached the natural end (rare), userPaused still ok
141
+ userPaused = true;
142
+ });
143
+
144
+ // If user hits play, allow it (resume normal looping)
145
+ videoEl.addEventListener("play", () => {
146
+ userPaused = false;
147
+ });
148
+
149
+ // Core loop logic: when reaching endSec, loop back to startSec
150
+ videoEl.addEventListener("timeupdate", () => {
151
+ // epsilon to prevent jitter
152
+ if (endSec <= startSec + 0.01) return;
153
+
154
+ if (videoEl.currentTime >= endSec - 0.02) {
155
+ // Loop back, but DO NOT resume if user paused
156
+ const keepPaused = videoEl.paused || userPaused;
157
+ jumpToStart(keepPaused);
158
+ }
159
+ });
160
+
161
+ // IMPORTANT CHANGE: allow free seeking/scrubbing.
162
+ // No snapping during seek; we only enforce the window when time reaches endSec.
163
+ }
164
+
165
+ window.DEFAULT_FPS = DEFAULT_FPS;
166
+ window.attachLabeledLoop = attachLabeledLoop;
167
+ window.computeWindowFrames = computeWindowFrames;
168
+