Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 67 additions & 4 deletions web_ui/packages/smart-tools/src/utils/opencv-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,79 @@

import type { OpenCVTypes } from '../opencv/interfaces';

const READY_CHECK_INTERVAL_MS = 100;
const OPENCV_LOAD_TIMEOUT_MS = 30_000;

let opencv: OpenCVTypes | null = null;
let loadingPromise: Promise<OpenCVTypes> | null = null;

function delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}

/**
* Wait for cv.ready to be available with polling
* Some OpenCV builds delay initialization of cv.ready
*/
const waitForOpenCVReady = async (cv: OpenCVTypes): Promise<void> => {
const startTime = Date.now();

while (Date.now() - startTime < OPENCV_LOAD_TIMEOUT_MS) {
// Check if cv.ready exists and is a Promise-like object
if (cv && typeof cv.ready === 'object' && 'then' in cv.ready) {
try {
await cv.ready;
return; // Success
} catch (error) {
console.error('Error waiting for cv.ready:', error);
throw error;
}
}

// Check if cv.ready is already resolved (some builds may have it pre-resolved)
if (cv && cv.onload && typeof cv.onload === 'function') {
return;
}
Comment on lines +35 to +38
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check for cv.onload is ineffective for determining if OpenCV is ready. The presence of an onload function doesn't guarantee initialization is complete. This could lead to returning before OpenCV is actually ready to use, causing subsequent operations to fail.

Suggested change
// Check if cv.ready is already resolved (some builds may have it pre-resolved)
if (cv && cv.onload && typeof cv.onload === 'function') {
return;
}
// (Removed ineffective check for cv.onload)

Copilot uses AI. Check for mistakes.

// cv.ready not available yet, wait and retry
await delay(READY_CHECK_INTERVAL_MS);
}

throw new Error(
`Timeout waiting for cv.ready (${OPENCV_LOAD_TIMEOUT_MS}ms). ` +
'OpenCV may not be properly built or the file is corrupted.'
);
};

export const OpenCVLoader = async (): Promise<OpenCVTypes> => {
if (opencv) return opencv;
if (loadingPromise) return loadingPromise;

const cv: OpenCVTypes = await import('../opencv/4.9.0/opencv.js');
loadingPromise = Promise.race([
(async () => {
try {
const cv: OpenCVTypes = await import('../opencv/4.9.0/opencv.js');

if ('ready' in cv) await cv.ready;
// Wait for cv.ready with polling and timeout
await waitForOpenCVReady(cv);

opencv = cv;
if (!cv.Mat) {
throw new Error('OpenCV missing essential methods');
}
opencv = cv;
return opencv;
} catch (error) {
loadingPromise = null;
throw error;
}
})(),
new Promise<never>((_, reject) =>
setTimeout(
() => reject(new Error(`OpenCV loading timeout (${OPENCV_LOAD_TIMEOUT_MS}ms)`)),
OPENCV_LOAD_TIMEOUT_MS
)
),
]);
Comment on lines +54 to +78
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The timeout Promise in the race is redundant since waitForOpenCVReady already implements the same timeout. This creates two separate 30-second timers that could reject with different error messages, making debugging confusing. Remove the outer Promise.race wrapper and rely on the timeout in waitForOpenCVReady.

Copilot uses AI. Check for mistakes.

return opencv;
return loadingPromise;
};
Loading