Refactor: load panel detection libs from vendor dir

Update PanelDetector to load OpenCV, TensorFlow.js, and COCO-SSD
from local vendor directory instead of importing npm packages.
This ensures the libraries are available after build and avoids
runtime dependency resolution issues.

- Change imports to use ../vendor paths instead of npm packages
- Add caching to prevent reloading libraries
- Add error handling for failed library loads with console warnings
- Update OpenCV loading to handle both default and named exports
This commit is contained in:
2026-04-13 18:50:19 -04:00
parent fc29b463f4
commit 1223876b9d
2 changed files with 45 additions and 23 deletions
+32 -15
View File
@@ -97,23 +97,40 @@ export class PanelDetector {
}
async #loadOpenCV() {
const { default: cv } = await import("@techstark/opencv-js");
await new Promise((resolve, reject) => {
const check = () => {
if (cv && cv.Mat) resolve();
else if (!cv || cv.readyState === "complete")
reject(new Error("OpenCV failed to load"));
else setTimeout(check, 50);
};
check();
});
return cv;
}
if (this.#opencv) return this.#opencv;
try {
const cv = await import("../vendor/opencv/opencv.js");
await new Promise((resolve, reject) => {
const check = () => {
if (cv && cv.Mat) resolve();
else if (cv.readyState === "complete")
reject(new Error("OpenCV failed to load"));
else setTimeout(check, 50);
};
check();
});
this.#opencv = cv.default || cv;
return this.#opencv;
} catch (e) {
console.warn("Failed to load OpenCV:", e);
return null;
}
}
async #loadModel() {
const tf = await import("@tensorflow/tfjs");
const cocoSsd = await import("@tensorflow-models/coco-ssd");
return await cocoSsd.load({ base: "lite_mobilenet_v2" });
if (this.#model) return this.#model;
try {
await import("../vendor/tfjs/tf.min.js");
const cocoSsd = await import("../vendor/coco-ssd/coco-ssd.min.js");
this.#model = await cocoSsd.load({ base: "lite_mobilenet_v2" });
return this.#model;
} catch (e) {
console.warn("Failed to load ML model:", e);
return null;
}
}
clear() {
+13 -8
View File
@@ -104,18 +104,23 @@ class Reader {
{
name: "panel-mode",
label: "Panel Mode",
type: "checkbox",
checked: false,
onclick: () => {
// ← No 'value' parameter for checkbox
type: "radio",
items: [
["Off", "off"],
["On", "on"],
],
onclick: (value) => {
const renderer = this.view?.renderer;
if (!renderer?.togglePanelMode) return;
const isActive = renderer.hasAttribute("panel-mode");
if (isActive) {
renderer.removeAttribute("panel-mode");
if (value === "on") {
if (!renderer.hasAttribute("panel-mode")) {
renderer.togglePanelMode();
}
} else {
renderer.togglePanelMode();
if (renderer.hasAttribute("panel-mode")) {
renderer.togglePanelMode();
}
}
},
},