diff --git a/src/backends/onnx.js b/src/backends/onnx.js index a64f9d160..396a9b0ac 100644 --- a/src/backends/onnx.js +++ b/src/backends/onnx.js @@ -180,9 +180,16 @@ if (ONNX_ENV?.wasm) { if ( // @ts-ignore Cannot find name 'ServiceWorkerGlobalScope'.ts(2304) !(typeof ServiceWorkerGlobalScope !== 'undefined' && self instanceof ServiceWorkerGlobalScope) + && env.backends.onnx.versions?.web && !ONNX_ENV.wasm.wasmPaths ) { - ONNX_ENV.wasm.wasmPaths = `https://cdn.jsdelivr.net/npm/@huggingface/transformers@${env.version}/dist/`; + const wasmPathPrefix = `https://cdn.jsdelivr.net/npm/onnxruntime-web@${env.backends.onnx.versions.web}/dist/`; + + ONNX_ENV.wasm.wasmPaths = apis.IS_SAFARI ? { + "mjs": `${wasmPathPrefix}/ort-wasm-simd-threaded.mjs`, + "wasm": `${wasmPathPrefix}/ort-wasm-simd-threaded.wasm`, + } + : wasmPathPrefix; } // TODO: Add support for loading WASM files from cached buffer when we upgrade to onnxruntime-web@1.19.0 diff --git a/src/env.js b/src/env.js index 5f0e8d94f..07e9932de 100644 --- a/src/env.js +++ b/src/env.js @@ -30,11 +30,39 @@ const VERSION = '3.4.0'; // Check if various APIs are available (depends on environment) const IS_BROWSER_ENV = typeof window !== "undefined" && typeof window.document !== "undefined"; -const IS_WEBWORKER_ENV = typeof self !== "undefined" && self.constructor?.name === 'DedicatedWorkerGlobalScope'; +const IS_WEBWORKER_ENV = typeof self !== "undefined" && self.constructor?.name === 'DedicatedWorkerGlobalScope'; const IS_WEB_CACHE_AVAILABLE = typeof self !== "undefined" && 'caches' in self; const IS_WEBGPU_AVAILABLE = typeof navigator !== 'undefined' && 'gpu' in navigator; const IS_WEBNN_AVAILABLE = typeof navigator !== 'undefined' && 'ml' in navigator; +/** + * Check if the current environment is Safari browser. + * Works in both browser and web worker contexts. + * @returns {boolean} Whether the current environment is Safari. + */ +const isSafari = () => { + // Check if we're in a browser environment + if (typeof navigator === 'undefined') { + return false; + } + + const userAgent = navigator.userAgent; + const vendor = navigator.vendor || ''; + + // Safari has "Apple" in vendor string + const isAppleVendor = vendor.indexOf('Apple') > -1; + + // Exclude Chrome on iOS (CriOS), Firefox on iOS (FxiOS), + // Edge on iOS (EdgiOS), and other browsers + const notOtherBrowser = + !userAgent.match(/CriOS|FxiOS|EdgiOS|OPiOS|mercury|brave/i) && + !userAgent.includes('Chrome') && + !userAgent.includes('Android'); + + return isAppleVendor && notOtherBrowser; +}; +const IS_SAFARI = isSafari(); + const IS_PROCESS_AVAILABLE = typeof process !== 'undefined'; const IS_NODE_ENV = IS_PROCESS_AVAILABLE && process?.release?.name === 'node'; const IS_FS_AVAILABLE = !isEmpty(fs); @@ -59,6 +87,9 @@ export const apis = Object.freeze({ /** Whether the WebNN API is available */ IS_WEBNN_AVAILABLE, + /** Whether we are running in a Safari browser */ + IS_SAFARI, + /** Whether the Node.js process API is available */ IS_PROCESS_AVAILABLE,