edge-impulse-linux 1.17.1 → 1.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/build/cli/linux/runner-utils.d.ts +1 -0
  2. package/build/cli/linux/runner-utils.js +73 -15
  3. package/build/cli/linux/runner-utils.js.map +1 -1
  4. package/build/cli/linux/runner.js +42 -7
  5. package/build/cli/linux/runner.js.map +1 -1
  6. package/build/cli/linux/webserver/public/webserver.js +124 -17
  7. package/build/cli/linux/webserver/public/webserver.js.map +1 -1
  8. package/build/cli/linux/webserver/views/index.js +5 -3
  9. package/build/cli/linux/webserver/views/index.js.map +1 -1
  10. package/build/library/classifier/image-classifier.d.ts +4 -1
  11. package/build/library/classifier/image-classifier.js +4 -4
  12. package/build/library/classifier/image-classifier.js.map +1 -1
  13. package/build/sdk/studio/sdk/api/rawDataApi.d.ts +55 -1
  14. package/build/sdk/studio/sdk/api/rawDataApi.js +166 -1
  15. package/build/sdk/studio/sdk/api/rawDataApi.js.map +1 -1
  16. package/build/sdk/studio/sdk/model/batchEditBoundingBoxesRequest.d.ts +32 -0
  17. package/build/sdk/studio/sdk/model/batchEditBoundingBoxesRequest.js +34 -0
  18. package/build/sdk/studio/sdk/model/batchEditBoundingBoxesRequest.js.map +1 -0
  19. package/build/sdk/studio/sdk/model/models.d.ts +1 -0
  20. package/build/sdk/studio/sdk/model/models.js +3 -0
  21. package/build/sdk/studio/sdk/model/models.js.map +1 -1
  22. package/build/sdk/studio/sdk/model/permission.d.ts +1 -1
  23. package/build/sdk/studio/sdk/model/permission.js +1 -1
  24. package/build/sdk/studio/sdk/model/permission.js.map +1 -1
  25. package/cli/linux/webserver/public/assets/mobileclient.css +26 -3
  26. package/cli/linux/webserver/public/webserver.js +136 -17
  27. package/package.json +1 -1
