Spaces:
Running
Running
Zhen Ye
commited on
Commit
·
ec62a08
1
Parent(s):
af0f84f
Rename UI terms: Reason->Detect, Engage->Track
Browse files- frontend/index.html +32 -34
- frontend/js/core/hel.js +1 -1
- frontend/js/main.js +20 -20
- frontend/js/ui/chat.js +2 -2
- frontend/js/ui/intel.js +1 -1
frontend/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
| 5 |
<meta charset="UTF-8" />
|
| 6 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 7 |
<link rel="stylesheet" href="style.css">
|
| 8 |
-
<title>
|
| 9 |
</head>
|
| 10 |
|
| 11 |
<body>
|
|
@@ -14,9 +14,8 @@
|
|
| 14 |
<div class="brand">
|
| 15 |
<div class="logo" aria-hidden="true"></div>
|
| 16 |
<div>
|
| 17 |
-
<h1>
|
| 18 |
-
<div class="sub">Video → detection →
|
| 19 |
-
closed-loop tracking & dwell control</div>
|
| 20 |
</div>
|
| 21 |
</div>
|
| 22 |
<div class="status-row">
|
|
@@ -25,12 +24,12 @@
|
|
| 25 |
<span id="sys-status">STANDBY · No video loaded</span>
|
| 26 |
</div>
|
| 27 |
<div class="pill">
|
| 28 |
-
<span class="kbd">
|
| 29 |
-
<span>
|
| 30 |
</div>
|
| 31 |
<div class="pill">
|
| 32 |
-
<span class="kbd">
|
| 33 |
-
<span>
|
| 34 |
</div>
|
| 35 |
</div>
|
| 36 |
</header>
|
|
@@ -40,7 +39,7 @@
|
|
| 40 |
<div class="card">
|
| 41 |
<h2>Video Input</h2>
|
| 42 |
<div class="hint">Upload one video. Tab 1 uses only the first frame. Tab 2 reuses the same video for tracking
|
| 43 |
-
and
|
| 44 |
|
| 45 |
<div class="row mt-md">
|
| 46 |
<label for="videoFile">Video file</label>
|
|
@@ -92,7 +91,7 @@
|
|
| 92 |
</select>
|
| 93 |
</div>
|
| 94 |
|
| 95 |
-
<label class="checkbox-row" for="enableDepthToggle">
|
| 96 |
<input type="checkbox" id="enableDepthToggle">
|
| 97 |
<span>Enable Legacy Depth Map (Slow)</span>
|
| 98 |
</label>
|
|
@@ -117,8 +116,8 @@
|
|
| 117 |
|
| 118 |
<main>
|
| 119 |
<div class="tabs">
|
| 120 |
-
<button class="tabbtn active" data-tab="frame">Tab 1 ·
|
| 121 |
-
<button class="tabbtn" data-tab="engage">Tab 2 ·
|
| 122 |
</div>
|
| 123 |
|
| 124 |
<!-- ===== Tab 1 ===== -->
|
|
@@ -126,17 +125,17 @@
|
|
| 126 |
<div class="frame-grid">
|
| 127 |
<div class="panel panel-monitor">
|
| 128 |
<h3>
|
| 129 |
-
<span>First Frame · Detection +
|
| 130 |
<span class="rightnote" id="frameNote">Awaiting video</span>
|
| 131 |
</h3>
|
| 132 |
<div class="viewbox" id="frameViewBox">
|
| 133 |
<canvas id="frameCanvas" width="1280" height="720"></canvas>
|
| 134 |
<canvas id="frameOverlay" class="overlay" width="1280" height="720"></canvas>
|
| 135 |
-
<div class="watermark">EO/IR · Track-ID ·
|
| 136 |
<div class="empty" id="frameEmpty">
|
| 137 |
<div class="big">Upload a video to begin</div>
|
| 138 |
-
<div class="small">This demo performs first-frame
|
| 139 |
-
|
| 140 |
<div style="display:flex; gap:10px; margin-top:6px; flex-wrap:wrap; justify-content:center;">
|
| 141 |
<span class="badge"><span class="dot"></span> If you are online, COCO-SSD loads automatically</span>
|
| 142 |
</div>
|
|
@@ -144,15 +143,15 @@
|
|
| 144 |
</div>
|
| 145 |
|
| 146 |
<div class="btnrow" style="margin-top:10px">
|
| 147 |
-
<button id="btnReason" class="btn">
|
| 148 |
<button id="btnCancelReason" class="btn danger" style="display: none;">Cancel</button>
|
| 149 |
-
<button id="btnRecompute" class="btn secondary">
|
| 150 |
<button id="btnClear" class="btn secondary">Clear</button>
|
| 151 |
</div>
|
| 152 |
|
| 153 |
<div class="strip mt-md">
|
| 154 |
<span class="chip" id="chipFrameDepth"
|
| 155 |
-
title="Toggle depth view of first frame (if available)">VIEW:DEFAULT</span>
|
| 156 |
</div>
|
| 157 |
</div>
|
| 158 |
|
|
@@ -174,18 +173,18 @@
|
|
| 174 |
<!-- Threat Chat Panel -->
|
| 175 |
<div class="panel panel-chat" id="chatPanel">
|
| 176 |
<h3>
|
| 177 |
-
<span>
|
| 178 |
<button class="collapse-btn" id="chatToggle" style="font-size: 0.75rem;">▲ Close Chat</button>
|
| 179 |
</h3>
|
| 180 |
<div class="chat-container">
|
| 181 |
<div class="chat-messages" id="chatMessages">
|
| 182 |
<div class="chat-message chat-system">
|
| 183 |
<span class="chat-icon">SYS</span>
|
| 184 |
-
<span class="chat-content">Run detection first, then ask questions about detected
|
| 185 |
</div>
|
| 186 |
</div>
|
| 187 |
<div class="chat-input-row">
|
| 188 |
-
<input type="text" id="chatInput" placeholder="Ask about
|
| 189 |
<button id="chatSend" class="btn">Send</button>
|
| 190 |
</div>
|
| 191 |
</div>
|
|
@@ -200,7 +199,7 @@
|
|
| 200 |
<div class="engage-grid">
|
| 201 |
<div class="panel">
|
| 202 |
<h3>
|
| 203 |
-
<span>Video
|
| 204 |
<div style="display: flex; gap: 8px; align-items: center;">
|
| 205 |
<button class="collapse-btn" id="btnToggleSidebar">◀ Hide Sidebar</button>
|
| 206 |
<span class="rightnote" id="engageNote">Awaiting video</span>
|
|
@@ -210,16 +209,16 @@
|
|
| 210 |
<div class="viewbox" style="min-height: 420px;">
|
| 211 |
<video id="videoEngage" playsinline muted></video>
|
| 212 |
<canvas id="engageOverlay" class="overlay"></canvas>
|
| 213 |
-
<div class="watermark">
|
| 214 |
<div class="empty" id="engageEmpty">
|
| 215 |
<div class="big">No video loaded</div>
|
| 216 |
-
<div class="small">Upload a video. Run <b>
|
| 217 |
-
Then click <b>
|
| 218 |
</div>
|
| 219 |
</div>
|
| 220 |
|
| 221 |
<div class="btnrow mt-md">
|
| 222 |
-
<button id="btnEngage" class="btn">
|
| 223 |
<button id="btnPause" class="btn secondary">Pause</button>
|
| 224 |
<button id="btnReset" class="btn secondary">Reset</button>
|
| 225 |
</div>
|
|
@@ -227,14 +226,14 @@
|
|
| 227 |
<div class="strip mt-md">
|
| 228 |
<span class="chip" id="chipPolicy">POLICY:AUTO</span>
|
| 229 |
<span class="chip" id="chipTracks">TRACKS:0</span>
|
| 230 |
-
<span class="chip" id="chipBeam">
|
| 231 |
<span class="chip" id="chipHz">DET:6Hz</span>
|
| 232 |
<span class="chip" id="chipFeed" title="Toggle raw vs HF-processed feed (if available)">FEED:RAW</span>
|
| 233 |
-
<span class="chip" id="chipDepth" title="Toggle depth view (if available)">VIEW:DEFAULT</span>
|
| 234 |
</div>
|
| 235 |
|
| 236 |
<div class="mt-md">
|
| 237 |
-
<div class="row"><label>Active
|
| 238 |
id="dwellText">—</small>
|
| 239 |
</div>
|
| 240 |
<div class="bar">
|
|
@@ -242,8 +241,7 @@
|
|
| 242 |
</div>
|
| 243 |
</div>
|
| 244 |
|
| 245 |
-
<div class="hint mt-md">Manual
|
| 246 |
-
click a target in the video. The “beam” will track its aimpoint and accumulate dwell.</div>
|
| 247 |
</div>
|
| 248 |
|
| 249 |
<div class="engage-right">
|
|
@@ -261,8 +259,8 @@
|
|
| 261 |
</div>
|
| 262 |
|
| 263 |
<footer>
|
| 264 |
-
<div>
|
| 265 |
-
<div class="mono" id="telemetry">
|
| 266 |
</footer>
|
| 267 |
|
| 268 |
<!-- Hidden video used only for first-frame capture -->
|
|
|
|
| 5 |
<meta charset="UTF-8" />
|
| 6 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 7 |
<link rel="stylesheet" href="style.css">
|
| 8 |
+
<title>Mission Console</title>
|
| 9 |
</head>
|
| 10 |
|
| 11 |
<body>
|
|
|
|
| 14 |
<div class="brand">
|
| 15 |
<div class="logo" aria-hidden="true"></div>
|
| 16 |
<div>
|
| 17 |
+
<h1>Mission Console</h1>
|
| 18 |
+
<div class="sub">Video → detection → analysis → tracking → mission assessment</div>
|
|
|
|
| 19 |
</div>
|
| 20 |
</div>
|
| 21 |
<div class="status-row">
|
|
|
|
| 24 |
<span id="sys-status">STANDBY · No video loaded</span>
|
| 25 |
</div>
|
| 26 |
<div class="pill">
|
| 27 |
+
<span class="kbd">Detect</span>
|
| 28 |
+
<span>First-frame analysis</span>
|
| 29 |
</div>
|
| 30 |
<div class="pill">
|
| 31 |
+
<span class="kbd">Track</span>
|
| 32 |
+
<span>Continuous monitoring</span>
|
| 33 |
</div>
|
| 34 |
</div>
|
| 35 |
</header>
|
|
|
|
| 39 |
<div class="card">
|
| 40 |
<h2>Video Input</h2>
|
| 41 |
<div class="hint">Upload one video. Tab 1 uses only the first frame. Tab 2 reuses the same video for tracking
|
| 42 |
+
and monitoring.</div>
|
| 43 |
|
| 44 |
<div class="row mt-md">
|
| 45 |
<label for="videoFile">Video file</label>
|
|
|
|
| 91 |
</select>
|
| 92 |
</div>
|
| 93 |
|
| 94 |
+
<label class="checkbox-row" for="enableDepthToggle" style="display:none">
|
| 95 |
<input type="checkbox" id="enableDepthToggle">
|
| 96 |
<span>Enable Legacy Depth Map (Slow)</span>
|
| 97 |
</label>
|
|
|
|
| 116 |
|
| 117 |
<main>
|
| 118 |
<div class="tabs">
|
| 119 |
+
<button class="tabbtn active" data-tab="frame">Tab 1 · Detect & Analyze</button>
|
| 120 |
+
<button class="tabbtn" data-tab="engage">Tab 2 · Track & Monitor</button>
|
| 121 |
</div>
|
| 122 |
|
| 123 |
<!-- ===== Tab 1 ===== -->
|
|
|
|
| 125 |
<div class="frame-grid">
|
| 126 |
<div class="panel panel-monitor">
|
| 127 |
<h3>
|
| 128 |
+
<span>First Frame · Detection + Analysis</span>
|
| 129 |
<span class="rightnote" id="frameNote">Awaiting video</span>
|
| 130 |
</h3>
|
| 131 |
<div class="viewbox" id="frameViewBox">
|
| 132 |
<canvas id="frameCanvas" width="1280" height="720"></canvas>
|
| 133 |
<canvas id="frameOverlay" class="overlay" width="1280" height="720"></canvas>
|
| 134 |
+
<div class="watermark">EO/IR · Track-ID · Classification</div>
|
| 135 |
<div class="empty" id="frameEmpty">
|
| 136 |
<div class="big">Upload a video to begin</div>
|
| 137 |
+
<div class="small">This demo performs first-frame detection and analysis. Then it replays the video
|
| 138 |
+
with continuous object tracking.</div>
|
| 139 |
<div style="display:flex; gap:10px; margin-top:6px; flex-wrap:wrap; justify-content:center;">
|
| 140 |
<span class="badge"><span class="dot"></span> If you are online, COCO-SSD loads automatically</span>
|
| 141 |
</div>
|
|
|
|
| 143 |
</div>
|
| 144 |
|
| 145 |
<div class="btnrow" style="margin-top:10px">
|
| 146 |
+
<button id="btnReason" class="btn">Detect</button>
|
| 147 |
<button id="btnCancelReason" class="btn danger" style="display: none;">Cancel</button>
|
| 148 |
+
<button id="btnRecompute" class="btn secondary">Reanalyze</button>
|
| 149 |
<button id="btnClear" class="btn secondary">Clear</button>
|
| 150 |
</div>
|
| 151 |
|
| 152 |
<div class="strip mt-md">
|
| 153 |
<span class="chip" id="chipFrameDepth"
|
| 154 |
+
title="Toggle depth view of first frame (if available)" style="display:none">VIEW:DEFAULT</span>
|
| 155 |
</div>
|
| 156 |
</div>
|
| 157 |
|
|
|
|
| 173 |
<!-- Threat Chat Panel -->
|
| 174 |
<div class="panel panel-chat" id="chatPanel">
|
| 175 |
<h3>
|
| 176 |
+
<span>Mission Analyst</span>
|
| 177 |
<button class="collapse-btn" id="chatToggle" style="font-size: 0.75rem;">▲ Close Chat</button>
|
| 178 |
</h3>
|
| 179 |
<div class="chat-container">
|
| 180 |
<div class="chat-messages" id="chatMessages">
|
| 181 |
<div class="chat-message chat-system">
|
| 182 |
<span class="chat-icon">SYS</span>
|
| 183 |
+
<span class="chat-content">Run detection first, then ask questions about detected objects.</span>
|
| 184 |
</div>
|
| 185 |
</div>
|
| 186 |
<div class="chat-input-row">
|
| 187 |
+
<input type="text" id="chatInput" placeholder="Ask about detections..." autocomplete="off">
|
| 188 |
<button id="chatSend" class="btn">Send</button>
|
| 189 |
</div>
|
| 190 |
</div>
|
|
|
|
| 199 |
<div class="engage-grid">
|
| 200 |
<div class="panel">
|
| 201 |
<h3>
|
| 202 |
+
<span>Video Tracking · Continuous Monitoring</span>
|
| 203 |
<div style="display: flex; gap: 8px; align-items: center;">
|
| 204 |
<button class="collapse-btn" id="btnToggleSidebar">◀ Hide Sidebar</button>
|
| 205 |
<span class="rightnote" id="engageNote">Awaiting video</span>
|
|
|
|
| 209 |
<div class="viewbox" style="min-height: 420px;">
|
| 210 |
<video id="videoEngage" playsinline muted></video>
|
| 211 |
<canvas id="engageOverlay" class="overlay"></canvas>
|
| 212 |
+
<div class="watermark">TRACK · ID · DIST · STATUS</div>
|
| 213 |
<div class="empty" id="engageEmpty">
|
| 214 |
<div class="big">No video loaded</div>
|
| 215 |
+
<div class="small">Upload a video. Run <b>Detect</b> first to analyze objects.
|
| 216 |
+
Then click <b>Track</b>.</div>
|
| 217 |
</div>
|
| 218 |
</div>
|
| 219 |
|
| 220 |
<div class="btnrow mt-md">
|
| 221 |
+
<button id="btnEngage" class="btn">Track</button>
|
| 222 |
<button id="btnPause" class="btn secondary">Pause</button>
|
| 223 |
<button id="btnReset" class="btn secondary">Reset</button>
|
| 224 |
</div>
|
|
|
|
| 226 |
<div class="strip mt-md">
|
| 227 |
<span class="chip" id="chipPolicy">POLICY:AUTO</span>
|
| 228 |
<span class="chip" id="chipTracks">TRACKS:0</span>
|
| 229 |
+
<span class="chip" id="chipBeam">MODE:AUTO</span>
|
| 230 |
<span class="chip" id="chipHz">DET:6Hz</span>
|
| 231 |
<span class="chip" id="chipFeed" title="Toggle raw vs HF-processed feed (if available)">FEED:RAW</span>
|
| 232 |
+
<span class="chip" id="chipDepth" title="Toggle depth view (if available)" style="display:none">VIEW:DEFAULT</span>
|
| 233 |
</div>
|
| 234 |
|
| 235 |
<div class="mt-md">
|
| 236 |
+
<div class="row"><label>Active track progress (selected)</label><small class="mini"
|
| 237 |
id="dwellText">—</small>
|
| 238 |
</div>
|
| 239 |
<div class="bar">
|
|
|
|
| 241 |
</div>
|
| 242 |
</div>
|
| 243 |
|
| 244 |
+
<div class="hint mt-md">Manual selection: choose "Manual" in Policy, then click a target in the video.</div>
|
|
|
|
| 245 |
</div>
|
| 246 |
|
| 247 |
<div class="engage-right">
|
|
|
|
| 259 |
</div>
|
| 260 |
|
| 261 |
<footer>
|
| 262 |
+
<div>Mission Console · Unclassified visuals</div>
|
| 263 |
+
<div class="mono" id="telemetry">VIS=16km · DET=6Hz</div>
|
| 264 |
</footer>
|
| 265 |
|
| 266 |
<!-- Hidden video used only for first-frame capture -->
|
frontend/js/core/hel.js
CHANGED
|
@@ -240,6 +240,6 @@ APP.core.hel.syncKnobDisplays = function () {
|
|
| 240 |
// Update telemetry footer
|
| 241 |
const telemetry = $("#telemetry");
|
| 242 |
if (telemetry && helPower && atmVis && atmCn2 && aoQ && detHz) {
|
| 243 |
-
telemetry.textContent = `
|
| 244 |
}
|
| 245 |
};
|
|
|
|
| 240 |
// Update telemetry footer
|
| 241 |
const telemetry = $("#telemetry");
|
| 242 |
if (telemetry && helPower && atmVis && atmCn2 && aoQ && detHz) {
|
| 243 |
+
telemetry.textContent = `VIS=${atmVis.value}km · DET=${detHz.value}Hz`;
|
| 244 |
}
|
| 245 |
};
|
frontend/js/main.js
CHANGED
|
@@ -100,13 +100,13 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 100 |
try {
|
| 101 |
await captureFirstFrame();
|
| 102 |
// Show placeholder message - actual frame will come from backend
|
| 103 |
-
if (frameNote) frameNote.textContent = "Video loaded (run
|
| 104 |
-
if (engageNote) engageNote.textContent = "Ready for
|
| 105 |
} catch (err) {
|
| 106 |
log(`First frame capture failed: ${err.message}`, "e");
|
| 107 |
}
|
| 108 |
|
| 109 |
-
setStatus("warn", "READY · Video loaded (run
|
| 110 |
log(`Video loaded: ${file.name}`, "g");
|
| 111 |
|
| 112 |
// Load video-specific demo tracks (e.g., helicopter demo)
|
|
@@ -142,7 +142,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 142 |
await recomputeHEL();
|
| 143 |
renderFrameOverlay();
|
| 144 |
|
| 145 |
-
log("
|
| 146 |
});
|
| 147 |
}
|
| 148 |
|
|
@@ -175,7 +175,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 175 |
btnPause.addEventListener("click", () => {
|
| 176 |
if (videoEngage) videoEngage.pause();
|
| 177 |
state.tracker.running = false;
|
| 178 |
-
log("
|
| 179 |
});
|
| 180 |
}
|
| 181 |
|
|
@@ -190,7 +190,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 190 |
state.tracker.running = false;
|
| 191 |
state.tracker.nextId = 1;
|
| 192 |
renderFrameTrackList();
|
| 193 |
-
log("
|
| 194 |
});
|
| 195 |
}
|
| 196 |
|
|
@@ -273,7 +273,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 273 |
chipFrameDepth.addEventListener("click", () => {
|
| 274 |
if (!state.videoLoaded) return;
|
| 275 |
if (!state.hf.depthFirstFrameUrl) {
|
| 276 |
-
log("First frame depth not ready yet. Run
|
| 277 |
return;
|
| 278 |
}
|
| 279 |
toggleFirstFrameDepthView();
|
|
@@ -309,7 +309,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 309 |
}
|
| 310 |
|
| 311 |
if (state.isReasoning) {
|
| 312 |
-
log("
|
| 313 |
return;
|
| 314 |
}
|
| 315 |
|
|
@@ -329,7 +329,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 329 |
renderFrameTrackList();
|
| 330 |
renderFrameOverlay();
|
| 331 |
|
| 332 |
-
setStatus("warn", "
|
| 333 |
|
| 334 |
// Agent cursor flair
|
| 335 |
if (state.ui.cursorMode === "on" && moveCursorToRect) {
|
|
@@ -342,7 +342,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 342 |
const mode = detectorSelect ? detectorSelect.value : "hf_yolov8";
|
| 343 |
const queries = missionText ? missionText.value.trim() : "";
|
| 344 |
const enableGPT = $("#enableGPTToggle")?.checked || false;
|
| 345 |
-
const enableDepth =
|
| 346 |
|
| 347 |
const form = new FormData();
|
| 348 |
form.append("video", state.videoFile);
|
|
@@ -445,8 +445,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 445 |
: `${state.hf.baseUrl}${data.stream_url}`;
|
| 446 |
log("Activating live stream...", "t");
|
| 447 |
setStreamingMode(streamUrl);
|
| 448 |
-
log("Live view available in '
|
| 449 |
-
setStatus("warn", "Live processing... View in
|
| 450 |
|
| 451 |
// Trigger resize/render for Tab 2
|
| 452 |
resizeOverlays();
|
|
@@ -459,8 +459,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 459 |
stopStreamingMode();
|
| 460 |
|
| 461 |
state.hasReasoned = true;
|
| 462 |
-
setStatus("good", "READY ·
|
| 463 |
-
log("
|
| 464 |
|
| 465 |
// Seed tracks for Tab 2
|
| 466 |
seedTracksFromTab1();
|
|
@@ -479,8 +479,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 479 |
|
| 480 |
|
| 481 |
} catch (err) {
|
| 482 |
-
setStatus("bad", "ERROR ·
|
| 483 |
-
log(`
|
| 484 |
console.error(err);
|
| 485 |
} finally {
|
| 486 |
state.isReasoning = false;
|
|
@@ -634,14 +634,14 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 634 |
}
|
| 635 |
if (btnCancelReason) btnCancelReason.style.display = "none";
|
| 636 |
|
| 637 |
-
setStatus("warn", "CANCELLED ·
|
| 638 |
setHfStatus("cancelled (stopped by user)");
|
| 639 |
-
log("
|
| 640 |
}
|
| 641 |
|
| 642 |
function runEngage() {
|
| 643 |
if (!state.hasReasoned) {
|
| 644 |
-
log("Please run
|
| 645 |
return;
|
| 646 |
}
|
| 647 |
|
|
@@ -673,7 +673,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
| 673 |
seedTracksFromTab1();
|
| 674 |
}
|
| 675 |
|
| 676 |
-
log("
|
| 677 |
}
|
| 678 |
|
| 679 |
function loop() {
|
|
|
|
| 100 |
try {
|
| 101 |
await captureFirstFrame();
|
| 102 |
// Show placeholder message - actual frame will come from backend
|
| 103 |
+
if (frameNote) frameNote.textContent = "Video loaded (run Detect for processed frame)";
|
| 104 |
+
if (engageNote) engageNote.textContent = "Ready for Track";
|
| 105 |
} catch (err) {
|
| 106 |
log(`First frame capture failed: ${err.message}`, "e");
|
| 107 |
}
|
| 108 |
|
| 109 |
+
setStatus("warn", "READY · Video loaded (run Detect)");
|
| 110 |
log(`Video loaded: ${file.name}`, "g");
|
| 111 |
|
| 112 |
// Load video-specific demo tracks (e.g., helicopter demo)
|
|
|
|
| 142 |
await recomputeHEL();
|
| 143 |
renderFrameOverlay();
|
| 144 |
|
| 145 |
+
log("Parameters recomputed.", "g");
|
| 146 |
});
|
| 147 |
}
|
| 148 |
|
|
|
|
| 175 |
btnPause.addEventListener("click", () => {
|
| 176 |
if (videoEngage) videoEngage.pause();
|
| 177 |
state.tracker.running = false;
|
| 178 |
+
log("Tracking paused.", "t");
|
| 179 |
});
|
| 180 |
}
|
| 181 |
|
|
|
|
| 190 |
state.tracker.running = false;
|
| 191 |
state.tracker.nextId = 1;
|
| 192 |
renderFrameTrackList();
|
| 193 |
+
log("Tracking reset.", "t");
|
| 194 |
});
|
| 195 |
}
|
| 196 |
|
|
|
|
| 273 |
chipFrameDepth.addEventListener("click", () => {
|
| 274 |
if (!state.videoLoaded) return;
|
| 275 |
if (!state.hf.depthFirstFrameUrl) {
|
| 276 |
+
log("First frame depth not ready yet. Run Detect and wait for depth processing.", "w");
|
| 277 |
return;
|
| 278 |
}
|
| 279 |
toggleFirstFrameDepthView();
|
|
|
|
| 309 |
}
|
| 310 |
|
| 311 |
if (state.isReasoning) {
|
| 312 |
+
log("Detection already in progress. Please wait.", "w");
|
| 313 |
return;
|
| 314 |
}
|
| 315 |
|
|
|
|
| 329 |
renderFrameTrackList();
|
| 330 |
renderFrameOverlay();
|
| 331 |
|
| 332 |
+
setStatus("warn", "DETECTING · Running perception pipeline");
|
| 333 |
|
| 334 |
// Agent cursor flair
|
| 335 |
if (state.ui.cursorMode === "on" && moveCursorToRect) {
|
|
|
|
| 342 |
const mode = detectorSelect ? detectorSelect.value : "hf_yolov8";
|
| 343 |
const queries = missionText ? missionText.value.trim() : "";
|
| 344 |
const enableGPT = $("#enableGPTToggle")?.checked || false;
|
| 345 |
+
const enableDepth = false; // depth mode disabled
|
| 346 |
|
| 347 |
const form = new FormData();
|
| 348 |
form.append("video", state.videoFile);
|
|
|
|
| 445 |
: `${state.hf.baseUrl}${data.stream_url}`;
|
| 446 |
log("Activating live stream...", "t");
|
| 447 |
setStreamingMode(streamUrl);
|
| 448 |
+
log("Live view available in 'Track' tab.", "g");
|
| 449 |
+
setStatus("warn", "Live processing... View in Track tab");
|
| 450 |
|
| 451 |
// Trigger resize/render for Tab 2
|
| 452 |
resizeOverlays();
|
|
|
|
| 459 |
stopStreamingMode();
|
| 460 |
|
| 461 |
state.hasReasoned = true;
|
| 462 |
+
setStatus("good", "READY · Detection complete (you can Track)");
|
| 463 |
+
log("Detection complete. Ready to Track.", "g");
|
| 464 |
|
| 465 |
// Seed tracks for Tab 2
|
| 466 |
seedTracksFromTab1();
|
|
|
|
| 479 |
|
| 480 |
|
| 481 |
} catch (err) {
|
| 482 |
+
setStatus("bad", "ERROR · Detection failed");
|
| 483 |
+
log(`Detection failed: ${err.message}`, "e");
|
| 484 |
console.error(err);
|
| 485 |
} finally {
|
| 486 |
state.isReasoning = false;
|
|
|
|
| 634 |
}
|
| 635 |
if (btnCancelReason) btnCancelReason.style.display = "none";
|
| 636 |
|
| 637 |
+
setStatus("warn", "CANCELLED · Detection stopped");
|
| 638 |
setHfStatus("cancelled (stopped by user)");
|
| 639 |
+
log("Detection cancelled by user.", "w");
|
| 640 |
}
|
| 641 |
|
| 642 |
function runEngage() {
|
| 643 |
if (!state.hasReasoned) {
|
| 644 |
+
log("Please run Detect first.", "w");
|
| 645 |
return;
|
| 646 |
}
|
| 647 |
|
|
|
|
| 673 |
seedTracksFromTab1();
|
| 674 |
}
|
| 675 |
|
| 676 |
+
log("Tracking started.", "g");
|
| 677 |
}
|
| 678 |
|
| 679 |
function loop() {
|
frontend/js/ui/chat.js
CHANGED
|
@@ -56,7 +56,7 @@
|
|
| 56 |
|
| 57 |
// Check if we have detections
|
| 58 |
if (!state.detections || state.detections.length === 0) {
|
| 59 |
-
appendMessage("system", "No
|
| 60 |
return;
|
| 61 |
}
|
| 62 |
|
|
@@ -66,7 +66,7 @@
|
|
| 66 |
chatInput.disabled = true;
|
| 67 |
|
| 68 |
// Show loading indicator
|
| 69 |
-
const loadingId = appendMessage("assistant", "Analyzing
|
| 70 |
|
| 71 |
try {
|
| 72 |
const response = await APP.api.client.chatAboutThreats(question, state.detections);
|
|
|
|
| 56 |
|
| 57 |
// Check if we have detections
|
| 58 |
if (!state.detections || state.detections.length === 0) {
|
| 59 |
+
appendMessage("system", "No detections yet. Run Detect first to analyze the scene.");
|
| 60 |
return;
|
| 61 |
}
|
| 62 |
|
|
|
|
| 66 |
chatInput.disabled = true;
|
| 67 |
|
| 68 |
// Show loading indicator
|
| 69 |
+
const loadingId = appendMessage("assistant", "Analyzing scene...", true);
|
| 70 |
|
| 71 |
try {
|
| 72 |
const response = await APP.api.client.chatAboutThreats(question, state.detections);
|
frontend/js/ui/intel.js
CHANGED
|
@@ -28,7 +28,7 @@ APP.ui.intel.resetIntelUI = function () {
|
|
| 28 |
const intelSummaryBox = $("#intelSummaryBox");
|
| 29 |
|
| 30 |
if (!intelSummaryBox) return;
|
| 31 |
-
intelSummaryBox.innerHTML = 'Upload a video, then click <b>
|
| 32 |
APP.ui.intel.setIntelStatus("warn", "Idle");
|
| 33 |
APP.ui.intel.setIntelThumb(0, "");
|
| 34 |
APP.ui.intel.setIntelThumb(1, "");
|
|
|
|
| 28 |
const intelSummaryBox = $("#intelSummaryBox");
|
| 29 |
|
| 30 |
if (!intelSummaryBox) return;
|
| 31 |
+
intelSummaryBox.innerHTML = 'Upload a video, then click <b>Detect</b> to generate an unbiased scene summary.';
|
| 32 |
APP.ui.intel.setIntelStatus("warn", "Idle");
|
| 33 |
APP.ui.intel.setIntelThumb(0, "");
|
| 34 |
APP.ui.intel.setIntelThumb(1, "");
|