HanningChen commited on
Commit
af40191
Β·
1 Parent(s): 398e700

update front page

Browse files
webui/runner.py CHANGED
@@ -485,7 +485,14 @@ class ModelRunner:
485
  tgt = bbox_embeddings
486
  memory = text_embeddings
487
  image_embedding_2d = image_embedding.view(1, -1)
488
- _, _, score_res, _ = taskclip(tgt, memory, image_embedding_2d)
 
 
 
 
 
 
 
489
  score = score_res.view(-1).detach().cpu().numpy().tolist()
490
 
491
  # post-process
 
485
  tgt = bbox_embeddings
486
  memory = text_embeddings
487
  image_embedding_2d = image_embedding.view(1, -1)
488
+ _, _, score_res, _ = taskclip(
489
+ tgt,
490
+ memory,
491
+ image_embedding_2d,
492
+ hw_noise_dist=hw_noise_dist,
493
+ hw_noise_width=int(hw_noise_width),
494
+ hw_noise_strength=int(hw_noise_strength),
495
+ hdc_bits=hdc_bits)
496
  score = score_res.view(-1).detach().cpu().numpy().tolist()
497
 
498
  # post-process
webui/static/main.js CHANGED
@@ -33,6 +33,7 @@ const dlSelected = $("#dlSelected");
33
  const copyMetaBtn = $("#copyMetaBtn");
34
 
