scrypted-detection-trainer 0.1.2 → 0.1.3
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.
- package/dist/main.nodejs.js +1 -1
- package/dist/main.nodejs.js.map +1 -1
- package/dist/plugin.zip +0 -0
- package/out/main.nodejs.js +27 -12
- package/out/main.nodejs.js.map +1 -1
- package/out/plugin.zip +0 -0
- package/package.json +28 -32
- package/src/main.ts +27 -12
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/out/main.nodejs.js
CHANGED
|
@@ -1624,15 +1624,16 @@ class DetectionTrainer extends sdk_1.ScryptedDeviceBase {
|
|
|
1624
1624
|
{
|
|
1625
1625
|
key: 'info',
|
|
1626
1626
|
title: 'Detection Trainer',
|
|
1627
|
-
description: `${this.captures.size} captures stored (${[...this.captures.values()].filter(c => !c.reviewed).length} pending review, ${[...this.captures.values()].filter(c => c.reviewed && c.label !== 'discard').length} labeled)
|
|
1627
|
+
description: `${this.captures.size} captures stored (${[...this.captures.values()].filter(c => !c.reviewed).length} pending review, ${[...this.captures.values()].filter(c => c.reviewed && c.label !== 'discard').length} labeled).`,
|
|
1628
1628
|
readonly: true,
|
|
1629
1629
|
value: '',
|
|
1630
1630
|
},
|
|
1631
1631
|
{
|
|
1632
|
-
key: '
|
|
1633
|
-
title: '
|
|
1632
|
+
key: 'ui_link',
|
|
1633
|
+
title: 'Review UI',
|
|
1634
1634
|
description: 'Open the detection review and labeling interface.',
|
|
1635
|
-
|
|
1635
|
+
readonly: true,
|
|
1636
|
+
value: await sdk_1.default.endpointManager.getLocalEndpoint('scrypted-detection-trainer', { public: true }).catch(() => '/endpoint/scrypted-detection-trainer/public/'),
|
|
1636
1637
|
},
|
|
1637
1638
|
];
|
|
1638
1639
|
for (const cam of cameras) {
|
|
@@ -1649,7 +1650,7 @@ class DetectionTrainer extends sdk_1.ScryptedDeviceBase {
|
|
|
1649
1650
|
return settings;
|
|
1650
1651
|
}
|
|
1651
1652
|
async putSetting(key, value) {
|
|
1652
|
-
if (key === 'open_ui')
|
|
1653
|
+
if (key === 'open_ui' || key === 'ui_link' || key === 'info')
|
|
1653
1654
|
return;
|
|
1654
1655
|
this.storage.setItem(key, value);
|
|
1655
1656
|
if (key.startsWith('rate:')) {
|
|
@@ -1853,6 +1854,7 @@ class DetectionTrainer extends sdk_1.ScryptedDeviceBase {
|
|
|
1853
1854
|
<meta charset="UTF-8">
|
|
1854
1855
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1855
1856
|
<title>Detection Trainer</title>
|
|
1857
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
|
1856
1858
|
<style>
|
|
1857
1859
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
1858
1860
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0f0f0f; color: #e8e8e8; min-height: 100vh; }
|
|
@@ -1979,10 +1981,14 @@ class DetectionTrainer extends sdk_1.ScryptedDeviceBase {
|
|
|
1979
1981
|
<div class="toast" id="toast"></div>
|
|
1980
1982
|
|
|
1981
1983
|
<script>
|
|
1982
|
-
const BASE = location.pathname.replace(
|
|
1984
|
+
const BASE = location.pathname.replace(/\/$/, '');
|
|
1983
1985
|
let pending = [];
|
|
1984
1986
|
let labeledCount = 0;
|
|
1985
1987
|
|
|
1988
|
+
function imgError(img) {
|
|
1989
|
+
img.parentElement.innerHTML = '<div style="padding:20px;color:#555;font-size:12px;text-align:center">No image</div>';
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1986
1992
|
function showTab(name) {
|
|
1987
1993
|
document.querySelectorAll('.tab').forEach((t, i) => {
|
|
1988
1994
|
const names = ['review', 'stats', 'export'];
|
|
@@ -2024,7 +2030,7 @@ async function loadPending() {
|
|
|
2024
2030
|
return \`
|
|
2025
2031
|
<div class="detection" id="det-\${r.id}">
|
|
2026
2032
|
<div class="detection-img">
|
|
2027
|
-
<img src="\${BASE}/img/\${r.id}" alt="\${r.detectedClass}" loading="lazy" onerror="this
|
|
2033
|
+
<img src="\${BASE}/img/\${r.id}" alt="\${r.detectedClass}" loading="lazy" onerror="imgError(this)">
|
|
2028
2034
|
<div class="detection-class">\${r.detectedClass} \${score}%</div>
|
|
2029
2035
|
</div>
|
|
2030
2036
|
<div class="detection-info">
|
|
@@ -2095,7 +2101,7 @@ async function exportDataset() {
|
|
|
2095
2101
|
const btn = document.getElementById('export-btn');
|
|
2096
2102
|
const status = document.getElementById('export-status');
|
|
2097
2103
|
btn.disabled = true;
|
|
2098
|
-
status.textContent = '
|
|
2104
|
+
status.textContent = 'Fetching data…';
|
|
2099
2105
|
|
|
2100
2106
|
try {
|
|
2101
2107
|
const res = await fetch(BASE + '/api/export');
|
|
@@ -2103,13 +2109,22 @@ async function exportDataset() {
|
|
|
2103
2109
|
const data = await res.json();
|
|
2104
2110
|
if (data.error) { status.textContent = data.error; btn.disabled = false; return; }
|
|
2105
2111
|
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
const
|
|
2112
|
+
status.textContent = 'Building zip…';
|
|
2113
|
+
|
|
2114
|
+
const zip = new JSZip();
|
|
2115
|
+
for (const f of data.files) {
|
|
2116
|
+
if (f.encoding === 'base64') {
|
|
2117
|
+
zip.file(f.filename, f.content, { base64: true });
|
|
2118
|
+
} else {
|
|
2119
|
+
zip.file(f.filename, f.content);
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
const blob = await zip.generateAsync({ type: 'blob', compression: 'DEFLATE' });
|
|
2109
2124
|
const url = URL.createObjectURL(blob);
|
|
2110
2125
|
const a = document.createElement('a');
|
|
2111
2126
|
a.href = url;
|
|
2112
|
-
a.download = 'scrypted_dataset_' + new Date().toISOString().slice(0,10) + '.
|
|
2127
|
+
a.download = 'scrypted_dataset_' + new Date().toISOString().slice(0,10) + '.zip';
|
|
2113
2128
|
a.click();
|
|
2114
2129
|
URL.revokeObjectURL(url);
|
|
2115
2130
|
status.textContent = \`Downloaded \${data.count} samples.\`;
|