@@ -2,6 +2,7 @@ window.WebServer = async () => {
2
2
 
3
3
  const els = {
4
4
  title: document.querySelector('#header-row h1'),
5
+ cameraOuterContainer: document.querySelector('#capture-camera .capture-camera-outer'),
5
6
  cameraContainer: document.querySelector('#capture-camera .capture-camera-inner'),
6
7
  cameraImg: document.querySelector('#capture-camera img'),
7
8
  timePerInference: document.querySelector('#time-per-inference'),
@@ -29,6 +30,9 @@ window.WebServer = async () => {
29
30
  ];
30
31
  let colorIx = 0;
31
32
  const labelToColor = { };
33
+ let isFirstClassification = true;
34
+ let inferenceIx = 0;
35
+ let lastClassification;
32
36
 
33
37
  function switchView(el) {
34
38
  for (let k of Object.keys(els.views)) {
@@ -150,6 +154,7 @@ window.WebServer = async () => {
150
154
  inputEl.oninput = () => {
151
155
  if (typeof threshold[k] === 'number') {
152
156
  if (!inputEl.value || isNaN(Number(inputEl.value))) return;
157
+ if (k === 'min_score' && Number(inputEl.value) === 0) return;
153
158
 
154
159
  threshold[k] = Number(inputEl.value);
155
160
  }
@@ -194,14 +199,65 @@ window.WebServer = async () => {
194
199
  bindThresholdSettings(opts.thresholds);
195
200
  });
196
201
 
202
+ const onWindowResize = () => {
203
+ if (els.cameraContainer.naturalWidth === 0) {
204
+ return;
205
+ }
206
+
207
+ let oldStyleWidth = els.cameraImg.style.width;
208
+ const containerWidth = els.cameraOuterContainer.getBoundingClientRect().width;
209
+
210
+ // height >480
211
+ if (els.cameraImg.naturalHeight > 480) {
212
+ // and fits within the container? just display as is
213
+ if (els.cameraImg.naturalWidth < containerWidth) {
214
+ els.cameraImg.style.width = els.cameraImg.naturalWidth + 'px';
215
+ }
216
+ else {
217
+ // does not fit within container? just use 100%
218
+ els.cameraImg.style.width = containerWidth + 'px';
219
+ }
220
+ }
221
+ else {
222
+ // what if we resize to 480 high?
223
+ const factor = els.cameraImg.naturalWidth / els.cameraImg.naturalHeight;
224
+ let newHeight = 480;
225
+ let newWidth = newHeight * factor;
226
+
227
+ // fits within the container? just display as is
228
+ if (newWidth < containerWidth) {
229
+ els.cameraImg.style.width = newWidth + 'px';
230
+ }
231
+ else {
232
+ // does not fit within container? just use 100%
233
+ els.cameraImg.style.width = containerWidth + 'px';
234
+ }
235
+ }
236
+
237
+ if (oldStyleWidth !== els.cameraImg.style.width && lastClassification) {
238
+ onClassification({
239
+ dontUpdateTable: true,
240
+ ...lastClassification,
241
+ });
242
+ }
243
+ };
244
+
245
+ let isFirstImage = true;
197
246
  socket.on('image', (opts) => {
247
+ if (isFirstImage) {
248
+ els.cameraImg.onload = () => {
249
+ onWindowResize();
250
+ els.cameraImg.onload = null;
251
+ };
252
+ isFirstImage = false;
253
+ }
198
254
  els.cameraImg.src = opts.img;
199
255
  });
256
+ window.addEventListener('resize', onWindowResize);
200
257
 
201
- let isFirstClassification = true;
202
- let inferenceIx = 0;
258
+ function onClassification(opts) {
259
+ lastClassification = opts;
203
260
 
204
- socket.on('classification', (opts) => {
205
261
  let result = opts.result;
206
262
  let modelType = opts.modelType;
207
263
 
@@ -218,16 +274,39 @@ window.WebServer = async () => {
218
274
 
219
275
  els.imageClassify.row.style.display = 'none';
220
276
 
221
- if (result.classification) {
277
+ if (result.classification && !opts.dontUpdateTable) {
278
+ const showOnlyTopResults = Object.keys(result.classification).length > 10 && !result.visual_anomaly_grid;
279
+
222
280
  if (isFirstClassification) {
223
- for (let ix = 0; ix < Object.keys(result.classification).length; ix++) {
224
- const key = Object.keys(result.classification)[ix];
281
+ if (showOnlyTopResults) {
282
+ // only 1 results th
283
+ {
284
+ let th = document.createElement('th');
285
+ th.scope = 'col';
286
+ th.textContent = th.title = 'Top 5 results';
287
+ th.classList.add('px-0', 'text-center');
288
+ els.resultsThead.appendChild(th);
289
+ }
225
290
 
226
- let th = document.createElement('th');
227
- th.scope = 'col';
228
- th.classList.add('px-0', 'text-center');
229
- th.textContent = th.title = key;
230
- els.resultsThead.appendChild(th);
291
+ // unless also have anomaly...
292
+ if (Object.keys(result.classification).indexOf('anomaly') > -1) {
293
+ let th = document.createElement('th');
294
+ th.scope = 'col';
295
+ th.textContent = th.title = 'anomaly';
296
+ th.classList.add('px-0', 'text-center');
297
+ els.resultsThead.appendChild(th);
298
+ }
299
+ }
300
+ else {
301
+ for (let ix = 0; ix < Object.keys(result.classification).length; ix++) {
302
+ const key = Object.keys(result.classification)[ix];
303
+
304
+ let th = document.createElement('th');
305
+ th.scope = 'col';
306
+ th.classList.add('px-0', 'text-center');
307
+ th.textContent = th.title = key;
308
+ els.resultsThead.appendChild(th);
309
+ }
231
310
  }
232
311
 
233
312
  if (result.visual_anomaly_grid) {
@@ -264,15 +343,53 @@ window.WebServer = async () => {
264
343
  let td1 = document.createElement('td');
265
344
  td1.textContent = (++inferenceIx).toString();
266
345
  tr.appendChild(td1);
267
- for (let k of Object.keys(result.classification)) {
346
+ if (showOnlyTopResults) {
347
+ // only print top 5
268
348
  let td = document.createElement('td');
269
- td.classList.add('text-center');
270
- td.textContent = result.classification[k].toFixed(2);
271
- if (result.classification[k] === highest && !isVisualAnomaly) {
272
- td.style.fontWeight = 600;
349
+
350
+ let results = [];
351
+ for (const key of Object.keys(result.classification)) {
352
+ if (key === 'anomaly') continue;
353
+
354
+ results.push({
355
+ label: key,
356
+ value: result.classification[key],
357
+ });
358
+ }
359
+
360
+ const top = results.sort((a, b) => b.value - a.value).slice(0, 5);
361
+ for (let ix = 0; ix < top.length; ix++) {
362
+ let span = ix === 0 ? document.createElement('strong') : document.createElement('span');
363
+ span.textContent = `${top[ix].label}: ${top[ix].value.toFixed(2)}`;
364
+ td.appendChild(span);
365
+
366
+ if (ix !== top.length - 1) {
367
+ let commaSpan = document.createElement('span');
368
+ commaSpan.textContent = ', ';
369
+ td.appendChild(commaSpan);
370
+ }
273
371
  }
274
372
  tr.appendChild(td);
373
+
374
+ if (Object.keys(result.classification).indexOf('anomaly') > -1) {
375
+ let anomalyTd = document.createElement('td');
376
+ anomalyTd.classList.add('text-center');
377
+ anomalyTd.textContent = result.classification.anomaly.toFixed(2);
378
+ tr.appendChild(anomalyTd);
379
+ }
380
+ }
381
+ else {
382
+ for (let k of Object.keys(result.classification)) {
383
+ let td = document.createElement('td');
384
+ td.classList.add('text-center');
385
+ td.textContent = result.classification[k].toFixed(2);
386
+ if (result.classification[k] === highest && !isVisualAnomaly) {
387
+ td.style.fontWeight = 600;
388
+ }
389
+ tr.appendChild(td);
390
+ }
275
391
  }
392
+
276
393
  if (result.visual_anomaly_grid) {
277
394
  let td = document.createElement('td');
278
395
  td.classList.add('text-center');
@@ -406,7 +523,9 @@ window.WebServer = async () => {
406
523
  els.cameraContainer.appendChild(el);
407
524
  }
408
525
  }
409
- });
526
+ }
527
+
528
+ socket.on('classification', onClassification);
410
529
 
411
530
  if (els.websocketAddress) {
412
531
  els.websocketAddress.textContent = `ws://${location.host}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edge-impulse-linux",
3
- "version": "1.17.1",
3
+ "version": "1.17.2",
4
4
  "description": "Node.js SDK and tools for Edge Impulse for Linux",
5
5
  "directories": {
6
6
  "example": "examples"