35
  function setStatus(kind, text, logLine) {
 
36
  statusDot.className = `dot ${kind}`;
37
  statusText.textContent = text;
38
  if (logLine) statusLog.textContent = logLine + "\n" + statusLog.textContent;
@@ -70,6 +71,112 @@ function setPreview(file) {
70
  previewWrap.classList.remove("hidden");
71
  }
72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  dropzone.addEventListener("click", () => fileInput.click());
74
  dropzone.addEventListener("keydown", (e) => {
75
  if (e.key === "Enter" || e.key === " ") fileInput.click();
@@ -100,8 +207,10 @@ dropzone.addEventListener("drop", (e) => {
100
  const file = e.dataTransfer.files && e.dataTransfer.files[0];
101
  if (!file) return;
102
 
 
103
  setPreview(file);
104
 
 
105
  const dt = new DataTransfer();
106
  dt.items.add(file);
107
  fileInput.files = dt.files;
@@ -139,33 +248,28 @@ form.addEventListener("submit", async (e) => {
139
 
140
  try {
141
  const resp = await fetch("/api/run", { method: "POST", body: fd });
 
142
 
143
- // Read as text first so we can show raw errors if not JSON
144
- const text = await resp.text();
145
- let data;
146
- try {
147
- data = JSON.parse(text);
148
- } catch {
149
- throw new Error(`Server returned non-JSON (HTTP ${resp.status}): ${text.slice(0, 300)}`);
150
- }
151
-
152
- if (!resp.ok || data.ok === false) {
153
- throw new Error(data.error || `Request failed: HTTP ${resp.status}`);
154
  }
155
 
156
  jobPill.textContent = `job: ${data.job_id}`;
157
  setStatus("ok", "Done", `Inference finished. job_id=${data.job_id}`);
158
 
 
159
  const bust = `t=${Date.now()}`;
160
  imgInput.src = `${data.image_urls.input}?${bust}`;
161
  imgYolo.src = `${data.image_urls.yolo}?${bust}`;
162
  imgSelected.src = `${data.image_urls.selected}?${bust}`;
163
 
 
164
  dlInput.href = data.image_urls.input;
165
  dlYolo.href = data.image_urls.yolo;
166
  dlSelected.href = data.image_urls.selected;
167
  [dlInput, dlYolo, dlSelected].forEach(a => a.classList.remove("hidden"));
168
 
 
169
  meta.textContent = JSON.stringify({
170
  task_id: data.task_id,
171
  task_name: data.task_name,
@@ -178,4 +282,4 @@ form.addEventListener("submit", async (e) => {
178
  } finally {
179
  setRunning(false);
180
  }
181
- });
 
33
  const copyMetaBtn = $("#copyMetaBtn");
34
 
35
  function setStatus(kind, text, logLine) {
36
+ // kind: idle | run | ok | bad
37
  statusDot.className = `dot ${kind}`;
38
  statusText.textContent = text;
39
  if (logLine) statusLog.textContent = logLine + "\n" + statusLog.textContent;
 
71
  previewWrap.classList.remove("hidden");
72
  }
73
 
74
+ (function () {
75
+ const noiseType = document.getElementById("noiseType");
76
+ if (!noiseType) return;
77
+
78
+ const panels = {
79
+ none: document.getElementById("noisePanelNone"),
80
+ gaussian: document.getElementById("noisePanelGaussian"),
81
+ linear: document.getElementById("noisePanelLinear"),
82
+ adv: document.getElementById("noisePanelAdv"),
83
+ };
84
+
85
+ const sliders = {
86
+ gaussian: document.getElementById("noiseGaussian"),
87
+ linear: document.getElementById("noiseLinear"),
88
+ adv: document.getElementById("noiseAdv"),
89
+ };
90
+
91
+ const labels = {
92
+ gaussian: document.getElementById("noiseValGaussian"),
93
+ linear: document.getElementById("noiseValLinear"),
94
+ adv: document.getElementById("noiseValAdv"),
95
+ };
96
+
97
+ const hiddenStrength = document.getElementById("noiseStrength");
98
+
99
+ // Map dropdown values to ONE of the existing panel keys.
100
+ function noiseFamily(val) {
101
+ const t = String(val || "none").toLowerCase();
102
+
103
+ if (t === "none" || t === "off") return "none";
104
+
105
+ // gaussian variants
106
+ if (t === "gaussian" || t.includes("gauss")) return "gaussian";
107
+
108
+ // linear variants
109
+ if (t === "linear" || t.includes("linear")) return "linear";
110
+
111
+ // adversarial variants (covers: "simple_adversarial_noise", "fgsm", "pgd", etc.)
112
+ if (
113
+ t === "adv" ||
114
+ t.startsWith("adv") ||
115
+ t.includes("adversarial") ||
116
+ t.includes("attack") ||
117
+ t.includes("fgsm") ||
118
+ t.includes("pgd")
119
+ ) return "adv";
120
+
121
+ return "none";
122
+ }
123
+
124
+
125
+ function updateHiddenStrength() {
126
+ const fam = noiseFamily(noiseType.value);
127
+ if (fam === "none") {
128
+ hiddenStrength.value = "0";
129
+ return;
130
+ }
131
+ hiddenStrength.value = String(sliders[fam]?.value ?? "0");
132
+ }
133
+
134
+ function showPanelForCurrentSelection() {
135
+ const fam = noiseFamily(noiseType.value);
136
+ Object.values(panels).forEach((p) => p && p.classList.add("hidden"));
137
+ (panels[fam] || panels.none).classList.remove("hidden");
138
+ updateHiddenStrength();
139
+ }
140
+
141
+ // Slider updates
142
+ Object.keys(sliders).forEach((k) => {
143
+ sliders[k]?.addEventListener("input", () => {
144
+ if (labels[k]) labels[k].textContent = sliders[k].value;
145
+ if (noiseFamily(noiseType.value) === k) updateHiddenStrength();
146
+ });
147
+ });
148
+
149
+ // Dropdown updates
150
+ noiseType.addEventListener("change", showPanelForCurrentSelection);
151
+
152
+ // Initialize from current dropdown value (NOT hard-coded none)
153
+ showPanelForCurrentSelection();
154
+ })();
155
+
156
+ (function () {
157
+ // Tabs
158
+ const tabBtns = document.querySelectorAll(".tabBtn");
159
+ const panels = document.querySelectorAll(".tabPanel");
160
+ tabBtns.forEach((b) => {
161
+ b.addEventListener("click", () => {
162
+ tabBtns.forEach((x) => x.classList.remove("active"));
163
+ panels.forEach((p) => p.classList.add("hidden"));
164
+ b.classList.add("active");
165
+ const id = b.getAttribute("data-tab");
166
+ document.getElementById(id)?.classList.remove("hidden");
167
+ });
168
+ });
169
+
170
+ // Hardware noise sliders -> label text
171
+ const w = document.getElementById("hwNoiseWidth");
172
+ const s = document.getElementById("hwNoiseStrength");
173
+ const wv = document.getElementById("hwNoiseWidthVal");
174
+ const sv = document.getElementById("hwNoiseStrengthVal");
175
+ if (w && wv) w.addEventListener("input", () => (wv.textContent = w.value));
176
+ if (s && sv) s.addEventListener("input", () => (sv.textContent = s.value));
177
+ })();
178
+
179
+
180
  dropzone.addEventListener("click", () => fileInput.click());
181
  dropzone.addEventListener("keydown", (e) => {
182
  if (e.key === "Enter" || e.key === " ") fileInput.click();
 
207
  const file = e.dataTransfer.files && e.dataTransfer.files[0];
208
  if (!file) return;
209
 
210
+ // Set preview
211
  setPreview(file);
212
 
213
+ // Safely assign to input (works across browsers)
214
  const dt = new DataTransfer();
215
  dt.items.add(file);
216
  fileInput.files = dt.files;
 
248
 
249
  try {
250
  const resp = await fetch("/api/run", { method: "POST", body: fd });
251
+ const data = await resp.json();
252
 
253
+ if (!resp.ok || !data.ok) {
254
+ throw new Error(data?.error || `HTTP ${resp.status}`);
 
 
 
 
 
 
 
 
 
255
  }
256
 
257
  jobPill.textContent = `job: ${data.job_id}`;
258
  setStatus("ok", "Done", `Inference finished. job_id=${data.job_id}`);
259
 
260
+ // Update images (cache-bust)
261
  const bust = `t=${Date.now()}`;
262
  imgInput.src = `${data.image_urls.input}?${bust}`;
263
  imgYolo.src = `${data.image_urls.yolo}?${bust}`;
264
  imgSelected.src = `${data.image_urls.selected}?${bust}`;
265
 
266
+ // Open links
267
  dlInput.href = data.image_urls.input;
268
  dlYolo.href = data.image_urls.yolo;
269
  dlSelected.href = data.image_urls.selected;
270
  [dlInput, dlYolo, dlSelected].forEach(a => a.classList.remove("hidden"));
271
 
272
+ // Meta
273
  meta.textContent = JSON.stringify({
274
  task_id: data.task_id,
275
  task_name: data.task_name,
 
282
  } finally {
283
  setRunning(false);
284
  }
285
+ });
webui/static/style.css CHANGED
@@ -170,6 +170,12 @@ select:focus, input[type="text"]:focus, textarea:focus{border-color: rgba(106,22
170
 
171
  .tinyBtn{padding:8px 10px; font-weight:900}
172
  .hidden{display:none !important}
 
 
 
 
 
 
173
 
174
  /* Spinner */
175
  .spinner{
 
170
 
171
  .tinyBtn{padding:8px 10px; font-weight:900}
172
  .hidden{display:none !important}
173
+ .hidden { display: none; }
174
+ .tabBar { display: flex; gap: 8px; margin: 8px 0 12px; }
175
+ .tabBtn { padding: 8px 10px; border-radius: 10px; border: 1px solid rgba(255,255,255,.12); background: transparent; color: inherit; cursor: pointer; }
176
+ .tabBtn.active { background: rgba(255,255,255,.08); }
177
+ .tabPanel { margin-top: 8px; }
178
+
179
 
180
  /* Spinner */
181
  .spinner{
webui/templates/index.html CHANGED
@@ -5,7 +5,6 @@
5
  <meta name="viewport" content="width=device-width,initial-scale=1" />
6
  <title>TaskCLIP Web UI</title>
7
 
8
- <!-- Fonts / Icons (same β€œstyle family” as your advisor’s demo) -->
9
  <link rel="preconnect" href="https://fonts.googleapis.com">
10
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
@@ -16,8 +15,6 @@
16
 
17
  <body>
18
  <div class="app">
19
-
20
- <!-- Left: Controls -->
21
  <aside class="sidebar">
22
  <div class="sideTop">
23
  <div class="sideTitle">
@@ -56,6 +53,19 @@
56
  </select>
57
  </div>
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  <div class="field">
60
  <label>HDV Dim</label>
61
  <select name="hdv_dim">
@@ -79,10 +89,10 @@
79
  </div>
80
 
81
  <div class="field">
82
- <label>Task ID</label>
83
  <select name="task_id">
84
- {% for t in task_ids %}
85
- <option value="{{t}}">{{t}}</option>
86
  {% endfor %}
87
  </select>
88
  </div>
@@ -98,12 +108,94 @@
98
 
99
  <div class="divider"></div>
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  <div class="field">
102
  <label>Upload Image</label>
103
 
104
  <input id="fileInput" name="upload" type="file" accept="image/*" class="fileHidden" required />
105
 
106
- <!-- Fancy dropzone -->
107
  <div id="dropzone" class="dropzone" role="button" tabindex="0">
108
  <div class="dzLeft">
109
  <i class="fa-solid fa-file-arrow-up"></i>
@@ -152,7 +244,6 @@
152
  </div>
153
  </aside>
154
 
155
- <!-- Right: Results -->
156
  <main class="main">
157
  <header class="topbar card">
158
  <div class="topLeft">
 
5
  <meta name="viewport" content="width=device-width,initial-scale=1" />
6
  <title>TaskCLIP Web UI</title>
7
 
 
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
 
15
 
16
  <body>
17
  <div class="app">
 
 
18
  <aside class="sidebar">
19
  <div class="sideTop">
20
  <div class="sideTitle">
 
53
  </select>
54
  </div>
55
 
56
+ <div class="field" id="hdcBitsField" style="display:none;">
57
+ <label>HDC Precision</label>
58
+ <select name="hdc_bits" id="hdcBits">
59
+ <option value="1">1-bit</option>
60
+ <option value="2">2-bit</option>
61
+ <option value="4">4-bit</option>
62
+ <option value="8">8-bit</option>
63
+ <option value="16">16-bit (fp16/bf16)</option>
64
+ <option value="32" selected>32-bit (fp32)</option>
65
+ </select>
66
+ <div class="hint">Applies to HDC score function only (weights + activations).</div>
67
+ </div>
68
+
69
  <div class="field">
70
  <label>HDV Dim</label>
71
  <select name="hdv_dim">
 
89
  </div>
90
 
91
  <div class="field">
92
+ <label>Task</label>
93
  <select name="task_id">
94
+ {% for tid, tname in task_items %}
95
+ <option value="{{tid}}">{{tid}} β€” {{tname}}</option>
96
  {% endfor %}
97
  </select>
98
  </div>
 
108
 
109
  <div class="divider"></div>
110
 
111
+ <div class="sectionTitle">
112
+ <i class="fa-solid fa-microchip"></i>
113
+ <span>Noise</span>
114
+ </div>
115
+
116
+ <div class="tabBar">
117
+ <button type="button" class="tabBtn active" data-tab="tabInputNoise">Input noise</button>
118
+ <button type="button" class="tabBtn" data-tab="tabHwNoise">Hardware related noise</button>
119
+ </div>
120
+
121
+ <!-- βœ… FIX: input noise UI must be INSIDE this tab panel -->
122
+ <div class="tabPanel" id="tabInputNoise">
123
+ <div class="field">
124
+ <label>Input Noise</label>
125
+ <select name="noise_type" id="noiseType">
126
+ <option value="none" selected>default (no noise)</option>
127
+ <option value="gaussian">Gaussian noise</option>
128
+ <option value="linear">Linear noise</option>
129
+ <option value="adv">Simple adversarial noise</option>
130
+ <option value="adv_rand_sign">Adversarial: random sign (fast)</option>
131
+ <option value="adv_edge_sign">Adversarial: edge-sign (Laplacian)</option>
132
+ <option value="adv_patch">Adversarial: patch occlusion/noise</option>
133
+ <option value="adv_stripes">Adversarial: stripe/periodic</option>
134
+ <option value="adv_jpeg">Adversarial: JPEG compression artifacts</option>
135
+ </select>
136
+ <div class="hint">Applies noise to the uploaded image before running YOLO/TaskCLIP</div>
137
+ </div>
138
+
139
+ <div class="field" id="noisePanelNone">
140
+ <label>Noise Strength</label>
141
+ <div class="hint">No noise (strength ignored)</div>
142
+ </div>
143
+
144
+ <div class="field hidden" id="noisePanelGaussian">
145
+ <label>Gaussian Strength: <span class="mono" id="noiseValGaussian">0</span></label>
146
+ <input type="range" min="0" max="100" value="0" name="noise_strength_gaussian" id="noiseGaussian" />
147
+ <div class="hint">0–100 β†’ sigma scaling</div>
148
+ </div>
149
+
150
+ <div class="field hidden" id="noisePanelLinear">
151
+ <label>Linear Strength: <span class="mono" id="noiseValLinear">0</span></label>
152
+ <input type="range" min="0" max="100" value="0" name="noise_strength_linear" id="noiseLinear" />
153
+ <div class="hint">0–100 β†’ gradient amplitude</div>
154
+ </div>
155
+
156
+ <div class="field hidden" id="noisePanelAdv">
157
+ <label>Adversarial Strength: <span class="mono" id="noiseValAdv">0</span></label>
158
+ <input type="range" min="0" max="100" value="0" name="noise_strength_adv" id="noiseAdv" />
159
+ <div class="hint">0–100 β†’ adversarial-style perturbation strength</div>
160
+ </div>
161
+
162
+ <input type="hidden" name="noise_strength" id="noiseStrength" value="0" />
163
+ </div>
164
+
165
+ <div class="tabPanel hidden" id="tabHwNoise">
166
+ <div class="grid2">
167
+ <div class="field">
168
+ <label>Hardware noise distribution</label>
169
+ <select name="hw_noise_dist" id="hwNoiseDist">
170
+ <option value="none" selected>default (no noise)</option>
171
+ <option value="gaussian">Gaussian</option>
172
+ <option value="uniform">Uniform</option>
173
+ <option value="laplace">Laplace</option>
174
+ </select>
175
+ <div class="hint">Injected into TaskCLIP scoring (score_raw) before the score function.</div>
176
+ </div>
177
+
178
+ <div class="field">
179
+ <label>Width: <span class="mono" id="hwNoiseWidthVal">0</span></label>
180
+ <input type="range" min="0" max="100" value="0" name="hw_noise_width" id="hwNoiseWidth" />
181
+ <div class="hint">Controls Οƒ (Gaussian), range (Uniform), b (Laplace)</div>
182
+ </div>
183
+
184
+ <div class="field">
185
+ <label>Strength: <span class="mono" id="hwNoiseStrengthVal">0</span></label>
186
+ <input type="range" min="0" max="100" value="0" name="hw_noise_strength" id="hwNoiseStrength" />
187
+ <div class="hint">Scales injected noise amplitude</div>
188
+ </div>
189
+ </div>
190
+ </div>
191
+
192
+ <div class="divider"></div>
193
+
194
  <div class="field">
195
  <label>Upload Image</label>
196
 
197
  <input id="fileInput" name="upload" type="file" accept="image/*" class="fileHidden" required />
198
 
 
199
  <div id="dropzone" class="dropzone" role="button" tabindex="0">
200
  <div class="dzLeft">
201
  <i class="fa-solid fa-file-arrow-up"></i>
 
244
  </div>
245
  </aside>
246
 
 
247
  <main class="main">
248
  <header class="topbar card">
249
  <div class="topLeft">