**refactor(tests): consolidate and replace outdated environment test scripts**
- Removed obsolete scripts: `test-all-environments.js`, `test-fallback-function.js`, `test-fallback-simple.js`, `test-fix.js`, `test-tensorflow-textencoder.js`, `test-unified-encoding.js`, and `test-worker-utils.js`. - Introduced `scripts/comprehensive-test.js` as a unified testing script covering all environments: Browser, Node.js, and CLI. - Added `examples/cli-wrapper-example.js` to demonstrate a proper CLI implementation with TensorFlow.js initialization. This refactor simplifies the testing structure by consolidating redundant scripts into a single comprehensive script while ensuring robust cross-environment coverage.
This commit is contained in:
parent
fe1f418bf9
commit
19ed3dd081
20 changed files with 1253 additions and 808 deletions
|
|
@ -145,14 +145,36 @@ export async function calculateDistancesBatch(
|
|||
// In worker context, use the importTensorFlow function
|
||||
tf = await self.importTensorFlow()
|
||||
} else {
|
||||
// Dynamically import TensorFlow.js core module and backends
|
||||
tf = await import('@tensorflow/tfjs-core')
|
||||
// CRITICAL: First, directly import the setup module to ensure the TensorFlow.js patch is applied
|
||||
// This is the most reliable way to ensure the patch is applied before TensorFlow.js is loaded
|
||||
try {
|
||||
// In Node.js environment, use require() which is synchronous
|
||||
if (typeof require !== 'undefined') {
|
||||
// First, require the setup module to apply the patch
|
||||
require('../setup.js')
|
||||
|
||||
// Import CPU backend
|
||||
await import('@tensorflow/tfjs-backend-cpu')
|
||||
// Now load TensorFlow.js core module
|
||||
tf = require('@tensorflow/tfjs-core')
|
||||
|
||||
// Set CPU as the backend
|
||||
await tf.setBackend('cpu')
|
||||
// Load CPU backend
|
||||
require('@tensorflow/tfjs-backend-cpu')
|
||||
|
||||
// Set CPU as the backend
|
||||
tf.setBackend('cpu')
|
||||
} else {
|
||||
// In browser or other environments without require(), use dynamic imports
|
||||
// First, dynamically import the setup module to apply the patch
|
||||
await import('../setup.js')
|
||||
|
||||
// Now load TensorFlow.js core module
|
||||
tf = await import('@tensorflow/tfjs-core')
|
||||
await import('@tensorflow/tfjs-backend-cpu')
|
||||
await tf.setBackend('cpu')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize TensorFlow.js:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// Convert vectors to tensors
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ export class UniversalSentenceEncoder implements EmbeddingModel {
|
|||
/**
|
||||
* Add polyfills and patches for TensorFlow.js compatibility
|
||||
* This addresses issues with TensorFlow.js in Node.js environments
|
||||
*
|
||||
* Note: The main TensorFlow.js patching is now centralized in textEncoding.ts
|
||||
* and applied through setup.ts. This method only adds additional utility functions
|
||||
* that might be needed by TensorFlow.js.
|
||||
*/
|
||||
private addNodeCompatibilityPolyfills(): void {
|
||||
// Only apply in Node.js environment
|
||||
|
|
@ -38,82 +42,30 @@ export class UniversalSentenceEncoder implements EmbeddingModel {
|
|||
// This fixes the "Cannot read properties of undefined (reading 'isFloat32Array')" error
|
||||
if (typeof global !== 'undefined') {
|
||||
try {
|
||||
// Define a custom PlatformNode class
|
||||
class PlatformNode {
|
||||
util: any
|
||||
textEncoder: TextEncoder
|
||||
textDecoder: TextDecoder
|
||||
// Ensure the util object exists
|
||||
if (!global.util) {
|
||||
global.util = {}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
// Create a util object with necessary methods
|
||||
this.util = {
|
||||
// Add isFloat32Array and isTypedArray directly to util
|
||||
isFloat32Array: (arr: any) => {
|
||||
return !!(
|
||||
arr instanceof Float32Array ||
|
||||
(arr &&
|
||||
Object.prototype.toString.call(arr) ===
|
||||
'[object Float32Array]')
|
||||
)
|
||||
},
|
||||
isTypedArray: (arr: any) => {
|
||||
return !!(ArrayBuffer.isView(arr) && !(arr instanceof DataView))
|
||||
},
|
||||
// Use native TextEncoder and TextDecoder
|
||||
TextEncoder: TextEncoder,
|
||||
TextDecoder: TextDecoder
|
||||
}
|
||||
|
||||
// Initialize encoders using native constructors
|
||||
this.textEncoder = new TextEncoder()
|
||||
this.textDecoder = new TextDecoder()
|
||||
}
|
||||
|
||||
// Define isFloat32Array directly on the instance
|
||||
isFloat32Array(arr: any) {
|
||||
// Add isFloat32Array method if it doesn't exist
|
||||
if (!global.util.isFloat32Array) {
|
||||
global.util.isFloat32Array = (obj: any) => {
|
||||
return !!(
|
||||
arr instanceof Float32Array ||
|
||||
(arr &&
|
||||
Object.prototype.toString.call(arr) === '[object Float32Array]')
|
||||
obj instanceof Float32Array ||
|
||||
(obj &&
|
||||
Object.prototype.toString.call(obj) === '[object Float32Array]')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Define isTypedArray directly on the instance
|
||||
isTypedArray(arr: any) {
|
||||
return !!(ArrayBuffer.isView(arr) && !(arr instanceof DataView))
|
||||
// Add isTypedArray method if it doesn't exist
|
||||
if (!global.util.isTypedArray) {
|
||||
global.util.isTypedArray = (obj: any) => {
|
||||
return !!(ArrayBuffer.isView(obj) && !(obj instanceof DataView))
|
||||
}
|
||||
}
|
||||
|
||||
// Assign the PlatformNode class to the global object
|
||||
;(global as any).PlatformNode = PlatformNode
|
||||
|
||||
// Also create an instance and assign it to global.platformNode
|
||||
;(global as any).platformNode = new PlatformNode()
|
||||
} catch (error) {
|
||||
console.warn('Failed to define global PlatformNode class:', error)
|
||||
}
|
||||
|
||||
// Ensure the util object exists
|
||||
if (!global.util) {
|
||||
global.util = {}
|
||||
}
|
||||
|
||||
// Add isFloat32Array method if it doesn't exist
|
||||
if (!global.util.isFloat32Array) {
|
||||
global.util.isFloat32Array = (obj: any) => {
|
||||
return !!(
|
||||
obj instanceof Float32Array ||
|
||||
(obj &&
|
||||
Object.prototype.toString.call(obj) === '[object Float32Array]')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Add isTypedArray method if it doesn't exist
|
||||
if (!global.util.isTypedArray) {
|
||||
global.util.isTypedArray = (obj: any) => {
|
||||
return !!(ArrayBuffer.isView(obj) && !(obj instanceof DataView))
|
||||
}
|
||||
console.warn('Failed to add utility polyfills:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -145,36 +97,95 @@ export class UniversalSentenceEncoder implements EmbeddingModel {
|
|||
|
||||
// TensorFlow.js will use its default EPSILON value
|
||||
|
||||
// Dynamically import TensorFlow.js core module and backends
|
||||
// Use type assertions to tell TypeScript these modules exist
|
||||
this.tf = await import('@tensorflow/tfjs-core')
|
||||
|
||||
// Import CPU backend (always needed as fallback)
|
||||
await import('@tensorflow/tfjs-backend-cpu')
|
||||
|
||||
// Try to import WebGL backend for GPU acceleration in browser environments
|
||||
// CRITICAL: First, directly import the setup module to ensure the TensorFlow.js patch is applied
|
||||
// This is the most reliable way to ensure the patch is applied before TensorFlow.js is loaded
|
||||
try {
|
||||
if (typeof window !== 'undefined') {
|
||||
await import('@tensorflow/tfjs-backend-webgl')
|
||||
// Check if WebGL is available using setBackend instead of findBackend
|
||||
try {
|
||||
if (this.tf.setBackend) {
|
||||
await this.tf.setBackend('webgl')
|
||||
this.backend = 'webgl'
|
||||
console.log('Using WebGL backend for TensorFlow.js')
|
||||
} else {
|
||||
// In Node.js environment, use require() which is synchronous
|
||||
if (typeof require !== 'undefined') {
|
||||
// First, require the setup module to apply the patch
|
||||
require('../setup.js')
|
||||
|
||||
// Now load TensorFlow.js core module
|
||||
this.tf = require('@tensorflow/tfjs-core')
|
||||
|
||||
// Load CPU backend (always needed as fallback)
|
||||
require('@tensorflow/tfjs-backend-cpu')
|
||||
|
||||
// Try to load WebGL backend for GPU acceleration in browser environments
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
require('@tensorflow/tfjs-backend-webgl')
|
||||
// Check if WebGL is available
|
||||
if (this.tf.setBackend) {
|
||||
this.tf.setBackend('webgl')
|
||||
this.backend = 'webgl'
|
||||
console.log('Using WebGL backend for TensorFlow.js')
|
||||
} else {
|
||||
console.warn(
|
||||
'tf.setBackend is not available, falling back to CPU'
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
'tf.setBackend is not available, falling back to CPU'
|
||||
'WebGL backend not available, falling back to CPU:',
|
||||
e
|
||||
)
|
||||
this.backend = 'cpu'
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('WebGL backend not available, falling back to CPU:', e)
|
||||
}
|
||||
|
||||
// Load Universal Sentence Encoder
|
||||
this.use = require('@tensorflow-models/universal-sentence-encoder')
|
||||
} else {
|
||||
// In browser or other environments without require(), use dynamic imports
|
||||
// First, dynamically import the setup module to apply the patch
|
||||
await import('../setup.js')
|
||||
|
||||
// Now load TensorFlow.js core module
|
||||
this.tf = await import('@tensorflow/tfjs-core')
|
||||
|
||||
// Import CPU backend (always needed as fallback)
|
||||
await import('@tensorflow/tfjs-backend-cpu')
|
||||
|
||||
// Try to import WebGL backend for GPU acceleration in browser environments
|
||||
try {
|
||||
if (typeof window !== 'undefined') {
|
||||
await import('@tensorflow/tfjs-backend-webgl')
|
||||
// Check if WebGL is available
|
||||
try {
|
||||
if (this.tf.setBackend) {
|
||||
await this.tf.setBackend('webgl')
|
||||
this.backend = 'webgl'
|
||||
console.log('Using WebGL backend for TensorFlow.js')
|
||||
} else {
|
||||
console.warn(
|
||||
'tf.setBackend is not available, falling back to CPU'
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
'WebGL backend not available, falling back to CPU:',
|
||||
e
|
||||
)
|
||||
this.backend = 'cpu'
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
'WebGL backend not available, falling back to CPU:',
|
||||
error
|
||||
)
|
||||
this.backend = 'cpu'
|
||||
}
|
||||
|
||||
// Load Universal Sentence Encoder
|
||||
this.use = await import(
|
||||
'@tensorflow-models/universal-sentence-encoder'
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('WebGL backend not available, falling back to CPU:', error)
|
||||
this.backend = 'cpu'
|
||||
console.error('Failed to initialize TensorFlow.js:', error)
|
||||
throw error
|
||||
}
|
||||
|
||||
// Set the backend
|
||||
|
|
@ -182,8 +193,6 @@ export class UniversalSentenceEncoder implements EmbeddingModel {
|
|||
await this.tf.setBackend(this.backend)
|
||||
}
|
||||
|
||||
this.use = await import('@tensorflow-models/universal-sentence-encoder')
|
||||
|
||||
// Log the module structure to help with debugging
|
||||
console.log(
|
||||
'Universal Sentence Encoder module structure in main thread:',
|
||||
|
|
|
|||
|
|
@ -1,94 +1,224 @@
|
|||
// In: @soulcraft/brainy/src/utils/textEncoding.ts
|
||||
|
||||
/**
|
||||
* Unified Text Encoding Utilities
|
||||
* Checks if the code is running in a Node.js environment.
|
||||
*/
|
||||
function isNode(): boolean {
|
||||
return (
|
||||
typeof process !== 'undefined' &&
|
||||
process.versions != null &&
|
||||
process.versions.node != null
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Global flag to track if TensorFlow.js has been initialized
|
||||
* This helps prevent multiple registrations of the same kernels
|
||||
*/
|
||||
const TENSORFLOW_INITIALIZED = Symbol('TENSORFLOW_INITIALIZED')
|
||||
|
||||
/**
|
||||
* Flag to track if the patch has been applied
|
||||
* This prevents multiple applications of the patch
|
||||
*/
|
||||
let patchApplied = false
|
||||
|
||||
/**
|
||||
* CRITICAL: Applies a compatibility patch for TensorFlow.js when running in a modern
|
||||
* Node.js ES Module environment. This must be called before any TensorFlow.js
|
||||
* modules are imported.
|
||||
*
|
||||
* This module provides a consistent way to handle text encoding/decoding across all environments
|
||||
* using the native TextEncoder/TextDecoder APIs.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get a text encoder that works in the current environment
|
||||
* @returns A TextEncoder instance
|
||||
*/
|
||||
export function getTextEncoder(): TextEncoder {
|
||||
return new TextEncoder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a text decoder that works in the current environment
|
||||
* @returns A TextDecoder instance
|
||||
*/
|
||||
export function getTextDecoder(): TextDecoder {
|
||||
return new TextDecoder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the TensorFlow.js platform patch if needed
|
||||
* This function patches the global object to provide a PlatformNode class
|
||||
* that uses native TextEncoder/TextDecoder
|
||||
* This function prevents the "TextEncoder is not a constructor" error by preemptively
|
||||
* creating a compliant PlatformNode class with proper TextEncoder/TextDecoder support
|
||||
* and placing it on the global object where TensorFlow.js expects to find it.
|
||||
*
|
||||
* The race condition occurs because TensorFlow.js's platform detection might run
|
||||
* before the necessary global objects are properly initialized in certain Node.js
|
||||
* environments, particularly when the package is being used by other applications.
|
||||
*
|
||||
* This function is called from setup.ts, which must be the first import in unified.ts
|
||||
* to ensure the patch is applied before any TensorFlow.js code is executed.
|
||||
*
|
||||
* It also applies a patch to prevent duplicate kernel registrations when TensorFlow.js
|
||||
* is imported multiple times.
|
||||
*/
|
||||
export function applyTensorFlowPatch(): void {
|
||||
try {
|
||||
// Define a custom Platform class that works in both Node.js and browser environments
|
||||
class Platform {
|
||||
util: any
|
||||
textEncoder: TextEncoder
|
||||
textDecoder: TextDecoder
|
||||
// Prevent multiple applications of the patch
|
||||
if (patchApplied) {
|
||||
return
|
||||
}
|
||||
|
||||
constructor() {
|
||||
// Create a util object with necessary methods and constructors
|
||||
this.util = {
|
||||
// Use native TextEncoder and TextDecoder
|
||||
TextEncoder: globalThis.TextEncoder || TextEncoder,
|
||||
TextDecoder: globalThis.TextDecoder || TextDecoder
|
||||
if (!isNode()) {
|
||||
return // Patch is only for Node.js
|
||||
}
|
||||
|
||||
// In modern Node.js with ES Modules, TensorFlow.js can fail during its
|
||||
// initial platform detection. This patch preempts that logic by creating
|
||||
// a compliant "Platform" class that uses the standard global TextEncoder
|
||||
// and placing it on the global object where TensorFlow.js expects to find it.
|
||||
try {
|
||||
// Ensure TextEncoder and TextDecoder are available
|
||||
const nodeUtil = require('util')
|
||||
const TextEncoderPolyfill = nodeUtil.TextEncoder || global.TextEncoder
|
||||
const TextDecoderPolyfill = nodeUtil.TextDecoder || global.TextDecoder
|
||||
|
||||
if (!TextEncoderPolyfill || !TextDecoderPolyfill) {
|
||||
console.warn(
|
||||
'Brainy: TextEncoder or TextDecoder not available, attempting to polyfill'
|
||||
)
|
||||
|
||||
// If still not available, try to use a simple polyfill
|
||||
if (!TextEncoderPolyfill) {
|
||||
class SimpleTextEncoder {
|
||||
encode(input: string): Uint8Array {
|
||||
const buf = Buffer.from(input, 'utf8')
|
||||
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize using native constructors directly
|
||||
this.textEncoder = new (globalThis.TextEncoder || TextEncoder)()
|
||||
this.textDecoder = new (globalThis.TextDecoder || TextDecoder)()
|
||||
global.TextEncoder = SimpleTextEncoder
|
||||
}
|
||||
|
||||
// Define isFloat32Array directly on the instance
|
||||
isFloat32Array(arr: any) {
|
||||
return !!(
|
||||
if (!TextDecoderPolyfill) {
|
||||
class SimpleTextDecoder {
|
||||
decode(input?: Uint8Array): string {
|
||||
if (!input) return ''
|
||||
return Buffer.from(
|
||||
input.buffer,
|
||||
input.byteOffset,
|
||||
input.byteLength
|
||||
).toString('utf8')
|
||||
}
|
||||
}
|
||||
|
||||
global.TextDecoder = SimpleTextDecoder
|
||||
}
|
||||
} else {
|
||||
// Ensure they're available globally
|
||||
global.TextEncoder = TextEncoderPolyfill
|
||||
global.TextDecoder = TextDecoderPolyfill
|
||||
}
|
||||
|
||||
// Create a PlatformNode implementation that uses the polyfilled TextEncoder/TextDecoder
|
||||
class BrainyPlatformNode {
|
||||
// Use the polyfilled TextEncoder/TextDecoder
|
||||
readonly util = {
|
||||
TextEncoder: global.TextEncoder,
|
||||
TextDecoder: global.TextDecoder,
|
||||
|
||||
// Add utility functions that TensorFlow.js might need
|
||||
isTypedArray: (arr: any): boolean => {
|
||||
return ArrayBuffer.isView(arr) && !(arr instanceof DataView)
|
||||
},
|
||||
|
||||
isFloat32Array: (arr: any): boolean => {
|
||||
return (
|
||||
arr instanceof Float32Array ||
|
||||
(arr &&
|
||||
Object.prototype.toString.call(arr) === '[object Float32Array]')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Create instances of the encoder/decoder
|
||||
readonly textEncoder: any
|
||||
readonly textDecoder: any
|
||||
|
||||
constructor() {
|
||||
try {
|
||||
// Initialize encoders using constructors
|
||||
this.textEncoder = new global.TextEncoder()
|
||||
this.textDecoder = new global.TextDecoder()
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
'Brainy: Error creating TextEncoder/TextDecoder instances:',
|
||||
e
|
||||
)
|
||||
// Provide fallback implementations if instantiation fails
|
||||
this.textEncoder = {
|
||||
encode: (input: string): Uint8Array => {
|
||||
const buf = Buffer.from(input, 'utf8')
|
||||
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)
|
||||
}
|
||||
}
|
||||
this.textDecoder = {
|
||||
decode: (input?: Uint8Array): string => {
|
||||
if (!input) return ''
|
||||
return Buffer.from(
|
||||
input.buffer,
|
||||
input.byteOffset,
|
||||
input.byteLength
|
||||
).toString('utf8')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isTypedArray(arr: any): arr is Float32Array | Int32Array | Uint8Array {
|
||||
return ArrayBuffer.isView(arr) && !(arr instanceof DataView)
|
||||
}
|
||||
|
||||
isFloat32Array(arr: any): arr is Float32Array {
|
||||
return (
|
||||
arr instanceof Float32Array ||
|
||||
(arr &&
|
||||
Object.prototype.toString.call(arr) === '[object Float32Array]')
|
||||
)
|
||||
}
|
||||
|
||||
// Define isTypedArray directly on the instance
|
||||
isTypedArray(arr: any) {
|
||||
return !!(ArrayBuffer.isView(arr) && !(arr instanceof DataView))
|
||||
}
|
||||
}
|
||||
|
||||
// Get the global object in a way that works in both Node.js and browser
|
||||
const globalObj =
|
||||
typeof global !== 'undefined'
|
||||
? global
|
||||
: typeof window !== 'undefined'
|
||||
? window
|
||||
: typeof self !== 'undefined'
|
||||
? self
|
||||
: {}
|
||||
// Assign the custom platform class to the global scope.
|
||||
// TensorFlow.js specifically looks for `PlatformNode`.
|
||||
global.PlatformNode = BrainyPlatformNode
|
||||
|
||||
// Only apply in Node.js environment
|
||||
if (
|
||||
typeof process !== 'undefined' &&
|
||||
process.versions &&
|
||||
process.versions.node
|
||||
) {
|
||||
// Assign the Platform class to the global object as PlatformNode for Node.js
|
||||
;(globalObj as any).PlatformNode = Platform
|
||||
// Also create an instance and assign it to global.platformNode (lowercase p)
|
||||
;(globalObj as any).platformNode = new Platform()
|
||||
} else if (typeof window !== 'undefined' || typeof self !== 'undefined') {
|
||||
// In browser environments, we might need to provide similar functionality
|
||||
// but we'll use a different name to avoid conflicts
|
||||
;(globalObj as any).PlatformBrowser = Platform
|
||||
;(globalObj as any).platformBrowser = new Platform()
|
||||
// Also create an instance and assign it to global.platformNode (lowercase p)
|
||||
// This is needed for some TensorFlow.js versions
|
||||
global.platformNode = new BrainyPlatformNode()
|
||||
|
||||
// Set up a global flag to track TensorFlow.js initialization
|
||||
global[TENSORFLOW_INITIALIZED] = false
|
||||
|
||||
// Monkey patch the registerKernel function to prevent duplicate registrations
|
||||
// This will be applied when TensorFlow.js is imported
|
||||
const originalRegisterKernel = global.registerKernel
|
||||
if (!originalRegisterKernel) {
|
||||
// Set up a handler to intercept the registerKernel function when it's defined
|
||||
Object.defineProperty(global, 'registerKernel', {
|
||||
set: function (newRegisterKernel) {
|
||||
// Replace the setter with our patched version
|
||||
Object.defineProperty(global, 'registerKernel', {
|
||||
value: function (kernel: any) {
|
||||
// Check if this kernel is already registered
|
||||
const kernelName = kernel.kernelName
|
||||
const backendName = kernel.backendName
|
||||
const key = `${kernelName}_${backendName}`
|
||||
|
||||
// Use a global registry to track registered kernels
|
||||
if (!global.__REGISTERED_KERNELS__) {
|
||||
global.__REGISTERED_KERNELS__ = new Set()
|
||||
}
|
||||
|
||||
// If this kernel is already registered, skip it
|
||||
if (global.__REGISTERED_KERNELS__.has(key)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, register it and add it to our registry
|
||||
global.__REGISTERED_KERNELS__.add(key)
|
||||
return newRegisterKernel(kernel)
|
||||
},
|
||||
configurable: true,
|
||||
writable: true
|
||||
})
|
||||
},
|
||||
configurable: true
|
||||
})
|
||||
}
|
||||
|
||||
// Mark the patch as applied
|
||||
patchApplied = true
|
||||
console.log('Brainy: Successfully applied TensorFlow.js platform patch')
|
||||
} catch (error) {
|
||||
console.warn('Failed to apply TensorFlow.js platform patch:', error)
|
||||
console.warn('Brainy: Failed to apply TensorFlow.js platform patch:', error)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue